;######################################################################
; Демонстрашка 
; Регулирование частоты ШИМ изменением верхней границы счета таймера
; Для ШИМ спользован 8-разрядный таймер0, выход - D5 (OC0B)
; Период ШИМ меняется туда-сюда между значениями c_Tmin и c_Tmax.
; Изменение происходит в прерывании по совпаденю таймера1.
; Для простоты ширина импульса постоянна.
;######################################################################
; AVR-Studio 4.13


.include "tn2313def.inc"

;######################################################################
;----- обзовем регистры и зададим константы ------------------
;######################################################################

.def flags	=r16	;флаги
 .equ f_up	=0	;флаг увеличения/уменьшения периода (1/0)
.def tmpa	=r17	;всяко-разно
.def tmpt	=r19	;только для обслуживания прерываний

;----- константы ------------------------------------------------------
.equ c_impuls	=20	;ширина импульса
.equ c_Tmax	=255	;максимальный период ШИМ
.equ c_Tmin	=25	;минимальный период ШИМ

;----------------------------------------------------------------------
;######################################################################



.cseg
;######################################################################
;-----  вектора прерываний --------------------------------------------
;######################################################################

.org 0
		rjmp	_reset
.org OC1Aaddr
		rjmp	_oc1a
.org INT_VECTORS_SIZE

;######################################################################



;######################################################################
;----- инициализация --------------------------------------------------
;######################################################################

_reset:	
;		ldi	tmpa,hi(RAMEND)		;установка указателя стека (старший)
;		out	SPH,tmpa
		ldi	tmpa,low(RAMEND)	;установка указателя стека (младший)
		out	SPL,tmpa

		ldi	tmpa,0b00100000
		out	DDRD,tmpa		;5-ый бит порта D(OC0B) - на вывод
		clr	flags			;очищаем флаги

		ldi	tmpa,(1<<com0b1)|(1<<wgm01)|(1<<wgm00)
		out	TCCR0A,tmpa
		ldi	tmpa,(1<<wgm02)|1
		out	TCCR0B,tmpa		;запуск Т0 с к=1, режим FastPWM, TOP=OCR0A

		ldi	tmpa,c_Tmax
		out	OCR0A,tmpa		;грузим максимальное значение периода ШИМ

		ldi	tmpa,c_impuls
		out	OCR0B,tmpa		;в регистр сравнения грузим период импульса

		ldi	tmpa,(1<<ocie1a)
		out	TIMSK,tmpa		;разрешаем прерывания по совпадению таймера1 (канал А)

		ldi	tmpa,1
		out	OCR1AH,tmpa		;грузим в старший разряд регистра совпадения 1
		clr	tmpa
		out	OCR1AL,tmpa		;грузим в младший разряд регистра совпадения 0 (итого 256)

		ldi	tmpa,(1<<wgm12)|2	
		out	TCCR1B,tmpa		;запуск Т1 с к=1/8, режим обнуления по совпадению

		sei				;разрешаем прерывания глобально

;######################################################################



;######################################################################
;----- основной цикл --------------------------------------------------
;######################################################################
_loop:
		nop			;здесь  может быть
		nop			;основная программа
		rjmp	_loop

;######################################################################


;######################################################################
;***** обработка прерываний *******************************************
;######################################################################

;----- обработка совпадения таймера1 (канал А)--------------------------------
_oc1a:		in	tmpt,SREG
		push	tmpt		;сохранили SREG

		in	tmpt,OCR0A	;считали текущее значение TOP
		sbrc	flags,f_up	;развилка на увеличение/уменьшение
		rjmp	_up

_down:		dec	tmpt		;уменьшили на 1
		cpi	tmpt,c_Tmin+1	;сравнили с максимумом
		brcc	_oc1a_end	;если не достигли, то уходим на метку
		sbr	flags,(1<<f_up)	;ставим флаг направления
		rjmp	_oc1a_end	;уходим на метку

_up:		inc	tmpt		;увеличили на 1
		cpi	tmpt,c_Tmax	;сравнили с минимумом
		brcs	_oc1a_end	;если не достигли, то уходим на метку
		cbr	flags,(1<<f_up)	;сбрасываем флаг направления

_oc1a_end:	out	OCR0A,tmpt	;загрузили новое значение TOP
		pop	tmpt
		out	SREG,tmpt	;восстановили SREG
		reti			;выход из прерывания
;----------------------------------------------------------------------
;######################################################################
