.include "tn2313def.inc"
.list
.def drebL=r1 ;Буфер антидребезга младший байт
.def drebH=r2 ;Буфер антидребезга младший байт
.def temp=r16 ;Вспомогательный регистр
.def data=r17 ;Регистр передачи данных
.def flz=r18 ;Флаг задержки
.def count=r19 ;Регистр передачи данных
.def addre=r20 ;Указатель адреса в EEPROM
.def codL=r21 ;Временный буфер кода младший байт
.def codH=r22 ;Временный буфер кода старший байт
;------------------Определение констант---------------------
.equ bsize=60 ;Размер буфера для хранения кода
.equ kzad=3000 ;Константа,определяющая длительность защитной паузы
.equ kandr=20 ;Константа антидребезга
;------------------Резервирование ячеек памяти(SRAM)---------
.dseg ;Выбираем сегмент ОЗУ
.org 0x60 ;Устанавливаем адрес с которого начинается .dseg
bufr: .byte bsize ;Буфер для приема кода
;------------------Резервирование ячеек памяти(EEPROM)
.eseg ;Выбираем сегмент EEPROM
.org 0x08 ;Устанавливаем адрес с которого начинается .eseg
klen: .byte 1 ;Ячейка для хранения длины кода
bufe: .byte bsize ;Буфер для хранения кода
;------------------Начало программного кода--------------------
.cseg ;Выбор сегмента програмного кода
.org 0 ;Установка .cseg на 0
;---------------Переопределение векторов прерывания 19шт.-----------------
start: rjmp init ;Переход на начало программы.Прерывание по сбросу
reti ;Внешнее прерывание 0
reti ;Внешнее прерывание 1
reti ;Таймер/счётчик 1,захват
rjmp propr ;Таймер/счётчик 1,совпадение,канал А
rjmp propr ;Таймер/счётчик 1,прерывание по переполнению
reti ;Таймер/счётчик 0,прерывание по переполнению
reti ;Переполнение UART пирём завершён
reti ;Переполнение UART регистр данных пуст
reti ;Переполнение UART передача завершена
reti ;Прерывание по изменению на любом контакте
reti ;Переполнение по компаратору
reti ;Таймер/счётчик 1,совпадение,канал В
reti ;Таймер/счётчик 0,совпадение,канал В
reti ;Таймер/счётчик 0,совпадение,канал А
reti ;USI готовность к старту
reti ;USI Переполнение
reti ;EEPROM Готовность
reti ;Переполнение охранного таймера
;---------------Инициалазация регистров общего назначения--------------------
init: ldi temp,RAMEND;Выбор адреса вершины стека
out SPL,temp ;Запись его в регистр стека
ldi temp,0x18
out DDRB,temp
ldi temp,0xe7
out PORTB,temp
ldi temp,0x7f
out PORTD,temp
ldi temp,0
out DDRD,temp
ldi temp,0x80 ;Загружаем в R16 число 1000 0000 или 128
out acsr,temp ;Отключаем компаратор
;----------------Таймер инит------------------------------------------------
ldi temp,high(kzad)
out OCR1AH,temp
ldi temp,low(kzad)
out OCR1AL,temp
ldi temp,0x03 ;Выбор коэф.деления
out TCCR1B,temp
;---------------основная программа-------------------------------------------
main: ldi codL,0x7f ;Код для сравнения
ldi codH,0x07 ;Старший байт
m0: rcall incod ;Ввод и проверка кода клавиш
brne m0 ;Если хоть одна кнопка не нажата,продолжаем
m1: rcall incod ;Ввод и проверка кода клавиш
brne m1 ;Если не одна не нажата,продолжаем
m2: ldi ZH,high(bufr);Установка указателя на начало буфера
ldi ZL,low(bufr)
clr count ;Сброс счетчика байт
;----------------Цикл ввода кода---------------------------------------------
m3: cli ;Запрет всех прерываний
ldi data,1 ;Вызываем задержку первого типа
rcall wait ;К подпрограмме задержки
m5: rcall incod ;Ввод и проверка кода кнопок
st Z+,XL ;Записываем его в буфер
st Z+,XH
inc count ;Увеличение счетчика байтов
inc count
cpi count,bsize ;Проверяем,не конец ли буфера
brsh m7 ;Если конец завершаем ввод кода
mov codL,XL ;Записываем код как старый
mov codH,XH
ldi data,2 ;Вызываем задержку третьего типа
rcall wait
m6: rcall incod ;Ввод и проверка кода кнопок
brne m3 ;Если изменилось,записываем в буфер
cpi flz,1 ;Проверка окончания фазы ввода кода
brne m6
;-----------------Опрос состояния тумблера------------------------------------
m7: sbic PINB,7 ;Проверка состояния тумблера
rjmp m9 ;К процедуре проверки кода
;-----------------Процедура записи кода---------------------------------------
mov data,count ;Помещаем длину кода в data
ldi addre,klen ;Адрес в EEPROM для хранения длины кода
rcall eewr ;Записываем длину кода в EEPROM
ldi addre,bufe ;В регистр адреса начало буфера в EEPROM
ldi ZH,high(bufr);В регистровую пару Z записываем
ldi ZL,low(bufr) ;адрес начала буфера в ОЗУ
m8: ld data,Z+ ;Читаем очередной байт из ОЗУ
rcall eewr ;Записываем в длину кода EEPROM
dec count ;Декремент счетчика байтов
brne m8 ;Если не конец,продолжаем запись
rjmp m11 ;К процедуре открывания замка
;------------------Процедура проверки кода--------------------------------------
m9: ldi addre,klen ;Адрес хранения длины кода
rcall eerd ;Чтение длины кода из EEPROM
cp count,data ;Сравнение с новым значением
brne m13 ;Если не равны к началу
ldi addre,bufe
ldi ZH,high(bufr);В Z записываем адрес начала буфера в ОЗУ
ldi ZL,low(bufr)
m10: rcall eerd ;Читаем очередной байт из EEPROM
ld temp,Z+ ;Читаем очеоедний байт из ОЗУ
cp data,temp ;Сравниваем два байта разных кодов
brne m13 ;Если не равны переходим к началу
dec count ;Уменьшаем содержимое счётчика байтов
brne m10 ;Если конец,продолжаем проверку
;-----------------Процедура открывания замка-------------------------------------
m11: sbi PORTB,4 ;Команда "Открыть замок"
ldi data,3 ;Вызываем задержку третьего типа
rcall wait
cbi PORTB,4 ;Команда "Закрыть замок"
m13: rjmp main
;----------------Подпрограммы-------------------------------------------------
;----------------Ввод и проверка 2-ух байтов с клавиатуры---------------------
incod: push count
ldi XL,0 ;Обнуление регистровой пары X
ldi XH,0
ic1: ldi count,kandr;Константа антидребезга
mov drebL,XL ;Старое значение младший байт
mov drebH,XH ;Старое значение старший байт
ic2: in XL,PIND ;Вводим код(младший байт)
cbr XL,0x80 ;Накладываем маску
in XH,PINB ;Вводим код(старший байт)
cbr XH,0xF8 ;Накладываем маску
ic3: cp XL,drebL ;Сверяем младший байт
brne ic1 ;Если не равен,начинаем с начала
cp XH,drebH
brne ic1
ic4: dec count ;Уменьшение счетчика антидребезга
brne ic2 ;Если еще не конец,продолжаем
cp XL,codL ;Сравнение с временным буфером
brne ic5 ;Если не равно,заканчиваем сравнение
cp XH,codH ;Сравниваем старшие байты
ic5: pop count
ret
;--------------------Подпрограмма задержки-------------------------------
wait: cpi data,1 ;Проверяем код задержки
brne w1
ldi temp,0x40 ;Разрешаем прерывание по совпадению
rjmp w2
w1: ldi temp,0x80 ;Разрешаем прерывание по переполнению
w2: out TIMSK,temp ;Записываем маску
clr temp
out TCNT1H,temp;Обнуляем таймер
out TCNT1L,temp
ldi flz,0 ;Cбрасываем флаг задержки
sei ;Разрешаем прерывание
cpi data,2 ;Если это задержка второго типа
breq w4 ;Переходим к концу подпрограммы
w3: cpi flz,1 ;Ожидаем окончания задержки
brne w3
cli ;Запрещаем прерывание
w4: ret
;---------------------Запись байта в ячейку EEPROM--------------------
eewr: cli ;Запрет прерываний
sbic EECR,EEWE ;Проверяем готовность EEPROM
rjmp eewr ;Если не готов ждем
out EEAR,addre ;Записываем адрес в регистр адреса
out EEDR,data ;Записываем данные в регистр данных
sbi EECR,EEMWE ;Устанавливаем бит разрешения записи
sbi EECR,EEWE ;Устанавливаем бит записи
inc addre ;Увеличиваем адрес в EEPROM
ret
;---------------------Чтение байта из ячейки EEPROM---------------------
eerd: cli
sbic EECR,EEWE ;Проверяем готовность EEPROM
rjmp eerd ;Если не готов ждем
out EEAR,addre ;Записываем адрес в регистр адреса
sbi EECR,EERE ;Устанавливаем бит инициализации чтения
in data,EEDR ;Помещаем прочитанный байт в data
inc addre ;Увеличиваем адрес в EEPROM
ret
propr: ldi flz,1 ;Установка флага задержки
reti