
.def	Temp=R16
.def	Temp1=R17
.def	Temp2=R18
.def	Temp3=R19
.def	Temp4=R20
.def	Temp5=R21
.def	Temp6=R22
.def	Temp7=R23
.def	Temp8=R24
.def	Temp9=R25


.dseg			;оперативка

key_buff: .byte 5	; зарезервируем 5 байт в ОЗУ


;******************************************************************************

.EQU ImpLen=0xCE4 			; длина импульса
.EQU OneLen=0xCE4 			; длина паузы для единицы
.EQU NulLen=0x19C8			; длина паузы для нуля

;******************************************************************************

.cseg

.org 0


						rjmp RESET			; External Pin, Power-on Reset, Brown-out Reset, and Watchdog Reset

.org   OC1Aaddr				; (=0x0004) Timer/Counter1 Compare Match A
						rjmp OCR1A_COMP

.org INT_VECTORS_SIZE


;******************************************************************************
;старт
;******************************************************************************

reset:					; включение микроконтроллера

						cli			  			; глобальный запрет на прерывания


						ldi Temp,low(RamEnd)	; инициализации стека	
						out SPL,Temp			;


						ldi Temp,0b00001000		; настроили порт "В" (0-ввод, 1-вывод)
						out DDRB,Temp			; 0000х000 - "вывод" на передатчик (PB3- 15 ножка)
												; хххх0000 - "ввод" для чтения строк клавиатуры
												 
						ldi Temp,0b00001111		; настраиваем порт "D" (0-ввод, 1-вывод)
						out DDRD,Temp 			; 0000хххх - на вывод столбцов клавы
					
						ldi Temp,0b00000000		; установили тактовый сигнал = CK 0
						out TCCR1B,Temp			; таймер выключен!!!

						sei						; глобальное разрешение прерываний
        



;*******************************************************************************
; главный цикл
;*******************************************************************************


Main_cicle:
						rcall keyboardread		; вызов подпрограммы чтения клавиатуры

						rcall certain_buttons_keyboard	; вызов подпрограммы проверки нажатия
	
						rjmp Main_cicle				; циклимся



;*******************************************************************************
; Чтение клавы и запись данных в ОЗУ
;*******************************************************************************

keyboardread:			; метка - опрос клавиатуры
          
						ldi Temp,5			; количество столбцов клавы = пять
         
						ldi Temp1,0b00000001		; первый столбец

          				; загружаем адрес метки (key_buff) находящейся в ОЗУ в регистровую пару X
						ldi XL,	low(key_buff)		; младший байт адреса
						ldi XH,	high(key_buff)		; старший байт адреса

keyboardread_loop:			; цикл опроса

						out PortD,	Temp1			; выводим в порт "Д" значение "Temp1" для выбора столбца клавиатуры
						in Temp2,	PinB			; прочитали состояние столбца
         
						st X+,		Temp2			; сохраним в ОЗУ состояние столбца клавы, 
 					; адрес в регстровой паре "X" автоматом увеличится на 1

						lsl Temp1			; сдвинули единичку выбора столбца клавиатуры на 1
 					; позицию влево

						dec temp			; уменьшим счетчик
						brne keyboardread_loop		; если не все просканировали, то циклимся

						ret

       
;******************************************************************************************
;проверка нажатия клавиатуры
;******************************************************************************************

certain_buttons_keyboard:
		

						ldi temp1,5			; УСТАНОВИМ СЧЕТЧИК столбцов клавы	

	                  			; загружаем адрес метки (key_buff) находящейся в ОЗУ в регистровую пару "Z"
						ldi ZL,low (key_buff)		; младший байт адреса
						ldi ZH,high(key_buff)		; старший байт адреса 

Certain_button:

						ld Temp,Z+			; загрузим данные в регистр из ОЗУ по адресу из регистровой пары "Z", 
					; и после этого адресс в регистровой паре автоматически увеличится на еденицу


						cpi Temp,0b00000000		; проверяем, нажата ли какая ни будь кнопка?
						brne inform				; если нажата то переходим на метку "inform"


						dec temp1			; уменьшим счетчик
						brne Certain_button		; если не все столбцы, то циклимся

metka:


						ret

;***********************************************************************************************
;вывод информации о состоянии клавиатуры в порт "Б" 
;***********************************************************************************************

inform:


							; включаем таймер
						ldi Temp,(1<<COM1A0)				; переключать ножку "OC1A" по совпадению (PB3- 15 ножка)
						out TCCR1A,Temp					; *1


						LDI R19, 2				; зададим фиксированную длительность импульса
						OUT OCR1AH, R19			; и выведем ее в порт сравнения
						LDI R19, 0   
						OUT OCR1AL ,R19       

						ldi Temp,0					; обнуление таймера 
						out TCNT1H,Temp
						out TCNT1L,Temp

						ldi Temp,(1<<wgm12)|(1<<cs10)			; подключили режим "CTC" (вместе с *1) 
						out TCCR1B,Temp					; и установили тактовый сигнал = CK 1:1  ++++++++++++++++++++++++++++++++++++++
							; таймер начал считать!!!

						ldi Temp,(1<<OCIE1A)	; разрешить прерывание компаратора 
						out TIMSK,Temp
	

						ldi	R22, 0				; фаза передачи

loop_wait_transmitt:								; цикл ожидания завершения передачи
						cpi R22 , 7
						brne    loop_wait_transmitt

					    ret	


;*******************************************************************************
;обработка прерывания
;*******************************************************************************

OCR1A_COMP:
					; первоначальное значение R22 - 0
					; таким образом сначала будет выполнена инициализации передачи

					; проверяем фазу работы прерывания

						in temp , SREG
						push	temp


						CPI R22, 1
						BREQ transmitt_byte			; фаза передачи байта

						CPI R22, 2
						BREQ transmitt_bite_imp		; фаза передачи импульса бита в байте

						CPI R22, 3
						BREQ transmitt_bite_pause	; фаза передачи паузы бита в байте

						CPI R22, 4
						BREQ transmitt_imp_chetn	; фаза передачи импульса бита четности

						CPI R22, 5
						BREQ transmitt_pausa_chetn	; фаза передачи паузы бита четности

						CPI R22, 6
						BREQ transmitt_complete		; передача завершена, выключение прерываний


;****************************************************************************************************************

					; инициализация передачи, (при R22=0)

						ldi R21,0			; это будет счетчик единичек в передаче (четность)

						ldi yl,low(key_buff)		; зададим адрес начала массива прочитанных кнопок
						ldi yh,high(key_buff)

						ldi R17,5			; количество байт для передачи


transmitt_byte:				; фаза начала передачи - передача байта

 						ld temp,y+			; прочитаем байт для передачи, увеличим на единицу адрес в "Y" 

						ldi r18,8			; количество бит в байте для передачи


transmitt_bite_imp:			; фаза передачи импульса в передаваемом бите


						LDI R19 ,high(ImpLen)		; зададим фиксированную длительность импульса
						OUT OCR1AH, R19			; и выведем ее в порт сравнения
						LDI R19,low(ImpLen)   
						OUT OCR1AL ,R19       

						LDI  R22, 3			; в следующий раз передаем паузу

int_reti:
						pop		temp
						out SREG	, temp
						RETI				; точка выхода из прерывания


;**********************************************************************************************************************

transmitt_bite_pause:			; фаза передачи паузы в передаваемом бите

					; здесь кодируем импульс для бита


						LDI XL,low(Nullen)		; длительность для передачи нуля
						LDI XH,high(Nullen)

						ROL temp			; двигаем байт влево (циклический сдвиг влево)
						BRCC send_nullen		; если "С"=0 то записываем нулевую длительность

	
						LDI XL,low(onelen)		; длительность для передачи единицы
						LDI XH,high(onelen)

						INC R21				; передаем единицу - увеличим счетчик единичек (четность) 

send_nullen:

						OUT OCR1AH,XH			; установим длительность
						OUT OCR1AH,XL         
               
						LDI R22,2			; в следующий раз передадим импульс бита

						dec R18				; уменьшим счетчик бит на передачу
						brne int_reti			; если это непоследний бит в байте - то выход из прерывания

						LDI R22,1			; в следующий раз передадим новый байт

						dec R17				; уменьшим счетчик Байт для передачи
						brne int_reti			; если это не последний байт в массиве - то выход из прерывания
                   
						LDI R22,4			; в следующий раз передадим импульс бита четности

						RJMP int_reti			; выход из прерывания

;*********************************************************************************************************************                   


transmitt_imp_chetn:			; передача импульса бита четности

	
						LDI R19 ,high(ImpLen)		; зададим фиксированную длительность импульса
						OUT OCR1AH, R19			; и выведем ее в порт сравнения
						LDI R19,low(ImpLen)   
						OUT OCR1AL,R19       


						LDI R22,5			; в следующий раз передаем паузу бита четности

						rjmp int_reti			; выход из прерывания

;**********************************************************************************************************************


transmitt_pausa_chetn:			; передача паузы импульса четности

						; здесь кодируем длительность паузы для бита четности

						LDI XL,low(Nullen)		; длительность для передачи нуля
						LDI XH,high(Nullen)

						COM R21				; Побитная инверсия

						ROR R21				; Циклический сдвиг вправо

						BRCC send_chetn 		; если "С"=0 то записываем нулевую длительность

						LDI XL,low(onelen)		; длительность для передачи единицы
						LDI XH,high(onelen)

send_chetn:

						OUT OCR1AH,XH			; установим длительность
						OUT OCR1AH,XL         

						LDI R22,6			; ОТКЛЮЧЕНИЕ ПРЕРЫВАНИЯ
						rjmp int_reti

;*************************************************************************************************************************

transmitt_complete:		; КОД ДЛЯ ОТКЛЮЧЕНИЯ ПРЕРЫВАНИЙ 

						ldi Temp,0b00000000			; установили тактовый сигнал = CK 0  ++++++++++++++++++++++++++++++++++++++++++++++++++++
						out TCCR1B,Temp				; таймер выключен!!!
	
						LDI R22, 7					; Признак окончания передачи
						rjmp int_reti				

;***********************************************************************************************
