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

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

Добавлено: Вт янв 09, 2018 01:29:51
ultexplorer
Народ, написал программу с таймером для мигания светодиодом.
Он мигает, но не с той частотой…
Мигает где-то с частотой 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
Reflector
[uquote="ultexplorer",url="/forum/viewtopic.php?p=3278196#p3278196"]Далее в регистр TCNT0 записываю 250 для круглого счета:
ldi r16, 250
neg r16 ;
out TCNT0, r16[/uquote]
Neg то тут что делает?

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

Добавлено: Вт янв 09, 2018 05:19:29
akl
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
Z_h_e
dec_var: subi Temp1,1
sbci Temp2,0
brcc no_ziro
rjmp dec_end
brne , я по памяти команду написал, давно на ассме ничего не делал. Ну т.е. нужно проверять флаг Z.

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

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

Добавлено: Вт янв 09, 2018 06:25:36
akl

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

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
ultexplorer
[uquote="Reflector",url="/forum/viewtopic.php?p=3278201#p3278201"][uquote="ultexplorer",url="/forum/viewtopic.php?p=3278196#p3278196"]Далее в регистр TCNT0 записываю 250 для круглого счета:
ldi r16, 250
neg r16 ;
out TCNT0, r16[/uquote]
Neg то тут что делает?[/uquote]
Это 256 - 250 = 6. С 6 начинается счет, так как таймер работает по переполнени. Т.е, чтобы таймер отсчитал 250 тиков, а затем сработало прерывание, необходимо. чтобы он начинал отсчет с 6.

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

Добавлено: Ср янв 10, 2018 14:24:34
Z_h_e
Освойте режим CTC, как указал akl, таймер будет считать от 0 до нужного значения и сам сбрасываться.

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

Добавлено: Ср янв 10, 2018 14:50:57
ultexplorer
[uquote="Z_h_e",url="/forum/viewtopic.php?p=3279368#p3279368"]Освойте режим CTC, как указал akl, таймер будет считать от 0 до нужного значения и сам сбрасываться.[/uquote]
Спасибо. Займусь этим.
В своем коде нашел ошибку.
Забыл поставить метку на выход из подпрограммы, если переменная все еще больше 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
Z_h_e
ultexplorer писал(а):Это 256 - 250 = 6
neg , это же не оператор препроцессора, а реальная команда, абсолютно избыточная.

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

ldi r16, 0-250
//neg r16 ;
out TCNT0, r16

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

Добавлено: Ср янв 10, 2018 15:05:43
ultexplorer
[uquote="Z_h_e",url="/forum/viewtopic.php?p=3279401#p3279401"]
ultexplorer писал(а):Это 256 - 250 = 6
neg , это же не оператор препроцессора, а реальная команда, абсолютно избыточная.

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

ldi r16, 0-250
//neg r16 ;
out TCNT0, r16
[/uquote]
Точно!
Не все в книгах верно...

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

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

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

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

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

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

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

Добавлено: Ср янв 10, 2018 21:21:48
Demiurg
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
akl
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
Demiurg
akl писал(а):так будет гораздо (на 4мкс) точнее.
Я в симуляторе AVR-Studio проверял. А вы?

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

Добавлено: Чт янв 11, 2018 06:59:22
Z_h_e
А минус 1 это из дш

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

Добавлено: Чт янв 11, 2018 08:32:20
akl
[uquote="Demiurg",url="/forum/viewtopic.php?p=3280071#p3280071"]Я в симуляторе AVR-Studio проверял. А вы?[/uquote]Разумеется проверял.
Изображение
с -1, т.е. на 64 такта короче
Изображение

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

Добавлено: Чт янв 11, 2018 08:55:51
BOB51
Так 0,1ГЦ это ж не мигание, а непрерывное горение 10 секунд с паузой в 10 секунд...
:dont_know:

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

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

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

Добавлено: Чт янв 11, 2018 22:04:22
ultexplorer
[uquote="BOB51",url="/forum/viewtopic.php?p=3280146#p3280146"]Так 0,1ГЦ это ж не мигание, а непрерывное горение 10 секунд с паузой в 10 секунд...
:dont_know:[/uquote]
Да. Так легче на глаз проверить, как работает собранная схема.

Я поправил код, нашел ошибки, поменял 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		 
;;------------------------------------------------------