; ПРОГРАММА - счетчик электронный для счета импульсов
;
; Кварц - 4 МГц
;
.include "tn2313def.inc"
;======================================================
#define F_CPU (4000000)
;Здесь идёт определение тактовой частоты. Нужно для 
;библиотеки задержек,используемой в этой либе. 
;Частота в Герцах.
;======================================================
;***** Регистровые переменные подпрограммы

;* Примечания: 1. Переменные fASCIIL и tASCII0 должны размещаться в
;*                одном  регистре.
;*             2. Переменные cnt16a и tASCII1 должны размещаться в одном
;*                регистре.
;*             3. Переменные, определенные в младших регистрах могут быть
;*                также определены и в старших регистрах.

.def    fASCIIL		=r23
.def    tASCII0		=r11
.def    fASCIIH		=r22
.def    tASCII2		=r13
.def    tASCII3		=r14
.def    tASCII4		=r15
.def    tASCII1		=r19
.def    cnt16a		=r19
.def    tmp16a		=r17
.def    tmp16b		=r18
.def    temp1		=r16
.def    flags		= r20   ; state flags   
.equ	   EventForward   = 0    ;=1 если надо обслужить прямой счет   
.equ	   EventRevers    = 1    ;=1 если надо обслужить обратный счет
.def    tm     = r21

.def	CountLow	=r24
.def	CountHigh	=r25


.CSEG
.org 0
	rjmp START ; на основную программу.
 .org INT0addr
	rjmp IntForward ;Oбработка прерывания по INT0 (инкремент)
.org INT1addr
	rjmp IntBack ;Oбработка прерывания по INT1 (декремент)


;*************************************************************************
IntForward:;(ПРИБАВИТ)
	sbr	flags, (1<<EventForward)
	reti
;*************************************************************************
IntBack:;(ОТНЯТЬ)
	sbr	flags,(1<<EventRevers)
	reti
;*************************************************************************

START:
;	ldi	temp,$0F
;	out	WDTCR,temp	;Включение сторожевого таймера 1,9 секунды.

;======================================================
	ldi	Temp1,RamEnd		; установка указателя стека
	out	SPL,Temp1
	clr	flags		;сбросить флаги
	clr	CountLow	 ;сбросить двоичный счетчи
	clr	CountHigh	 ;
;------------------------------------------------------

	ldi	temp1,0b00000000
	out	DDRD,temp1	;Направление данных PortD (1)-выходы
	ldi	temp1,0b11111111
	out	PORTD,temp1
	ldi	temp1,0b11111111
	out	DDRB,temp1	;Направление данных порта B на вывод,В.1,2 -как входы
	out	PORTB,temp1	;Выдать данные на порт В

	ldi temp1,(1<<ISC01|1<<ISC11);устанавливаем прерывания INT0 и INT1 по спадающему фронту 
	out MCUCR,temp1
 
;	rcall lcd_init;Инициализация дисплея.
	nop
	nop

	ldi temp1,(1<<INT1)+(1<<INT0);разрешаем прерывания INT1,INT0
	out GIMSK,temp1
	sei			;разрешаем прерывания   
;	rcall	LongDelay	;программная задержка при включении
;	wdr			;сбросить стор. таймер

;основной цикл
Inf:
	sbrc	flags, EventForward	;переход если установлен EventForward   
	rcall	Forward			;   
	sbrc	flags, EventRevers	 ;соотв. для EventRevers   
	rcall	Back			 ;    
	rjmp	Inf			;бесконечный цикл

;**********************************************************************
Forward:
	cbr	flags, (1<<EventForward);сбросить флаг,обработали событие
	adiw	CountHigh:CountLow,1	;инкремент 16-ти битного счетчика
	rcall	PrintASCII
	ret
;**********************************************************************
Back:
	cbr	flags, (1<<EventRevers)	;сбросить флаг,обработали событие
	sbiw	CountHigh:CountLow,1	;декремент 16-ти битного счетчика
	rcall	PrintASCII
	ret
;**********************************************************************


;**********************************************************************
PrintASCII:
	mov	fASCIIL,CountLow	;переслать счетчик в регистры 10-ой коррекции
	mov	fASCIIH,CountHigh	;

	rcall	bin2ASCII16	;десятичная коррекция
;преобразовать десятичный код в ASCII	
	ldi	temp1,0x30	;Смещение для ASCII кода
	add	tASCII4,temp1	 ;r15
	add	tASCII3,temp1	 ;r14
	add	tASCII2,temp1	 ;r13
	add	cnt16a, temp1	 ;r19
	add	fASCIIL,temp1	 ;r23

;вывод на lcd
	mov	temp1,tASCII4
;	rcall	LCD_WriteData
	mov	temp1,tASCII3
;	rcall	LCD_WriteData
	mov	temp1,tASCII2
;	rcall	LCD_WriteData
	mov	temp1,cnt16a
;	rcall	LCD_WriteData
	mov	temp1,fASCIIL
;	rcall	LCD_WriteData
	ret
;**********************************************************************


;*********************************************************************
;преобразование 16-битного двоичного значения в неупакованный BCD формат
;*********************************************************************
;* Количество слов кода            :22 + возврат
;* Количество циклов               :60/220 (Мин/Макс) + возврат
;* Использованные младшие регистры :5 (fASCIIL/tASCII0,fASCIIH,tASCII2,
;*                                     tASCII3,tASCII4)
;* Использованные старшие регистры :3 (cnt16a/tASCII1,tmp16a,tmp16b)
;*********************************************************************
bin2ASCII16:
;двоичный код должен быть в fASCIIL,fASCIIH (r11,r12). 
        ldi     tmp16a, low(10000)
        ldi     tmp16b, high(10000)
        rcall   bin2ASCII_digit
        mov     tASCII4, cnt16a
        ldi     tmp16a, low(1000)
        ldi     tmp16b, high(1000)
        rcall   bin2ASCII_digit
        mov     tASCII3, cnt16a
        ldi     tmp16a, low(100)
        ldi     tmp16b, high(100)
        rcall   bin2ASCII_digit
        mov     tASCII2, cnt16a
        ldi     tmp16a, low(10)
        ldi     tmp16b, high(10)
bin2ASCII_digit:
        ldi     cnt16a, -1
bin2ASCII_digit_loop:
        inc     cnt16a
        sub     fASCIIL, tmp16a
        sbc     fASCIIH, tmp16b
        brsh    bin2ASCII_digit_loop
        add     fASCIIL, tmp16a
        adc     fASCIIH, tmp16b
	ret
;Итог, число 0xffff преобразовалось в 65535 (десятичное) и лежит 
;в tASCII4(r15),tASCII3(14),tASCII2(r13),cnt16a(r16),fASCIIL(r11).
; Заняло 162 такта. Все работает.
;**********************************************************************






;.include file "C:\AVR\WH4\hd44780.asm"
; Подключение библиотеки для
                      ; работы с дисплеем.

