|
@@ -1,13 +1,12 @@
|
|
|
; Автор: shilow@ukr.net
|
|
|
-; Дата: октябрь 2014
|
|
|
+; Дата: июнь 2015
|
|
|
; Название: avm
|
|
|
-; Версия: 3
|
|
|
+; Версия: 4
|
|
|
; Имя файла: avm.asm, avm.spl7, avm.lay6
|
|
|
; Для AVR: ATtiny24A
|
|
|
; Тактовая частота: 8MHz, внутренний RC-генератор
|
|
|
; Выполняемые функции: Автомобильный вольтемтр
|
|
|
; см. ReadMe.txt
|
|
|
-; схема по "Вариант 5"
|
|
|
|
|
|
;******************************
|
|
|
; инклуды
|
|
@@ -40,8 +39,8 @@
|
|
|
.def LEDN = r20
|
|
|
; r21
|
|
|
; r22
|
|
|
-.def bAddr = r23 ; адрес текущей позиции в буфере измерений
|
|
|
-.def bIdx = r24 ; индекс буфера
|
|
|
+;.def = r23 ;
|
|
|
+;.def = r24 ;
|
|
|
.def flags = r25
|
|
|
; r26 XL OUT_NIBBL
|
|
|
; r27 XH
|
|
@@ -54,8 +53,8 @@
|
|
|
.equ AtBCD0 = 0 ;address of job0
|
|
|
.equ AtBCD2 = 2 ;address of job2
|
|
|
.equ AtLED1 = 4 ;address of LED1
|
|
|
-.equ MSEK100 = 7 ; 7bit of flags == 0.1 sek
|
|
|
-.equ NEED_DOT = 6 ; нужна точка
|
|
|
+.equ MEASURE = 7 ; 7bit of flags -- пора мерять
|
|
|
+.equ NEED_DOT = 6 ; 6bit of flags -- нужна точка
|
|
|
.equ DISP_PORT = PORTA
|
|
|
.equ DISP_DDR = DDRA
|
|
|
.equ LA1 = 4
|
|
@@ -63,18 +62,18 @@
|
|
|
.equ LA3 = 6
|
|
|
.equ LA4 = 7
|
|
|
.equ IND_LA = (1<<LA1)|(1<<LA2)|(1<<LA3)|(1<<LA4)
|
|
|
+.equ FIRST_LED = 0b11101111
|
|
|
.equ SER_PORT = PORTB
|
|
|
.equ SER_DDR = DDRB
|
|
|
.equ SCK = 0
|
|
|
.equ DATA = 1
|
|
|
.equ LOCK = 2
|
|
|
-;.equ T1DIVL = 0x8F
|
|
|
-;.equ T1DIVH = 0xFD ; 0x10000-8MHz/64/200Hz
|
|
|
-.equ T0DIV = 0x83 ; 0x100-8MHz/256/250Hz
|
|
|
-.equ VREF = 498 ; опорное напряжение, десятки миливольт
|
|
|
+.equ T1DIVL = 0x8F
|
|
|
+.equ T1DIVH = 0xFD ; 0x10000-8MHz/64/200Hz
|
|
|
+;.equ T0DIV = 0x83 ; 0x100-8MHz/256/250Hz
|
|
|
+.equ VREF = 4980 ; опорное напряжение, миливольты
|
|
|
.equ SPH = 0x3e
|
|
|
.equ DOT_BIT = 5 ; bit5 -- точка
|
|
|
-.equ BuffSize = 16 ; глубина буфера результатов измерений
|
|
|
.equ BuffShift = 4 ; сколько раз сдвинуть вправо сумму буфера для усреднения
|
|
|
|
|
|
;******************************
|
|
@@ -95,10 +94,10 @@
|
|
|
|
|
|
;******************************
|
|
|
; ячейки в СОЗУ
|
|
|
-.DSEG
|
|
|
-.ORG SRAM_START
|
|
|
+;.DSEG
|
|
|
+;.ORG SRAM_START
|
|
|
;Display: .byte 4 ; 4 байта для индикатора
|
|
|
-Buffer: .byte 2*BuffSize
|
|
|
+;Buffer: .byte 2*BuffSize
|
|
|
|
|
|
;******************************
|
|
|
; константы в EEPROM
|
|
@@ -120,10 +119,10 @@ Buffer: .byte 2*BuffSize
|
|
|
reti;jmp TIM1_CAPT ; Timer1 Capture Handler
|
|
|
reti;jmp TIM1_COMPA ; Timer1 Compare A Handler
|
|
|
reti;jmp TIM1_COMPB ; Timer1 Compare B Handler
|
|
|
- reti;jmp TIM1_OVF ; Timer1 Overflow Handler
|
|
|
+ rjmp TIM1_OVF ; Timer1 Overflow Handler
|
|
|
reti;jmp TIM0_COMPA ; Timer0 Compare A Handler
|
|
|
reti;jmp TIM0_COMPB ; Timer0 Compare B Handler
|
|
|
- rjmp TIM0_OVF ; Timer0 Overflow Handler
|
|
|
+ reti;rjmp TIM0_OVF ; Timer0 Overflow Handler
|
|
|
reti;jmp ANA_COMP ; Analog Comparator Handler
|
|
|
rjmp ADCC ; ADC Conversion Handler
|
|
|
; rjmp EE_RDY ; EEPROM Ready Handler
|
|
@@ -142,34 +141,36 @@ RESET:
|
|
|
ldi temp,1<<ACD
|
|
|
out ACSR,temp
|
|
|
|
|
|
-;;; настроим АЦП. опора - Vcc, канал 1, непрерывное преобразование. temp=0b00100010
|
|
|
+;;; настроим АЦП. опора - Vcc, канал 1, 62.5 kHz
|
|
|
ldi temp,1<<MUX0
|
|
|
out ADMUX,temp
|
|
|
- ldi temp,(1<<ADEN)|(1<<ADSC)|(6<<ADPS0)
|
|
|
+ ldi temp,(1<<ADEN)|(1<<ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
|
|
|
out ADCSRA,temp
|
|
|
+ ldi temp,(1<<ADC1D)
|
|
|
+ out DIDR0,temp
|
|
|
|
|
|
;;; таймер0 интервалы в 4 мсек (250 Hz). прескалер = 256
|
|
|
- ldi temp,(1<<CS02)
|
|
|
- out TCCR0B,temp
|
|
|
- ldi temp,T0DIV
|
|
|
- out TCNT0,temp ; запустили таймер
|
|
|
+; ldi temp,(1<<CS02)
|
|
|
+; out TCCR0B,temp
|
|
|
+; ldi temp,T0DIV
|
|
|
+; out TCNT0,temp ; запустили таймер
|
|
|
; прерывания от таймеров
|
|
|
- ldi temp,(1<<TOIE0)
|
|
|
- out TIMSK0,temp ; разрешим прерывание по переполнению
|
|
|
+; ldi temp,(1<<TOIE0)
|
|
|
+; out TIMSK0,temp ; разрешим прерывание по переполнению
|
|
|
|
|
|
;; timer1 - частота 200 гц, при тактовой 8МГц, прескалер=64
|
|
|
-; ldi temp,(3<<CS10)
|
|
|
-; out TCCR1B,temp
|
|
|
-; ldi temp,T1DIVH
|
|
|
-; out TCNT1H,temp
|
|
|
-; ldi temp,T1DIVL
|
|
|
-; out TCNT1L,temp ; запустили таймер 1
|
|
|
+ ldi temp,(3<<CS10)
|
|
|
+ out TCCR1B,temp
|
|
|
+ ldi temp,T1DIVH
|
|
|
+ out TCNT1H,temp
|
|
|
+ ldi temp,T1DIVL
|
|
|
+ out TCNT1L,temp ; запустили таймер 1
|
|
|
; разрешаем прерывание от таймера
|
|
|
-; ldi temp,1<<TOIE1
|
|
|
-; out TIMSK1,temp
|
|
|
+ ldi temp,1<<TOIE1
|
|
|
+ out TIMSK1,temp
|
|
|
|
|
|
;;; init
|
|
|
- ldi LEDN,0b11101111 ; первый индикатор
|
|
|
+ ldi LEDN,FIRST_LED ; первый индикатор
|
|
|
ldi temp,IND_LA
|
|
|
out DISP_DDR,temp
|
|
|
out DISP_PORT,temp
|
|
@@ -182,114 +183,79 @@ RESET:
|
|
|
mov LED2,temp
|
|
|
mov LED3,temp
|
|
|
mov LED4,temp
|
|
|
- ldi bAddr,low(Buffer)
|
|
|
- clr bIdx
|
|
|
|
|
|
;;; Enable interrupts
|
|
|
sei
|
|
|
;******************************
|
|
|
;;;;; Основная программа
|
|
|
BEGIN:
|
|
|
-;;; запускаем измерения и преобразования
|
|
|
+
|
|
|
+;;; Подготовимся к новым измерениям
|
|
|
clr msrL
|
|
|
clr msrH ; очистили хранилище результата
|
|
|
- ldi cnt1,16 ; загрузили счётчик измерений
|
|
|
- sbi ADCSRA,ADATE ; запуск free running mode
|
|
|
+ ldi cnt1,64 ; загрузили счётчик измерений
|
|
|
sbi ADCSRA,ADIE ; разрешаем прерывания от АЦП
|
|
|
+
|
|
|
+;;; Конец цикла, в начале :-)
|
|
|
+MAIN_END:
|
|
|
+ rcall WAIT_IRQ
|
|
|
+
|
|
|
+;;; Если при выходе из прерывания стоит флаг -- запускаем измерения
|
|
|
+ sbrs flags,MEASURE ; пора мерять?
|
|
|
+ rjmp CHECK_MEASURE ; если нет -- идём дальше
|
|
|
+ cbr flags,1<<MEASURE ; сбросим флаг
|
|
|
+
|
|
|
+;;; запускаем новый цикл измерений
|
|
|
+START_MEASURE:
|
|
|
sbi ADCSRA,ADSC ; запуск нов. преобразования
|
|
|
+ rjmp MAIN_END ; и спим дальше
|
|
|
|
|
|
-ML1:
|
|
|
-; rjmp PC+1 ; nop x 2 -- 1 world 2 takta. или sleep?
|
|
|
- rcall WAIT_IRQ ; один цикл измерения, ЕМНИП больше 100 мкс...
|
|
|
- tst cnt1 ; гоняем пустой цикл пока будут происходить 16 измерений
|
|
|
+;;; Если нет флага, значит прерывание было от АЦП
|
|
|
+CHECK_MEASURE:
|
|
|
+ tst cnt1 ; закончили измерения?
|
|
|
+ brne MAIN_END ; если нет -- спим дальше
|
|
|
+
|
|
|
+;; закончили, отключим прерывания
|
|
|
+ cbi ADCSRA,ADIE
|
|
|
|
|
|
- brne ML1
|
|
|
- cbi ADCSRA,ADIE ; запрещаем прерывания от АЦП
|
|
|
- cbi ADCSRA,ADATE ; stop free running mode
|
|
|
+;;; Здесь происходят все преобразования
|
|
|
+ML1:
|
|
|
+;; у нас 64 измерения, оверсэмплинг. пока делим на 8
|
|
|
lsr msrH
|
|
|
ror msrL
|
|
|
lsr msrH
|
|
|
- ror msrL ; поделили результат на 2^2
|
|
|
- ; теперь множим на Vref и делим на 4096
|
|
|
+ ror msrL
|
|
|
+ lsr msrH
|
|
|
+ ror msrL ; поделили результат на 2^3
|
|
|
+
|
|
|
+;; теперь нужно умножить на Vref и поделить на 8192 -- получим миливольты на входе АЦП
|
|
|
+;; а затем умножить на 4, чтобы получить напряжение на входе делителя.
|
|
|
+;; т.е. делим на 2048
|
|
|
ldi temp,low(VREF)
|
|
|
ldi tmp1,high(VREF)
|
|
|
- rcall MPY16U
|
|
|
- lsr job1 ; выбросили job0 == поделили на 256
|
|
|
+ rcall MPY16U ; отбросили job0 == поделили на 256
|
|
|
+ lsr job1
|
|
|
+ ror job0
|
|
|
+ lsr job1
|
|
|
ror job0
|
|
|
lsr job1
|
|
|
ror job0
|
|
|
-;; lsr job1
|
|
|
-;; ror job0
|
|
|
-;; lsr job1
|
|
|
-;; ror job0 ; доделили на 16, итого поделили на 4096
|
|
|
-; ldi cnt1,4
|
|
|
-;ML2: lsr job2
|
|
|
-; ror job1
|
|
|
-; dec cnt1
|
|
|
-; brne ML2
|
|
|
-; mov msrL,job0
|
|
|
-; mov msrH,job1 ; в MSR - напряжение в 10мВ
|
|
|
-;!!! умножить на входной делитель
|
|
|
-;; -- не доделили на 4 == умножили теперь на 4.
|
|
|
+
|
|
|
;; в реале нужно будет множить например на 400 и делить на 100 -- под реальный делитель.
|
|
|
; тут можно добавить коррекцию усиления.
|
|
|
|
|
|
-; сейчас текущий результат измерний в job1:job0
|
|
|
-
|
|
|
-
|
|
|
-;;; усреднения
|
|
|
- ; сохраним текущий результат
|
|
|
- mov XL,bAddr
|
|
|
- clr XH
|
|
|
- st X+,job0
|
|
|
- st X,job1 ; сохранили
|
|
|
- sbiw X,1 ; буфер в старой позиции -- на текущем результате
|
|
|
- clr msrL
|
|
|
- clr msrH
|
|
|
-
|
|
|
- ; теперь как-то нужно просуммировать содержимое буфера
|
|
|
- ldi cnt1,BuffSize
|
|
|
-BuffSummarize:
|
|
|
- ld temp,X+
|
|
|
- add msrL,temp
|
|
|
- ld temp,X+
|
|
|
- adc msrH,temp
|
|
|
- inc bIdx
|
|
|
- cpi bIdx,BuffSize
|
|
|
- brne BuffChkCnt
|
|
|
- ldi XL,low(Buffer)
|
|
|
- clr bIdx
|
|
|
-BuffChkCnt:
|
|
|
- dec cnt1
|
|
|
- brne BuffSummarize
|
|
|
-
|
|
|
- adiw X,2 ; адрес буфера - на следующую ячейку
|
|
|
- inc bIdx
|
|
|
- cpi bIdx,BuffSize
|
|
|
- brne BuffAddrSave
|
|
|
- ldi XL,low(Buffer)
|
|
|
- clr bIdx
|
|
|
-BuffAddrSave:
|
|
|
- mov bAddr,XL ; сохранили текущий адрес буфера
|
|
|
-
|
|
|
- ; тут имеем в msr сумму всех элементов массива. делим:
|
|
|
- ldi cnt1,BuffShift
|
|
|
-BuffDivide:
|
|
|
- lsr msrH
|
|
|
- ror msrL
|
|
|
- dec cnt1
|
|
|
- brne BuffDivide
|
|
|
-; теперь в msr среднее от содержимого буфера.
|
|
|
-; адрес и индекс буфера показывают следующую позицию.
|
|
|
-
|
|
|
+; сейчас текущий результат измерний в job1:job0. Перенесём в msr
|
|
|
+ mov msrH,job1
|
|
|
+ mov msrL,job0
|
|
|
+; наш результат, это по сути среднее за 64 измерения, в миливольтах, по входу.
|
|
|
|
|
|
;;; преобразуем msr в десятичный вид и положим в буфер индикатора
|
|
|
rcall bin2BCD16
|
|
|
- ; 4 значащих цифры в job1:job0
|
|
|
+ ; 5 значащих цифр в job2:job1:job0
|
|
|
ldi XL,AtLED1
|
|
|
clr XH
|
|
|
- mov temp,job1
|
|
|
- swap temp
|
|
|
+;; первый, старший разряд -- десятки вольт, младший нибл job2
|
|
|
+ mov temp,job2
|
|
|
; проверим на ведущий 0
|
|
|
andi temp,0x0F ; отсекаем ст ниббл
|
|
|
tst temp
|
|
@@ -299,21 +265,25 @@ BuffDivide:
|
|
|
rjmp MakeDigit2
|
|
|
MakeDigit3:
|
|
|
rcall OUT_NIBBL ; ниббл 3, десятки
|
|
|
+;; второй разряд -- единицы вольт, старший нибл job1
|
|
|
MakeDigit2:
|
|
|
mov temp,job1
|
|
|
+ swap temp
|
|
|
sbr flags,1<<NEED_DOT
|
|
|
- rcall OUT_NIBBL ; ниббл 2, единицы
|
|
|
+ rcall OUT_NIBBL
|
|
|
cbr flags,1<<NEED_DOT
|
|
|
+;; третий разряд -- десятые вольта, младший нибл job1
|
|
|
+ mov temp,job1
|
|
|
+ rcall OUT_NIBBL
|
|
|
+;; четвёртый разряд -- сотые вольта, старший нибл job0
|
|
|
mov temp,job0
|
|
|
swap temp
|
|
|
- rcall OUT_NIBBL ; ниббл 1, десятые
|
|
|
- mov temp,job0
|
|
|
- rcall OUT_NIBBL ; ниббл 0, сотые
|
|
|
+ rcall OUT_NIBBL
|
|
|
|
|
|
-;;; Конец цикла
|
|
|
- rcall WAIT_IRQ
|
|
|
+;;; и на новый виток
|
|
|
rjmp BEGIN
|
|
|
|
|
|
+
|
|
|
;******************************
|
|
|
;;;;; Подпрограммы
|
|
|
|
|
@@ -396,13 +366,15 @@ bBCDx_3:ld temp,-Z ;get (Z) with pre-decrement
|
|
|
;;;;; Обработчики прерываний
|
|
|
|
|
|
;******************************
|
|
|
-; Timer0 Overflow Handler
|
|
|
-TIM0_OVF:
|
|
|
+; Timer1 Overflow Handler
|
|
|
+TIM1_OVF:
|
|
|
; выводим данные на 7-ми сегментные индикаторы
|
|
|
PUSHF
|
|
|
|
|
|
- ldi temp,T0DIV
|
|
|
- out TCNT0,temp ; перезапустили таймер 0
|
|
|
+ ldi temp,T1DIVH
|
|
|
+ out TCNT1H,temp
|
|
|
+ ldi temp,T1DIVL
|
|
|
+ out TCNT1L,temp ; перезапустили таймер 1
|
|
|
|
|
|
;***************************
|
|
|
; вывод на индикатор очередной цифры
|
|
@@ -414,15 +386,15 @@ TIM0_OVF:
|
|
|
|
|
|
;;; выпихнем очередной байт в регистр
|
|
|
ldi cnt2,8 ; счетчик бит
|
|
|
-LO1: cbi SER_PORT,SCK ; SCK=0
|
|
|
+TLO1: cbi SER_PORT,SCK ; SCK=0
|
|
|
lsl temp ; старший бит в перенос
|
|
|
- brcc LO0 ; если в переносе 0 — перейти
|
|
|
+ brcc TLO0 ; если в переносе 0 — перейти
|
|
|
sbi SER_PORT,DATA ; выдали 1
|
|
|
- rjmp LOE
|
|
|
-LO0: cbi SER_PORT,DATA ; выдали 0
|
|
|
-LOE: sbi SER_PORT,SCK ; SCK=1, сдвиг данных
|
|
|
+ rjmp TLOE
|
|
|
+TLO0: cbi SER_PORT,DATA ; выдали 0
|
|
|
+TLOE: sbi SER_PORT,SCK ; SCK=1, сдвиг данных
|
|
|
dec cnt2
|
|
|
- brne LO1
|
|
|
+ brne TLO1
|
|
|
|
|
|
sbi SER_PORT,LOCK ; из 0 в 1 -- защёлкивание данных в регистре
|
|
|
in temp,DISP_PORT
|
|
@@ -430,11 +402,13 @@ LOE: sbi SER_PORT,SCK ; SCK=1,
|
|
|
and temp,LEDN
|
|
|
out DISP_PORT,temp ; включаем очередной индикатор
|
|
|
lsl LEDN ; сдвинули - следующий индикатор
|
|
|
- brlo T0L2 ; вышли за границы? проверка
|
|
|
- ldi LEDN,0b11101111 ; да, загружаем начальное значение
|
|
|
+ brlo T1L2 ; вышли за границы? проверка
|
|
|
+ ldi LEDN,FIRST_LED ; да, загружаем начальное значение
|
|
|
ldi YL,AtLED1 ; загружаем адрес 1-го индикатора
|
|
|
|
|
|
-T0L2:
|
|
|
+T1L2:
|
|
|
+ sbr flags,1<<MEASURE ; пора мерять
|
|
|
+ ;;; выход
|
|
|
POPF
|
|
|
reti
|
|
|
|