.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