Страница 1 из 1

Вопросы по программе "Частотомер"

Добавлено: Вс ноя 15, 2015 20:02:20
Dastan
Всем доброго времени суток! Разбираюсь с программой Джона Мортона "Частотомер". Не могу найти в чем ошибка. Только учусь. Поэтому сорри за код.
Изображение
Спойлер

Код: Выделить всё

;**************************
;Автор:Ионушас Сергей     *
;Дата: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            ;

Re: Вопросы по программе "Частотомер"

Добавлено: Вс ноя 15, 2015 21:41:52
Z_h_e
Попробуйте в свойствах модели индикатора поставить время, ну например 100нс.

И код возьмите в теги

Код: Выделить всё

 и под споллер. Не читаемо же.

Re: Вопросы по программе "Частотомер"

Добавлено: Вс ноя 15, 2015 22:10:21
Dastan
Спасибо. Поправил. В протеусе поставил в свойства индикатора 1нс. Вижу что поочередно медленно каждый сегмент переключается, бегущий "0" по 3-м индикаторам.Изображение

Re: Вопросы по программе "Частотомер"

Добавлено: Пн ноя 16, 2015 05:12:16
akl
Изображение
freq_1200_1.PNG
Вы не первый повторили эту ошибку.

Re: Вопросы по программе "Частотомер"

Добавлено: Пн ноя 16, 2015 15:04:48
Dastan
Изображение
Внес данное исправление в схему. Горит 3 "8".Что еще может быть?