Обсуждаем контроллеры компании Atmel.
Ответить

Расчет частоты таймера. Где-то ошибка в логике.

Вт янв 09, 2018 01:29:51

Народ, написал программу с таймером для мигания светодиодом.
Он мигает, но не с той частотой…
Мигает где-то с частотой 3 – 4 Гц. А по моим расчетам должен мигать с частотой 0,1 Гц.
Я пользовался методикой, изложенной в книге Ревича (Практическое программирование микроконтроллеров AVR).
Вот как я считал частоту:
Микропроцессор Atmega16. Выбрал частоту 8МгЦ.
В пред-делитель прописал 8.
Значит 8000000 / 8 = 1000000 (1мГц) - это частота, с которой тикает таймер.
Далее в регистр TCNT0 записываю 250 для круглого счета:
ldi r16, 250
neg r16 ;
out TCNT0, r16
По идее прерывание должно происходить с частотой 4кГц (1000000/250 = 4000), то есть 4000 прерываний за одну сек.
Обработчик прерываний вызывает подпрограмму.
В ней я выделил в оперативной памяти переменную в 2 байта.
В нее прописал число 40000.
Переменная декрементируется прерыванием.
Когда становится равной 0, то инвертируется PortD, на 0-м пине которого я запитал светодиод.
По идее, он должен мигать с частотой 4000 / 40000, т.е. 0,1 Гц.
А он мигает с частотой 3-4 Герца…
Помогите разобраться.
Код привожу:
Код:
.include "m16def.inc"
.def rK_div = r16
.def count  = r17
.def Temp1  = r18
.def Temp2  = r19
.equ K_div = 250
.equ t_counter = 40000
;Макросы---------------------------------------------------------------------
.macro mouti
      ldi r20, @1
     out @0, r20
.endm
;----------
.dseg
         ram_counter: .byte 2         
.cseg
         
.ORG $000        ; (RESET)
         RJMP   RESET
         .ORG $002
         RETI             ; (INT0) External Interrupt Request 0
         .ORG $004
         RETI             ; (INT1) External Interrupt Request 1
         .ORG $006
         RETI            ; (TIMER2 COMP) Timer/Counter2 Compare Match
         .ORG $008
         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
         .ORG $00A
         RETI            ; (TIMER1 CAPT) Timer/Counter1 Capture Event
         .ORG $00C
         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
         .ORG $00E
         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
         .ORG $010
         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow
         .ORG $012
         RJMP timer0ovf  ; (TIMER0 OVF) Timer/Counter0 Overflow
         .ORG $014
         RETI             ; (SPI,STC) Serial Transfer Complete
         .ORG $016
         RETI            ; (USART,RXC) USART, Rx Complete
         .ORG $018
         RETI             ; (USART,UDRE) USART Data Register Empty
         .ORG $01A
         RETI             ; (USART,TXC) USART, Tx Complete
         .ORG $01C
         RETI            ; (ADC) ADC Conversion Complete
         .ORG $01E
         RETI             ; (EE_RDY) EEPROM Ready
         .ORG $020
         RETI             ; (ANA_COMP) Analog Comparator
         .ORG $022
         RETI             ; (TWI) 2-wire Serial Interface
         .ORG $024
         RETI             ; (INT2) External Interrupt Request 2
         .ORG $026
         RETI             ; (TIMER0 COMP) Timer/Counter0 Compare Match
         .ORG $028
         RETI             ; (SPM_RDY) Store Program Memory Ready

       .ORG   INT_VECTORS_SIZE         
; Interrupts ==========
timer0ovf:
           push Temp1
         in   Temp1, SREG
         push Temp1
         push Temp2
           
         call dec_proc

           pop Temp2
         pop Temp1
         out SREG, Temp1
         pop Temp1
         
           RETI
;----------
       
   
        rjmp reset
RESET:  nop
RAM_flash:
            ldi zl, low(sram_start)
            ldi zh,high(sram_start)
            clr r16
flash:      st  z+, r16
            cpi zh,high(ramend+1)
          brne flash

          cpi zl,low (ramend+1)
          brne flash
          clr zl
          clr zh

          ldi zl, 30
            clr zh
            dec zl
            st  z, zh
          brne PC-2
         nop
         clr Temp1
            out TCNT0,Temp1
;Инициализирую стек ----------
            ldi Temp1, low(ramend)
         out spl, Temp1
         ldi Temp1,high(ramend)
         out sph, Temp1
;Инициализирую порт D для светодиода------------------------------------
            mouti DDRD, 0b00000001
         mouti PortD,0b11111110
         
;----------
;Записываю 40000 в переменную в ram-----------------------------------
ram_var:    nop
            ldi Temp1, low(t_counter)
         sts ram_counter,   Temp1
         ldi Temp1,high(t_counter)
         sts ram_counter+1, Temp1
;----------
;Инициализирую таймер ----------       
       
          ldi rK_div, K_div
          neg rK_div
          out TCNT0,rK_div
          mouti TCCR0,1<<CS01    ;предделитель 8
          mouti TIMSK,1<<TOIE0   ;разрешаю прерывания таймера
          mouti SREG, $80             ;разрешаю все прерывания (SREG)
      
;----------
main:        nop
             rjmp main       

;Подпрограммы----------------------------------------------------------------

;Декремент переменной в ram ----------
dec_proc:   lds Temp1, ram_counter
            lds Temp2, ram_counter+1

dec_var:    subi Temp1,1
            sbci Temp2,0
         brcc no_ziro
         rjmp dec_end

no_ziro:    sts ram_counter,   Temp1
         sts ram_counter+1, Temp2
         rjmp dec_proc

dec_end:    nop
;Когда 0, инвертирую PortD ----------
            cli
            ldi Temp1, low(t_counter)
            ldi Temp2,high(t_counter)

         sts ram_counter,   Temp1     ;восстанавливаю значение переменной в ram
         sts ram_counter+1, Temp2

            in  Temp1, PortD
         ldi Temp2,0b00000001
         eor Temp1,Temp2     
         out PortD, Temp1
;----------
            sei
            ret      
;;End подпрограммы------------------------------------------------------         

Re: Расчет частоты таймера. Где-то ошибка в логике.

Вт янв 09, 2018 02:02:49

Далее в регистр TCNT0 записываю 250 для круглого счета:
ldi r16, 250
neg r16 ;
out TCNT0, r16

Neg то тут что делает?

Re: Расчет частоты таймера. Где-то ошибка в логике.

Вт янв 09, 2018 05:19:29

ultexplorer Вы должны отсчитать 250мкс и уменьшить на единицу счетчик переполнений, а программа отсчитав 250мкс 40'000 выполняет декремент счетчика, выходит из прерывания
Спойлер
Код:
.include "m16def.inc"
.def rK_div = r16
.def count  = r17
.def Temp1  = r18
.def Temp2  = r19
.equ K_div = 250
.equ t_counter = 40000
;Макросы---------------------------------------------------------------------
.macro mouti
      ldi r20, @1
     out @0, r20
.endm
;----------
.dseg
         ram_counter: .byte 2         
.cseg
         
.ORG $000        ; (RESET)
         RJMP   RESET
;         .ORG $002
;         RETI             ; (INT0) External Interrupt Request 0
;         .ORG $004
;         RETI             ; (INT1) External Interrupt Request 1
;         .ORG $006
;         RETI            ; (TIMER2 COMP) Timer/Counter2 Compare Match
;         .ORG $008
;         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
;         .ORG $00A
;         RETI            ; (TIMER1 CAPT) Timer/Counter1 Capture Event
;         .ORG $00C
;         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
;         .ORG $00E
;         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
;         .ORG $010
;         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow

.ORG $012

   SUBI   XL,LOW(1)
   SBCI   XH,HIGH(1)
   BRNE   OUT_OVER_T0
   in  Temp1, PortD
   ldi Temp2,0b00000001
   eor Temp1,Temp2     
   out PortD, Temp1

   LDI   XH,HIGH(40000)
   LDI   XL,LOW(40000)

OUT_OVER_T0:
   LDI   R16,-250
   OUT   TCNT0,R16
   
   RETI
;         RJMP timer0ovf  ; (TIMER0 OVF) Timer/Counter0 Overflow
 ;        .ORG $014
  ;       RETI             ; (SPI,STC) Serial Transfer Complete
   ;      .ORG $016
    ;     RETI            ; (USART,RXC) USART, Rx Complete
     ;    .ORG $018
      ;   RETI             ; (USART,UDRE) USART Data Register Empty
       ;  .ORG $01A
        ; RETI             ; (USART,TXC) USART, Tx Complete
;         .ORG $01C
 ;        RETI            ; (ADC) ADC Conversion Complete
  ;       .ORG $01E
   ;      RETI             ; (EE_RDY) EEPROM Ready
    ;     .ORG $020
     ;    RETI             ; (ANA_COMP) Analog Comparator
      ;   .ORG $022
;         RETI             ; (TWI) 2-wire Serial Interface
 ;        .ORG $024
  ;       RETI             ; (INT2) External Interrupt Request 2
   ;      .ORG $026
    ;     RETI             ; (TIMER0 COMP) Timer/Counter0 Compare Match
     ;    .ORG $028
;         RETI             ; (SPM_RDY) Store Program Memory Ready

;       .ORG   INT_VECTORS_SIZE         
; Interrupts ==========
;timer0ovf:
;           push Temp1
;         in   Temp1, SREG
;         push Temp1
;         push Temp2
           
;         call dec_proc

;           pop Temp2
;         pop Temp1
;         out SREG, Temp1
;         pop Temp1
         
;           RETI
;----------
       
   
;        rjmp reset
RESET:
;  nop
;RAM_flash:
;            ldi zl, low(sram_start)
;            ldi zh,high(sram_start)
;            clr r16
;flash:      st  z+, r16
;            cpi zh,high(ramend+1)
;          brne flash

;          cpi zl,low (ramend+1)
;          brne flash
;          clr zl
;          clr zh

 ;         ldi zl, 30
  ;          clr zh
   ;         dec zl
    ;        st  z, zh
     ;     brne PC-2
      ;   nop
       ;  clr Temp1
        ;    out TCNT0,Temp1
;Инициализирую стек ----------
            ldi Temp1, low(ramend)
         out spl, Temp1
         ldi Temp1,high(ramend)
         out sph, Temp1
;Инициализирую порт D для светодиода------------------------------------
            mouti DDRD, 0b00000001
         mouti PortD,0b11111110
         
;----------
;Записываю 40000 в переменную в ram-----------------------------------
REG_var:
   LDI   XH,HIGH(40000)
   LDI   XL,LOW(40000)
;    nop
;            ldi Temp1, low(t_counter)
;         sts ram_counter,   Temp1
;         ldi Temp1,high(t_counter)
;         sts ram_counter+1, Temp1
   LDI   R16,1<<SE
   OUT   MCUCR,R16
;Инициализирую таймер ----------   
   LDI   R16,-250
   OUT   TCNT0,R16       
;          ldi rK_div, K_div
;          neg rK_div
;          out TCNT0,rK_div
          mouti TCCR0,1<<CS01    ;предделитель 8
          mouti TIMSK,1<<TOIE0   ;разрешаю прерывания таймера
          mouti TIFR,1<<TOV0   ;сброс флага переполнения
        SEI
;          mouti SREG, $80             ;разрешаю все прерывания (SREG)
     
;----------
main:
   SLEEP
   nop
   rjmp main       

;Подпрограммы----------------------------------------------------------------

;Декремент переменной в ram ----------
;dec_proc:   lds Temp1, ram_counter
;            lds Temp2, ram_counter+1

;dec_var:    subi Temp1,1
;            sbci Temp2,0
;         brcc no_ziro
;         rjmp dec_end

;no_ziro:    sts ram_counter,   Temp1
;         sts ram_counter+1, Temp2
;         rjmp dec_proc

;dec_end:    nop
;Когда 0, инвертирую PortD ----------
;            cli
;            ldi Temp1, low(t_counter)
;            ldi Temp2,high(t_counter)

;         sts ram_counter,   Temp1     ;восстанавливаю значение переменной в ram
;         sts ram_counter+1, Temp2

;            in  Temp1, PortD
;         ldi Temp2,0b00000001
;         eor Temp1,Temp2     
;         out PortD, Temp1
;----------
;            sei
;            ret     
;;End подпрограммы---------------------------
.EXIT

Re: Расчет частоты таймера. Где-то ошибка в логике.

Вт янв 09, 2018 05:35:21

dec_var: subi Temp1,1
sbci Temp2,0
brcc no_ziro
rjmp dec_end

brne , я по памяти команду написал, давно на ассме ничего не делал. Ну т.е. нужно проверять флаг Z.

Еще важный момент в целом, но возможно не в этом коде. Вы зачем то разрешаете прерывания внутри обработчика прерывания, это чревато зависнуть и сорвать стек.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Вт янв 09, 2018 06:25:36

Код:
sei
ret 
Проще выходить по RETI

По мне, лучше использовать режим CTC. Отсчет времени получается гораздо точнее.
Спойлер
Код:
.include "m16def.inc"
.equ   Fo=8000000
.def Temp1  = r18
.def Temp2  = r19

;Макросы------------------------------------------
.macro mouti
      ldi r20, @1
     out @0, r20
.endm
;----------
.cseg
         
.ORG $000
RESET:
   RJMP   START

.ORG $026; (TIMER0 COMP) Timer/Counter0 Compare Match
   SUBI   XL,LOW(1)
   SBCI   XH,HIGH(1)
   BRNE   OUT_OVER_T0
   RET
OUT_OVER_T0:
   RETI             ; (TIMER0 COMP) Timer/Counter0 Compare Match
;*************************************************
START:
;Инициализирую стек ----------
            ldi Temp1, low(ramend)
         out spl, Temp1
         ldi Temp1,high(ramend)
         out sph, Temp1
;Инициализирую порт D для светодиода------------------------------------
            mouti DDRD, 0b00000001
         mouti PortD,0b11111110
;Записываю 40000 в переменную в ram-----------------------------------
REG_var:
   LDI   XH,HIGH(Fo/10/250/8)
   LDI   XL,LOW(Fo/10/250/8)   ; 0,1 SEC
;   LDI   XH,HIGH(1*Fo/250/8)
;   LDI   XL,LOW(1*Fo/250/8)   ; 1 SEC
;   LDI   XH,HIGH(10*Fo/250/8)
;   LDI   XL,LOW(10*Fo/250/8)   ; 10 SEC

   LDI   R16,1<<SE
   OUT   MCUCR,R16
;Инициализирую таймер ----------   
   LDI   R16,250-1
   OUT   OCR0,R16       
   mouti TIMSK,1<<OCIE0   ;разрешаю прерывания таймера
   mouti TIFR,1<<OCF0   ;сброс флага переполнения

   mouti TCCR0,1<<CS01|1<<WGM01    ;Fo/8, CTC
   SEI
;----------
main:
   SLEEP
   BRIE   MAIN
   RJMP REG_VAR       
.EXIT

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 14:22:39

Далее в регистр TCNT0 записываю 250 для круглого счета:
ldi r16, 250
neg r16 ;
out TCNT0, r16

Neg то тут что делает?

Это 256 - 250 = 6. С 6 начинается счет, так как таймер работает по переполнени. Т.е, чтобы таймер отсчитал 250 тиков, а затем сработало прерывание, необходимо. чтобы он начинал отсчет с 6.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 14:24:34

Освойте режим CTC, как указал akl, таймер будет считать от 0 до нужного значения и сам сбрасываться.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 14:50:57

Освойте режим CTC, как указал akl, таймер будет считать от 0 до нужного значения и сам сбрасываться.

Спасибо. Займусь этим.
В своем коде нашел ошибку.
Забыл поставить метку на выход из подпрограммы, если переменная все еще больше 0.
Вот поправил подпрограмму:
Код:
;Счетчик декремент-----------------------------------------------------------
dec_proc:   lds Temp1, ram_counter
            lds Temp2, ram_counter+1

dec_var:    subi Temp1,1
            sbci Temp2,0
         brcc no_ziro
         rjmp dec_end

no_ziro:    sts ram_counter,   Temp1
         sts ram_counter+1, Temp2
         rjmp end_proc

dec_end:    nop
;Здесь инвертируем PortD ----------
            //cli
            ldi Temp1, low(t_counter)
            ldi Temp2,high(t_counter)

         sts ram_counter,   Temp1
         sts ram_counter+1, Temp2

            in  Temp1, PortD
         ldi Temp2,0b00000001 ; маска
         eor Temp1,Temp2      ;инвертирую
         out PortD, Temp1
;----------
            //sei
end_proc:   ret      
;;End Счетчик декремент------------------------------------------------------         

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 14:55:21

ultexplorer писал(а):Это 256 - 250 = 6

neg , это же не оператор препроцессора, а реальная команда, абсолютно избыточная.
Код:
ldi r16, 0-250
//neg r16 ;
out TCNT0, r16

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 15:05:43

ultexplorer писал(а):Это 256 - 250 = 6

neg , это же не оператор препроцессора, а реальная команда, абсолютно избыточная.
Код:
ldi r16, 0-250
//neg r16 ;
out TCNT0, r16

Точно!
Не все в книгах верно...

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 15:17:45

Метод рассчета несколько....
Если стандартная частота генератора (внутреннего) 8МГц, то обязательно включен предделитель (фузами, ежли МК после выпуска заводом - изготовителем никто не перепрошивал "по иному").
Итогом будем иметь тактовую ядра по умолчанию в 1МГц или привычнее 0,000001 секунды/такт.
250 тиков таймера дадут прерывание в 0,000001 *250=0,000250 секунды.
Тогда чтобы получить 0,1 секунды на инверсию потребуется 0,1/0,00025=400 прерываний. А у автора АЖ 40000!
И то при инверсии состояния вывода это будет мигание не раз в 0,1 а раз в 0,2 секунды (5ГЦ).
:tea:
Последний раз редактировалось BOB51 Ср янв 10, 2018 15:21:50, всего редактировалось 1 раз.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 15:21:17

Я Вам уже говорил. Ваша переменная не проверяется на ноль. Вы перейдете на метку dec_end, после того как из переменной равной 0 вычтете 1. Так что можете считать что проверяется на отрицательный знак числа (хотя и это не корректное утверждение). Для Вашего кода это врядли важно, всего лишь одна итерация дополнительная, но проверки на ноль нет.

З.Ы. Зачем команды nop?

----------
З.З.Ы Выкинте Ваш код, возьмите код akl. Я не предлагаю его брать как готовый текст бессмысленно, раскурите его как следует.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Ср янв 10, 2018 21:21:48

0,1 Гц - это до фига времени. Нужно делать на программных таймерах. Вкратце, аппаратный таймер настраивается на системный тик. Времянки выбираете исходя из своих задач. 1 мс, 10 мс. Пример на 1 мс при частоте кварца 16 МГц:
Спойлер
Код:
//==================
.equ ST_TCNT   = TCNT0
.equ ST_TIMSK   = TIMSK
.equ ST_OCIE   = OCIE0
.equ ST_OCR      = OCR0
.equ ST_TCCR   = TCCR0
.equ CS0      = CS00
.equ CS1      = CS01
.equ CS2      = CS02
//==================

//==================
.equ SYS_TICK   = 1 // Период системного таймера 1 мс
//==================

//==================
.macro   Init_System_Timer
   clr      r16
   out      ST_TCNT, r16
   in      r16, ST_TIMSK
   sbr      r16, 1<<ST_OCIE
   out      ST_TIMSK, r16
   outi   ST_OCR, (XTAL/64/1000)
   in      r16, ST_TCCR
   sbr      r16, 1<<CS0 | 1<<CS1
   out      ST_TCCR, r16
.endmacro

.macro ReRun_Sys_Timer
   in      r16,ST_OCR
   subi   r16,-(XTAL/64/1000)
   out      ST_OCR,r16
.endmacro
//==================

//==================
Sys_Timer_Comp:
   push   r16
   in      r16,SREG
   push   r16

   ReRun_Sys_Timer

   sbr      FLAGS,1<<SYS_TICK_FLG

   pop      r16
   out      SREG,r16
   pop      r16
   reti
//==================


Спойлер
Код:
// vectors_m8535

.cseg

.org   0x0000
      rjmp   Reset

;====== INTERRUPT VECTORS ============
.org   INT0addr            ; External Interrupt 0
      reti

.org   INT1addr            ; External Interrupt 1
      reti

.org   OC2addr               ; Timer/Counter2 Compare Match
      reti // rjmp   Proc_Int_BAM // reti

.org   OVF2addr            ; Timer/Counter2 Overflow
      reti

.org   ICP1addr            ; Timer/Counter1 Capture Event
      reti

.org   OC1Aaddr            ; Timer/Counter1 Compare Match A
      reti

.org   OC1Baddr            ; Timer/Counter1 Compare Match B
      reti

.org   OVF1addr            ; Timer/Counter1 Overflow
      reti

.org   OVF0addr            ; Timer/Counter0 Overflow
      reti

.org   SPIaddr               ; SPI Serial Transfer Complete
      reti               ; rjmp   SPI_Transfer_Int

.org   URXCaddr            ; USART, RX Complete
      reti

.org   UDREaddr            ; USART Data Register Empty
      reti

.org   UTXCaddr            ; USART, TX Complete
      reti

.org   ADCCaddr            ; ADC Conversion Complete
      reti // rjmp   ADC_Complete

.org   ERDYaddr            ; EEPROM Ready
      reti

.org   ACIaddr               ; Analog Comparator
      reti

.org   TWIaddr               ; Two-wire Serial Interface
      reti

.org   INT2addr            ; External Interrupt Request 2
      reti

.org   OC0addr               ; TimerCounter0 Compare Match
      rjmp   Sys_Timer_Comp

.org   SPMRaddr            ; Store Program Memory Read
      reti
;----------
.org   INT_VECTORS_SIZE      ; size in words
;===================

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 04:44:30

BOB51 писал(а):...Тогда чтобы получить 0,1 секунды...
Замечу, стартёру нужно было
ultexplorer писал(а):По идее, он должен мигать с частотой ... 0,1 Гц.

Demiurg
Код:
// outi   ST_OCR, (XTAL/64/1000)
 outi   ST_OCR, (XTAL/64/1000-1)
так будет гораздо (на 4мкс) точнее.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 06:56:17

akl писал(а):так будет гораздо (на 4мкс) точнее.

Я в симуляторе AVR-Studio проверял. А вы?

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 06:59:22

А минус 1 это из дш

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 08:32:20

Я в симуляторе AVR-Studio проверял. А вы?
Разумеется проверял.
Изображение
с -1, т.е. на 64 такта короче
Изображение
Вложения
test_1ms_ds.PNG
вторая и все последующие милисекунды
(14.14 KiB) Скачиваний: 347
test_1ms_demiurg.PNG
вторая и все последующие милисекунды
(13.12 KiB) Скачиваний: 487

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 08:55:51

Так 0,1ГЦ это ж не мигание, а непрерывное горение 10 секунд с паузой в 10 секунд...
:dont_know:

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 09:08:22

BOB51 писал(а):Так 0,1ГЦ это ж не мигание, а непрерывное горение 10 секунд с паузой в 10 секунд...
Нет, не 0,1Гц, а 0,05Гц. Пытаюсь донести, что 0,1 секунды это не 0,1Гц. Извините.

Re: Расчет частоты таймера. Где-то ошибка в логике.

Чт янв 11, 2018 22:04:22

Так 0,1ГЦ это ж не мигание, а непрерывное горение 10 секунд с паузой в 10 секунд...
:dont_know:

Да. Так легче на глаз проверить, как работает собранная схема.

Я поправил код, нашел ошибки, поменял brcc на brne, заменил neg на 0-250, немного усложнил код.
Теперь 3 светодиода. Один мигает с частотой 1 Гц, второй 2 Гц, Третий 4 Гц. Собрал, все работает.

Занимаюсь дальнейшим изучением таймеров в силу свободного времени :))

Вот код на 3 светодиода:
Код:
.include "m16def.inc"
.def rK_div = r16
.def count  = r17
.def Temp1  = r18
.def Temp2  = r19
.equ K_div = 250
.equ t_counter =  4000
.equ t_counter2 = 2000
.equ t_counter3 = 1000
;----------
.macro mouti
      ldi r20, @1
     out @0, r20
.endm
;----------
.dseg
         ram_counter:  .byte 2
       ram_counter2: .byte 2
       ram_counter3: .byte 2       
.cseg
         
.ORG $000        ; (RESET)
         RJMP   RESET
         .ORG $002
         RETI             ; (INT0) External Interrupt Request 0
         .ORG $004
         RETI             ; (INT1) External Interrupt Request 1
         .ORG $006
         RETI            ; (TIMER2 COMP) Timer/Counter2 Compare Match
         .ORG $008
         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
         .ORG $00A
         RETI            ; (TIMER1 CAPT) Timer/Counter1 Capture Event
         .ORG $00C
         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
         .ORG $00E
         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
         .ORG $010
         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow
         .ORG $012
         RJMP timer0ovf  ; (TIMER0 OVF) Timer/Counter0 Overflow
         .ORG $014
         RETI             ; (SPI,STC) Serial Transfer Complete
         .ORG $016
         RETI            ; (USART,RXC) USART, Rx Complete
         .ORG $018
         RETI             ; (USART,UDRE) USART Data Register Empty
         .ORG $01A
         RETI             ; (USART,TXC) USART, Tx Complete
         .ORG $01C
         RETI            ; (ADC) ADC Conversion Complete
         .ORG $01E
         RETI             ; (EE_RDY) EEPROM Ready
         .ORG $020
         RETI             ; (ANA_COMP) Analog Comparator
         .ORG $022
         RETI             ; (TWI) 2-wire Serial Interface
         .ORG $024
         RETI             ; (INT2) External Interrupt Request 2
         .ORG $026
         RETI             ; (TIMER0 COMP) Timer/Counter0 Compare Match
         .ORG $028
         RETI             ; (SPM_RDY) Store Program Memory Ready

       .ORG   INT_VECTORS_SIZE         ; Êîíåö òàáëèöû ïðåðûâàíèé

; Interrupts ==========
timer0ovf:
           push Temp1
         in   Temp1, SREG
         cli
         push Temp1
         push Temp2
           
         call dec_proc
         call dec_proc2
           call dec_proc3

           pop Temp2
         pop Temp1
         out SREG, Temp1
         pop Temp1
         
           RETI
;----------
       
   
        rjmp reset
RESET: 
RAM_flash:
            ldi zl, low(sram_start)
            ldi zh,high(sram_start)
            clr r16
flash:      st  z+, r16
            cpi zh,high(ramend+1)
          brne flash

          cpi zl,low (ramend+1)
          brne flash
          clr zl
          clr zh

          ldi zl, 30
            clr zh
            dec zl
            st  z, zh
          brne PC-2
         nop
         clr Temp1
            out TCNT0,Temp1
;----------
            ldi Temp1, low(ramend)
         out spl, Temp1
         ldi Temp1,high(ramend)
         out sph, Temp1
;----------
            mouti DDRD, 0b00000111
         mouti PortD,0b11111111
         
;----------
; ram_counter-----------------------------------
ram_var:   
            ldi Temp1, low(t_counter)
         sts ram_counter,   Temp1
         ldi Temp1,high(t_counter)
         sts ram_counter+1, Temp1

            ldi Temp1, low(t_counter2)
         sts ram_counter2,   Temp1
         ldi Temp1,high(t_counter2)
         sts ram_counter2+1, Temp1

         ldi Temp1, low(t_counter3)
         sts ram_counter3,   Temp1
         ldi Temp1,high(t_counter3)
         sts ram_counter3+1, Temp1
;----------
;----------       
       
          //ldi rK_div, K_div
          //neg rK_div
         ldi rK_div,0-250
          out TCNT0,rK_div
          mouti TCCR0,1<<CS01 
          mouti TIMSK,1<<TOIE0
          mouti SREG, $80     
      
;----------
main:       
             rjmp main       

;----------

;----------
dec_proc:   lds Temp1, ram_counter
            lds Temp2, ram_counter+1

dec_var:    subi Temp1,1
            sbci Temp2,0
         //brcc no_ziro
         brne no_ziro
         rjmp dec_end

no_ziro:    sts ram_counter,   Temp1
         sts ram_counter+1, Temp2
         rjmp end_proc

dec_end:   
; ----------
            //cli
            ldi Temp1, low(t_counter)
            ldi Temp2,high(t_counter)

         sts ram_counter,   Temp1
         sts ram_counter+1, Temp2

            in  Temp1, PortD
         ldi Temp2,0b00000001
         eor Temp1,Temp2     
         out PortD, Temp1
;----------
            //sei
end_proc:   ret      
;;----------

;----------
dec_proc2:  lds Temp1, ram_counter2
            lds Temp2, ram_counter2+1

dec_var2:   subi Temp1,1
            sbci Temp2,0
         //brcc no_ziro
         brne no_ziro2
         rjmp dec_end2

no_ziro2:   sts ram_counter2,   Temp1
         sts ram_counter2+1, Temp2
         rjmp end_proc2

dec_end2:   
; PortD ----------
            //cli
            ldi Temp1, low(t_counter2)
            ldi Temp2,high(t_counter2)

         sts ram_counter2,   Temp1
         sts ram_counter2+1, Temp2

            in  Temp1, PortD
         ldi Temp2,0b00000010 ; ìàñêà
         eor Temp1,Temp2      ;èíâåðòèðóþ
         out PortD, Temp1
;----------
            //sei
end_proc2:   ret      
;;----------                   

;----------
dec_proc3:  lds Temp1, ram_counter3
            lds Temp2, ram_counter3+1

dec_var3:   subi Temp1,1
            sbci Temp2,0
         //brcc no_ziro
         brne no_ziro3
         rjmp dec_end3

no_ziro3:   sts ram_counter3,   Temp1
         sts ram_counter3+1, Temp2
         rjmp end_proc3

dec_end3:   
;PortD ----------
            //cli
            ldi Temp1, low(t_counter3)
            ldi Temp2,high(t_counter3)

         sts ram_counter3,   Temp1
         sts ram_counter3+1, Temp2

            in  Temp1, PortD
         ldi Temp2,0b00000100
         eor Temp1,Temp2     
         out PortD, Temp1
;----------
            //sei
end_proc3:   ret      
;;----------                   

Ответить