.include "D:\pribor\2313def.inc"


.def	Temp1=R16
	.def	Temp2=R17
	.def	Temp3=R18
	.def	Temp4=R19
	.def	Temp=R20
	.def	DecCount=R21
	.def	Scd=R22
	.def	Min=R23
	.def	Hour=R24
	.def	Status=R25


.dseg

Digit:	.byte 4
Line:	.byte 4
Key:	.byte 1




;******************************************************************************
.macro	stsi		;save_immediate <SRAM_cell>,<k>
	ldi Temp,@1
	sts @0,Temp
.endmacro

.macro	outi
	ldi Temp,@1
	out @0,Temp
.endmacro

.macro	rdm
	ldi ZH,High(@0*2)
	ldi ZL,Low(@0*2)
	add ZL,Temp1
	adc ZH,Temp2
	lpm
	mov Temp3,r0
.endmacro
;******************************************************************************

.cseg
.org 0

              rjmp RESET    ; Reset Handler
              rjmp EXT_INT0 ; IRQ0 Handler
              rjmp EXT_INT1 ; IRQ1 Handler
              rjmp TIM_CAPT1 ; Timer1 Capture Handler
              rjmp TIM_COMP1 ; Timer1 Compare Handler
              rjmp TIM_OVF1 ; Timer1 Overflow Handler
              rjmp TIM_OVF0 ; Timer0 Overflow Handler
              rjmp UART_RXC ; UART RX Complete Handler
              rjmp UART_DRE ; UDR Empty Handler
              rjmp UART_TXC ; UART TX Complete Handler
              rjmp ANA_COMP ; Analog Comparator Handler



EXT_INT0  :	ret
EXT_INT1  :	ret
TIM_CAPT1 :	ret
TIM_OVF0  :	ret
TIM_OVF1  :   ret
UART_RXC  :   ret
UART_DRE  :   ret
UART_TXC  :   ret
ANA_COMP  :   ret
TIM_COMP1 :   ret



reset:        ldi Temp1,RamEnd	;set stack
              out SPL,Temp1

              cli

              ldi Temp,0b11111111
	out ddrb,Temp

              ldi Temp,0b00001111
              out ddrd,Temp


              stsi Digit  ,0
              stsi Digit+1,0
              stsi Digit+2,0
              stsi Digit+3,0


;*********************************************************
;MAIN CYCLE
;*********************************************************

IndicCycle:   rcall Display
              rcall KeyRead
	rcall Keyboard

              rjmp IndicCycle

;*********************************************************
;*********************************************************
Display:
              lds Temp1,Digit
              ldi Temp,0b00001110
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              in Temp,PinD
              sts Line,Temp
              rcall Delay1

              lds Temp1,Digit+1
              ldi Temp,0b00001101
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              in Temp,PinD
              sts Line+1,Temp
              rcall Delay1

              lds Temp1,Digit+2
              ldi Temp,0b00001011
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              in Temp,PinD
              sts Line+2,Temp
              rcall Delay1

              lds Temp1,Digit+3
              ldi Temp,0b00000111
              out PortD,Temp
              rcall Decoder
              out PortB,Temp1
              in Temp,PinD
              sts Line+3,Temp
              rcall Delay1

              ret


;*********************************************************
Decoder:

              ldi ZL,Low(DcMatrix*2)
              ldi ZH,High(DcMatrix*2)

              ldi Temp2,0
              add ZL,Temp1
              adc ZH,Temp2

              lpm
              mov Temp1,r0
              ret

DcMatrix:
              ;     hgfedcba   hgfedcba
              .db 0b00111111,0b00000110	;0,1
              .db 0b01011011,0b01001111	;2,3
              .db 0b01100110,0b01101101	;4,5
              .db 0b01111101,0b00000111	;6,7
              .db 0b01111111,0b01101111	;8,9
              .db 0b01110111,0b01111100	;A,B
              .db 0b00111001,0b01011110	;C,D
              .db 0b01111001,0b01110001	;E,F
              .db 0b01111111,0b01111111

;*********************************************************

Delay1:
              push Temp1
              push Temp2


              ldi Temp1,0
              ldi Temp2,50

d11:          dec Temp1
              brne d11
              dec Temp2
              brne d11

              pop Temp2
              pop Temp1

              ret

;*********************************************************
;*********************************************************
KeyRead:
;проверяет нажатие клавиши в клавиатуре
;возвращает номер клавиши в случае нажатия
;иначе возвращает -1 (255)
;также -1 возвращается в случае, если в прошлый раз была нажате та же
;кнопка
;возвращаемое значение - переменная Key

;блок проверки строки (всего их 4)
              lds Temp,Line         ;читаем состояние строки
              rcall KeyTest         ;вызываем программу проверки
                                    ;программа возвращает
                                    ;номер кнопки: 0..2
                                    ;или -1 - если нет нажатых кнопок

              ldi Temp,0            ;загружаем код текущей строки
              cpi Temp1,255         ;если ничего не нажато - идем дальше
              brne SetKey           ;иначе - переходим на обработку
;конец 0-го блока

              lds Temp,Line+1
              rcall KeyTest
              ldi Temp,3
              cpi Temp1,255
              brne SetKey

              lds Temp,Line+2
              rcall KeyTest
              ldi Temp,6
              cpi Temp1,255
              brne SetKey

              lds Temp,Line+3
              rcall KeyTest
              ldi Temp,9
              cpi Temp1,255
              brne SetKey

              ldi Temp,0


SetKey:       add Temp,Temp1        ;прибавляем номер кнопки
                                    ;к коду строчки
              lds Temp1,Key         ;грузим код кнопки,
                                    ;прочитанный в прошлый раз
              andi Temp1,0b00001111 ;"чистим" его по маске
              cp Temp,Temp1         ;если в прошлый раз
              brne EndKeyRead       ;была нажата не та же кнопка
                                    ;выходим

              ori Temp,0b10000000   ;иначе - пишем флажок "повтор"

EndKeyRead:   sts Key,Temp          ;сохраняем код кнопки в ОЗУ

              ret                   ;выходим


;*********************************************************

KeyTest:      andi Temp,0b01110000  ;обрезаем по маске
              ldi Temp1,0b01110000
              eor Temp,Temp1        ;инвертируем биты по маске
              breq NoButtons        ;если все нули (нет нажатых)
                                    ;переходим по метке

              ldi Temp1,0           ;инициализируем счетчик

              cpi Temp,0b00010000   ;проверяем 0-ю кнопку
              breq EndKeyTest       ;нажато - выход
              inc Temp1             ;иначе - инкремент счетчика

              cpi Temp,0b00100000   ;проверка 2 кнопки
              breq EndKeyTest
              inc Temp1

              cpi Temp,0b01000000   ;проверка 3 кнопки
              breq EndKeyTest

NoButtons:    ldi Temp1,255         ;если ничего не нажато -
                                    ;возвращаем 255

EndKeyTest:   ret

;*********************************************************
;*********************************************************
Keyboard:
;запускает выполнение операции, закрепленной за кнопкой


              lds Temp,Key          ;загружаем переменную Key
              mov Temp1,Temp        ;проверяем на наличие флажка
              andi Temp1,0b10000000 ;"повтор" или -1
              brne EndKeyboard      ;если повтор или -1 - выходим


              ldi ZH,High(KeysLUT*2);загружаем таблицу
              ldi ZL,Low (KeysLUT*2);истинности
                                    ;(клавиша -> значение)

              ldi Temp1,0           ;смещаемся на номер клавиши
              add ZL,Temp
              adc ZH,Temp1

              lpm                   ;загружаем значение элемента
              mov Temp,R0

              lds Temp1,Digit+2      ;сдвигаем разряды индикатора
              sts Digit+3,Temp1      ;на один влево
              lds Temp1,Digit+1
              sts Digit+2,Temp1
              lds Temp1,Digit
              sts Digit+1,Temp1

              sts Digit,Temp        ;пишем в млад. разряд
                                    ;индикатора текущее значение



EndKeyboard:  ret

;*********************************************************
KeysLUT:
.db  1,2,3,4,5,6,7,8,9,10,0,11      ;массив
;(таблица истинности клавиатуры)
