Вопросы по программе "Частотомер"
Добавлено: Вс ноя 15, 2015 20:02:20
Всем доброго времени суток! Разбираюсь с программой Джона Мортона "Частотомер". Не могу найти в чем ошибка. Только учусь. Поэтому сорри за код.
Спойлер
Код: Выделить всё
;**************************
;Автор:Ионушас Сергей *
;Дата:01.11.2015 *
;Версия:1.0 *
;Имя файла:chastotomer *
;Для AVR:at90s1200 *
;Тактовая частота:4 *
;**************************
;Выполняемые функции
;
.device AT90S1200
.nolist
.include "C:\Program Files (x86)\Atmel\AVR Tools\AvrAssembler\Appnotes\1200def.inc"
.list
;Назначаем имена рабочим регисрам
.def temp =r16
.def temp2 =r17
.def temp3 =r18
.def lowerbyte =r19
.def upperbyte =r20
.def DisplayCounter =r21
.def DisplayNumber =r22
.def Delay1 =r23
.def Delay2 =r24
.def Delay3 =r25
.def Hundreds =r26
.def Tens =r27
.def Ones =r28
.def store =r29
.def store2 =r19
.def Counter =r20
;-----------------------------------
rjmp Init
Init:
ser temp ;
out DDRB,temp ; устанавливаем все ножки порта B как выходы (PB1-7 - для
; индикаторов, и PB0 - СИД)
ldi temp,0b11101111 ; PD4 - вход для замеряемого сигнала
out DDRD,temp ;
clr temp ; выключаем подтяжку выходов порта B
out PORTB,temp ;
ldi temp,0b00000001 ; выключаем все выходы порта D кроме одного для первого Индикатора
out PORTD,temp ;
ldi temp,0b00001110 ; настраиваем сторожевой таймер на сбрасыв. через 1 сек.
out WDTCR,temp ;
ldi temp,0b00110000 ;
out MCUCR,temp ; разрешаем режим "Power Down"
ldi Hundreds,12 ;
ldi Tens,12 ;
ldi Ones,12 ;
clr ZH ; сбрасывает старший байт указателя Z
ldi DisplayCounter,50 ;
clr DisplayNumber
ldi temp,0b11111100 ; 0
mov R0,temp ;
ldi temp,0b01100000 ; 1
mov R1,temp ;
ldi temp,0b11011010 ; 2
mov R2,temp ;
ldi temp,0b11110010 ; 3
mov R3,temp ;
ldi temp,0b01100110 ; 4
mov R4,temp ;
ldi temp,0b10110110 ; 5
mov R5,temp ;
ldi temp,0b10111110 ; 6
mov R6,temp ;
ldi temp,0b11100000 ; 7
mov R7,temp ;
ldi temp,0b11111110 ; 8
mov R8,temp ;
ldi temp,0b11110110 ; 9
mov R9,temp ;
ldi temp,0b01101110 ; H
mov R10,temp ;
ldi temp,0b00000010 ; -
mov R11,temp ;
rjmp Start
;-----------------------------------------------
;Подпрограмма для работы с дисплеем
;-----------------------------------------------
Display:
dec DisplayCounter ; Обновляем дисплей при каждом 50-м вызове
breq PC+2 ; если нулевой флаг (Z=1) установлен то переход
; на команду по адресу PC+2
ret ; выход из подпрограммы если результат не равен нулю
wdr ; Переодически Сбрасываем сторожевой таймер,
; поскольку прогамма Display вызывается часто
; (не реже 1 раз в секунду)
ldi DisplayCounter,50 ; если результат счетчика равен 0, то надо
; снова загружать число 50 в счетчик
; Сдесь мы определяем с каким из индикаторов следует работать
; для чего в регистре DisplayNumber храним номер индикатора (от 0 до 2)
;
inc DisplayNumber ; инкрементируем
cpi DisplayNumber,3 ; если равено 3 сбрасываем в нуль
brne PC+2 ; если нет - перепргыиваем через команду
clr DisplayNumber ;
ldi ZL,26 ; ZL указывает на R26
add ZL,DisplayNumber ; добавляем число к ZL наход.в Disp.Numb.(1-3)
; в результате мы укажем на одно из 3 чисел,
; которое нам нужно отобразить
ld temp,Z ; загружаем это число косвенно в temp
clr ZL ; регистры с числам для индикаторов находятся
; c R0-R12, поэтому очищаем решистр указатель Z
;
add ZL,temp ; прибавляя число наход. в регистре TEMP
; к регистру ZL мы установим указатель на код
; семисег.индик. соответ. отображ. чисел
ld temp,Z ; считываем Z в temp
sbic PortB,7 ; проверяем состояние 7 бита в порте B (кГц)
; если....
ori temp,0b10000000 ; Если включен, то не выключаем путем операции "ИЛИ"
out PortB,temp ; Выводим temp в порт B
; Включаем требуемый индикатор
;---------------------------------------------
in temp,PinD ;
lsl temp ;
sbrc temp,3 ;
ldi temp,0b00000001 ;
out PortD,temp ;
ret ;
;-----------------------------------------------------------
;Подпрограмма для конвертирования 4-разрядного шест. числа в 3 десятичных цифры для разрядов
;------------------------------------------------------------------
DigitConvert:
clr Hundreds ; очищаем регистры
clr Tens ;
clr Ones ;
FindHundreds: ; СОТНИ
subi lowerbyte,100 ; вычитаем 100 из младшего байта
sbci upperbyte,0 ; Вычитание константы и содержимого флага переноса (С) (тоесть 1 при переносе) из содержимого регистра и занес ответа в него
brcs FindTens ; если перенос (С=1) переходим в вычисл.десятков
inc Hundreds ; если нет, инкрем.число сотен
rjmp FindHundreds ; повторяем цикл
FindTens: ; ДЕСЯТКИ
subi lowerbyte,-100 ; прибавляем последние 100
subi lowerbyte,10 ; вычитаем 10 из младшего байта
brcs FindOnes ; если перенос (С=1) переходим к вычислению едениц.
inc Tens ; инкрменетируем число десятков
rjmp FindTens+1 ; Повторяем цикл
FindOnes: ; ЕДЕНИЦЫ
subi lowerbyte, -10 ; Прибавляем последние 10
mov Ones,lowerbyte ; Сохраяняем число едениц
ret ; Выходим и з подпрограммы
;-----------------------------------------------------------
;---------------------------------------
; НАЧАЛО ПРОГРАММЫ
;---------------------------------------
; ОБРАБОТКА СИГАЛОВ С ЧАСТОТОЙ БОЛЕЕ 1 КГЦ
Start:
ldi Delay1,0x00 ; Вбиваем числа в регистры для задержки
ldi Delay2,0x7D ;
ldi temp,0b00000011
out TCCR0,temp
ldi temp,0b10000000
out PortB,temp
clr upperbyte
clr temp
out TCNT0,temp
Highspeed:
subi Delay1,1 ; задержка
sbci Delay2,0 ;
brcs DoneHi ; переход по переносу (если С=1)
mov temp2,temp ;
in temp,TCNT0 ;
cp temp,temp2 ; сравниваем старое и новое значение таймера
brsh Highspeed ; переход на метку при условии больше или равно
inc upperbyte ; инкрементируем страший байт
cpi upperbyte,0xFA ; сравнение с чилслом 250 (слишком высокая частота?)
breq TooHigh ; Выходим из цикла если так
subi Delay1,1 ; декрементируем счетные регистры
sbci Delay2,0 ;
brcs DoneHi ; выходим если время вышло (тоесть если С=1)
nop ; выравниваем на 1 такт за счет пустой команды
rjmp Highspeed ; возращаемся на начало цикла
DoneHi:
in lowerbyte,TCNT0 ; значение T/C0 сохр.в регистре lowerbyte
cp lowerbyte,temp ; сравниваем с регистром lowerbyte
brsh Divide64 ; если lowerbyte больше или равно temp,то сравн.upperbyte и число FA
inc upperbyte ; инкремент upperbyte в противном случае.
cpi upperbyte,0xFA ; сравнение с 0xFA
breq TooHigh ; если равен переход к программе TooHigh
;деление 2-байтного числа в регистрах lowerbyte и upperbyte
Divide64:
ldi temp,6 ;
lsr upperbyte ; делим upperbyte на 2 (лог.сдвиг вправо с учитываением флага перноса С)
ror lowerbyte ; делим lowerbyte (сдвиг вправо и заносим флаг переноса(С) со старшего байта вместо 7-го.
dec temp ; уменьшаем счетчик (6-1)
brne Divide64+1 ; если досих пор С=0 то повтр.цикла, а когда весь счетчик уменьшится то С=1 и переход дальше
; здесь мы проверяем ессть ли у нас здесь низкая частота?
cpi upperbyte,0 ; старший байт = 0?
brne PC+3 ; если нет переход на DigitConverter
cpi lowerbyte,0 ; Младший байт = 0?
breq LowSpeed ; если частота меньше 1кГц - переходим к секции
; измерения низкой частоты
; вызов DigitConvet
rcall DigitConvert ; вызов конвертора
ldi Delay1,0x09 ; иницилизация счетных регистров для задержки
ldi Delay2,0x2E ;
ldi Delay3,0x02 ;
HalfSecond: ; формируем пол секунд.задержку для вывода данных
; на дисплей после завершение измерения (64 мс)
rcall Display ;
subi Delay1,1 ;
sbci Delay2,0 ;
sbci Delay3,0 ;
brcc HalfSecond ; если не законч.время повторяем цикл.
rjmp Start ; если да переходим в начало проги (к Start)
TooHigh: ; подпрограма для вывода на дисплей "HI"
ldi Hundreds,11 ;
ldi Tens,10 ;
ldi Ones,1 ;
rjmp HalfSecond-3 ;
;-----------------------------------------------------------------------------
; Секция обработки сигналов с частотой менее 1 кГЦ
;-----------------------------------------------------------------------------
LowSpeed:
ldi temp,0b00000001 ; устанав. конфиг. для T/C0 что бы счет выполнялся
; по какждому такту
out TCCR0,temp ;
clr Delay2 ; очищаем регистры задержки
clr Delay3 ;
cbi PortB,7 ; сбросим PB7,что бы включить СИД "Гц"
in store,PinD ; для определения момента изменения состояния входа PD4
; запоминаем нач.значение регистра PinD
FirstChange:
rcall Display ; Обрабатываем дисплей
in store2,PinD ; сохраняем текущее значение
eor store2,store ; Сравниваем нач. и текущ. значение (ищем отличие XORом)
sbrs store2,4
rjmp FirstChange
ldi Counter,2
clr temp2
out TCNT0,temp2
in store,PinD
;в этом цикле будем проверять сост.входа и при его измен. выполн. переход к секции Change
LowLoop:
in store2,PinD ; сохраняем текущее значение
eor store2,store ; Сравниваем нач. и текущ. значение (ищем отличие XORом)
sbrc store2,4 ; Игнор всех битов кроме 4-го
rjmp Change ; Переходим к Change при измении PD4
rcall Display ; Обрабатываем дисплей
mov temp2,Delay1 ;
in Delay1,TCNT0 ; не было ли переноса в T/C0?
cp Delay1,temp2 ;
brsh LowLoop ;
inc Delay2 ;
brne LowLoop ;
inc Delay3 ;
cpi Delay3,0x3E ; слишком малое значение?
breq TooSlow ;
rjmp LowLoop ;
Change:
in store,PortB ; считваем новое значение порта B
dec Counter ; Ждем второго изменения
brne LowLoop ; если это не второе изменение - остаемся в цикле
ldi temp,0x0F ; загружаем временные регистры(999Гц-4004 такта)
ldi temp2,0x00 ; загружаем временные регистры
cpi Delay1,0xA0 ; сравниваем 3-байт. число с регистрами
cpc Delay2,temp ;
cpc Delay3,temp2 ;
brcc PC+2
rjmp Start ;
; вынужденн применти rjmp (Start далеко находится)
Divide:
sub temp,Delay1 ;
sbc temp2,Delay2 ;
sbc temp3,Delay3 ;
brcs DoneDividing ;
inc lowerbyte ;
brne Divide ;
inc upperbyte ;
rjmp Divide ;
DoneDividing:
rcall DigitConvert ;
rjmp LowSpeed ;
TooSlow:
clr temp ;!Очищаем temp!
out PortD,temp ;вывводим 0 в PortD
sleep ;Засыпаем
rjmp LowSpeed ;