Расчет частоты таймера. Где-то ошибка в логике.
Добавлено: Вт янв 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 Герца…
Помогите разобраться.
Код привожу:
Он мигает, но не с той частотой…
Мигает где-то с частотой 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 подпрограммы------------------------------------------------------