Код: Выделить всё
out OCR0A+1, temp1Код: Выделить всё
out OCR0A+1, temp1Код: Выделить всё
.include "tn13def.inc"
.def temp = r16
.def temp1 = r17
;для задержек
.equ d_t1=255
.equ d_t2=255
.DSEG
t1: .byte 1
t2: .byte 1
.CSEG
.ORG $00
rjmp reset ; reset
reset:
;стек
ldi r16,RAMEND
out SPL,r16
;загружаем данные
ldi temp, d_t1
sts t1, temp
ldi temp, d_t2
sts t2, temp
;перефирия
cli
;кнопки
andi temp, ~(1<<PB2 | 1<<PB3)
out DDRB, temp
andi temp, ~(1<<PB2 | 1<<PB3)
out PORTB, temp
;выходы
ori temp, (1<<PB0 | 1<<PB1)
out DDRB, temp
andi temp, ~(1<<PB0 | 1<<PB1)
out PORTB, temp
;настройка timer t0 - fast pwm
;TCCR0A
in temp, TCCR0A
ori temp, 1<<WGM00 | 1<<WGM01 | 1<<COM0A1 | 1<<COM0B1
out TCCR0A, temp
;TCCR0B, предделитель 64
in temp, TCCR0B
ori temp, 1<<CS01 | 1<<CS00
out TCCR0B, temp
;TCNT0
;OCR0A
ldi temp, 0
out OCR0A, temp
;OCR0B
ldi temp, 60
out OCR0B, temp
sei
;основная программа
main:
lds temp, TCNT0
lds temp1, TCNT0+1
cpi r16,$10
brcs ex1
cpi r17, $01
brcs ex1
rcall led_pwm
ex1:
nop
nop
rjmp main
;плавный розжиг светодиода
led_pwm:
cli
in temp, OCR0A
in temp1, OCR0A+1
inc temp
out OCR0A, temp
out OCR0A+1, temp1
sei
clr temp
cli
out TCNT0, temp
sts TCNT0, temp
sts TCNT0+1, temp
sts TCNT0+2, temp
sts TCNT0+3, temp
sei
ret
.ESEG
Код: Выделить всё
OUT TCNT0,R16 ; Ноль в счетный регистр таймера
STS TCNT,R16 ; Ноль в первый байт счетчика в RAM
STS TCNT+1,R16 ; Ноль в второй байт счетчика в RAM
STS TCNT+2,R16 ; Ноль в третий байт счетчика в RAM
STS TCNT+3,R16 ; Ноль в первый байт счетчика в RAM
SEI ; Разрешаем прерывания. Код: Выделить всё
;основная программа
ldi temp, 0
main:
cpi temp, 250
brlo led_pwm
ex1:
ldi temp,0
rjmp main
;плавный розжиг светодиода
led_pwm:
cli
inc temp
out OCR0A, temp
sei
rjmp mainКод: Выделить всё
cp OFFL, PERIODL
cpc OFFH, PERIODH
brlo OFF
Код: Выделить всё
Start:
cp PERIODL, OFFL
cpc PERIODH, OFFH
brlo OFF
cp PERIODL, ONTumL
cpc PERIODH, ONTumH
brsh ONT
rjmp Start
ONT: sbi PORTB, 0 ; Включаем туманки
cp PERIODL, ONBlL
cpc PERIODH, ONBLH
brsh ONB
rjmp Start
ONB: sbi PORTB, 2 ; Включаем ближний
rjmp Start
OFF: cbi PORTB, 0
cbi PORTB, 2
rjmp Start ; Конец программы, переход на начало
Код: Выделить всё
.include "tn13def.inc"
;======================
.def PERIODH=R20
.def PERIODL=R21
.def OFFH=R22
.def OFFL=R23
.def ONTumH=R24
.def ONTumL=R25
.def ONBlH=R26
.def ONBlL=R27
Start:
cp PERIODL, OFFL
cpc PERIODH, OFFH ; скорость >5км/час
BRSH OFF ; меньше, выключить всё
ONT:
sbi PORTB, 0 ; Включаем туманки
cp PERIODL, ONBlL
cpc PERIODH, ONBlH
BRSH START ; скорость <40км/час, выходим
ONB:
sbi PORTB, 2 ; скорость >40км/час,Включаем ближний
rjmp Start ; Конец программы, переход на начало
OFF:
cbi PORTB, 0
cbi PORTB, 2
rjmp Start ; Конец программы, переход на начало
.exit
СКАЗОЧНИК писал(а):Подскажите, как сравнить две переменные двухбайтные
Код: Выделить всё
cp R20, R16 ; младшие байты
cpc R21, R17 ; старшие байты
brlo error
СКАЗОЧНИК писал(а):Другой вопрос. Как создать в АВРСтудио ЕЕПРОМ файл? А то я старые значения затер...
Код: Выделить всё
.eseg
.org 0x01
EE_PARAM:
.db 0x55, 0xAA
.dw 0x55AA
Код: Выделить всё
;*************************************************************************
;========== EEPROM ===================
;*************************************************************************
;Так как возможна случайная запись в EEPROM в случае сбоя питания, то:
;1 - В микроконтроллере включить контроль снижения напряжения питания.
;2 - Первый (0x00) байт никогда не используется.
;3 - После ресета обнулить указатель адреса EEPROM.
;Решения для увеличения ресурса EEPROM:
;4 - Перед записью считывается байт, предназначенный для записи,
;проверяется на равенство с записываемым, если байты равны, то переход
;к записи следующего байта.
;5 - В конце работы с EEPROM обнулить указатель адреса.
#if (EEPROM==YES)
.macro Read_EEPROM
ldix @0 ; Указатель адреса EEPROM.
ldiy @1 ; Указатель адреса SRAM.
ldi CNT,@2 ; Количество байтов.
rcall _Read_EEPROM
.endmacro
_Read_EEPROM:
sbic EECR,EEWE
rjmp _Read_EEPROM
.ifdef EEARH
out EEARH,XH
.endif
out EEARL,XL
sbi EECR,EERE
sbi EECR,EERE
in EEDREG,EEDR
st Y+,EEDREG
adiw XL,1
dec Cnt
brne _Read_EEPROM
.ifdef EEARH
out EEARH,RClr
.endif
out EEARL,RClr
ret
EERead:
sbic EECR,EEWE
rjmp EERead
sbi EECR,EERE
sbi EECR,EERE
in EEDREG,EEDR
ret
EEWrite:
sbic EECR,EEWE
rjmp EEWrite
out EEDR,EEDREG
sbi EECR,EEMWE
sbi EECR,EEWE
ret
Write_EEPROM:
sbic EECR,EEWE
rjmp Write_EEPROM
.ifdef EEARH
out EEARH,YH
.endif
out EEARL,YL
ld EEDREG,X
out EEDR,EEDREG
sbi EECR,EEMWE
sbi EECR,EEWE
adiw XL,1
adiw YL,1
dec Cnt
brne Write_EEPROM
.ifdef EEARH
out EEARH,RClr
.endif
out EEARL,RClr
ret
Write_Param_EEPROM:
; LDIX Param_SRAM
; LDIY Param_EEPROM
; ldi Cnt,Param_Size
W_P_E_0:
sbic EECR,EEWE
rjmp W_P_E_0
.ifdef EEARH
out EEARH,YH
.endif
out EEARL,YL
ld r17,X
rcall EERead
cp r17,EEDREG
breq W_P_E_2
mov EEDREG,r17
W_P_E_1:
sbic EECR,EEWE
rjmp W_P_E_1
.ifdef EEARH
out EEARH,YH
.endif
out EEARL,YL
rcall EEWrite
W_P_E_2:
adiw XL,1
adiw YL,1
dec Cnt
brne W_P_E_0
.ifdef EEARH
out EEARH,RClr
.endif
out EEARL,RClr
ret
; Считывание параметров.
Read_Write_Param:
; LDIX Param_SRAM
; LDIY Param_EEPROM
; ldi Cnt,Param_Size
; rcall Read_EEPROM
ret
#endif
Код: Выделить всё
;--- деление 16 бит в R21:R20 на 8 бит в R16 ---
;------ целая часть в R20, остаток в R21 -------
div_16_8_8_8: ; 16 битов (2 байта) делим на 8 битов (1 байт), получаем целую часть 8 битов (1 байт) и остаток 8 битов (1 байт)
ldi R18, 8 ; делаем 8 циклов сдвига делимого/результата
div_16_8a:
lsl R20
rol R21
brcs div_16_8b ; если в результате сдвига влево появился перенос, то сразу же идем на вычитание, мимо сравнения
cp R21, R16
brcs div_16_8c ; если меньше, то пропускаем вычитание
div_16_8b:
sub R21,R16
sbr R20, 1
div_16_8c:
dec R18
brne div_16_8a
ret
;--- деление 32 бита в R23:R22:R21:R20 на 16 бит в R17:R16 ---
;--------- целая часть в R21:R20, остаток в R23:R22 ----------
div_32_16_16_16: ; 32 бита (4 байта) делим на 16 битов (2 байта), и получаем целую часть 16 битов (2 байта) и остаток 16 битов (2 байта)
ldi R18, 16 ; делаем 16 циклов сдвига делимого/результата
div_32_16a:
lsl R20
rol R21
rol R22
rol R23
brcs div_32_16b ; если в результате сдвига влево появился перенос, то сразу же идем на вычитание, мимо сравнения
cp R22, R16
cpc R23, R17
brcs div_32_16c
div_32_16b: ; если меньше, то пропускаем вычитание
sub R22,R16
sbc R23,R17
sbr R20, 1
div_32_16c:
dec R18
brne div_32_16a
ret
;--- умножение 16 бит в R21:R20 на 16 бит в R17:R16 ---
;----------- результат в R23:R22:R21:R20 --------------
mul_16x16_32: ; 16 битов (2 байта) умножаем на 16 битов (2 байта) и получаем в результате 32 бита (4 байта)
mov R18, R20
mov R19, R21
mul R21, R17 ; старший * старший '
movw R23:R22, R1:R0 ; старшая пара результата
mul R18, R16 ; младший * младший
movw R21:R20, R1:R0 ; младшая пара результата
mul R19, R16 ; старший * младший
add R21, R0
adc R22, R1
mul R18, R17 ; младший * старший
add R21, R0
adc R22, R1
adc R23, R31
ret
Код: Выделить всё
;--- калибровка тока или напряжения ---
calibr_zamer:
mov R16, R4 ; передадим замер в сомножитель
mov R17, R5 ; в первом сомножителе (R21:R20) уже находится калибровчный коэффициент
rcall mul_16x16_32
ldi R16, low(1024)
ldi R17, high(1024) ; делим на 1024, так как результат АЦП - 10-битный
rcall div_32_16_16_16
;--- округление числа после деления ---
okruglenie:
lsl R22 ; сдвигаем остаток от деления влево - умножение на 2
rol R23
cp R22, R16 ; сравниваем удвоенный остаток с делителем
cpc R23, R17
brlo end_okrug ; если меньше, то ничего не делаем
inc R20 ; а если больше или равно, то прибавляем 1 к целой части результата деления
brne end_okrug
inc R21
end_okrug:
mov R4, R20
mov R5, R21 ; вернем в регистры прокалиброванные ток или напряжение
ret
Код: Выделить всё
clr R23 ; в R22:R21:R20 уже находится набранное время, очистим старший байт
ldi R16, low(3600)
ldi R17, high(3600) ; после деления на 3600 в целой части результата получаеи количество часов, а в остатке получаем количество секунд
rcall div_32_16_16_16 ; остаток меньше 3600
ldi R16, 10 ; сразу же делим целую часть первого деления на 10,
rcall div_16_8_8_8 ; и получаем в целой части результата десятки часов, а в остатке получаем единицы часов
ldi R18, '0'
add R18, R20 ; десятки часов
rcall write_lcd
ldi R18, '0'
add R18, R21 ; единицы часов
rcall write_lcd
ldi R18, ':' ; выведем двоеточие
rcall write_lcd
mov R21, R23 ; переместим остаток в делимое
mov R20, R22
clr R23 ; очистим старшие байты
clr R22
ldi R16, low(600) ; после деления количества секунд на 600 получаем десятки минут,
ldi R17, high(600)
rcall div_32_16_16_16 ; остаток меньше 600
ldi R18, '0'
add R18, R20 ; десятки минут
rcall write_lcd
mov R21, R23
mov R20, R22 ; переместим остаток первого деления в делимое
ldi R16, 60 ; после деления на 60 получаем единицы минут
rcall div_16_8_8_8 ; остаток меньше 60
ldi R18, '0'
add R18, R20 ; единицы минут
rcall write_lcd
ldi R18, ':' ; выведем двоеточие
rcall write_lcd
mov R20, R21 ; переместим остаток от последнего деления в делимое
clr R21 ; очистим старший байт
ldi R16, 10 ; после деления на 10
rcall div_16_8_8_8 ; получаем в целой части результата десятки секунд, а в остатке получаем единицы секунд
ldi R18, '0'
add R18, R20 ; десятки секунд
rcall write_lcd
ldi R18, '0'
add R18, R21 ; единицы секунд
rcall write_lcd
end_vyvod_sekynd: