.INCLUDE "1200def.inc"; AT90S1200 @ 1 МГц
.CSEG
.EQU evReset=1
.EQU evPassed=3
.EQU evDenied=5
.EQU KeyRing=1
; Код клавиши звонка.EQU KeyEnter=9
; Код клавиши сброса.EQU NewPassKey=2
; Код клавиши, нажимаемой для ввода нового пароля.EQU KeyLen=5;
Длина секретного кода не должна быть больше 5 цифр.EQU FreqKeyPressed=50
; Константа частоты для выдачи писка при нажатии кнопок.EQU Note_1=227
; Константы частот и длительности нот.EQU Note_la0 = Note_1
.EQU Note_2=202
.EQU Note_ci0 = Note_2
.EQU Note_3=191
.EQU Note_do1 = Note_3
.EQU Note_4=170
.EQU Note_re1 = Note_4
.EQU Note_5=152
.EQU Notejni.1 = Note_5
.EQU Note_6=143
.EQU Note_fa1 = Note_6
.EQU Note_7=128
.EOU Note_sol1 = Note_7
.EOU Note_8=114
.EOU Note_la1=Note_8
.EOU Note9=101
.EOU Sote_ci1=Note_9
.EOU Note_10=96
.EOU Note_do2 = Note_10
.EGU Note_11=85
.EOU Note_re2 = Note_11
.EOU Note_12=76
.EOU Note_mi2 = Note_12
.EOU Note_13=72
.EOU Note_fa2 = Note_13
.EOU Note_14=64
.EOU Note_sol2 = Note_14
.EOU DURATION = 350
.EOU Time_1=1000/Note_1
.EOU Time_2=1000/Not e_2
.EOU Time_3=1000/Note_3
.EOU Time_4=1 000/Not e_4
.EOU Tinve_5=1000/Note_5
.EOU Time_6=1000/Note_6
.EOU Time_7=1000/Note_7
.DEF KeyPass=r0
.DEF tmp=r0
.DEF KeyPass1=r1
.DEF KeyPass2=r2
.DEF KeyPass3=r3
.DEF KeyPass4=r4
.DEF KeyPass5=r5
.DEF SSRE6=r6
.DEF DelayVar=r7
.DEF IntUse0=r8
.DEF LastKey=r9
.DEF ZerReg=r10
.DEF Time0=r16
; Время, увеличивается 3815 раз в секунду.DEF Time1=r17
; Время, увеличивается раз в 67 секунд.DEF Time2=r18
; Время, увеличивается раз в 47721 час,; насыщается за 50 суток
.DEF EEadr=r20
; Адрес для записи в EEPROM, равен 255.; если в текущий момент запись не производится
.DEF EventType=r21
.OEF BeepVar=r21
.DEF TimerEEByte=r22
.DEF TimerEEBit=r23
.DEF Key=r24
.DEF BeepDuration=r25
.DEF FreqConst=r26
.DEF IntUse1=r27
;.DEF PassLoopCounter=r28
.DEF Flags=r29
; bit 0 — Password accepted
.ORG 000
clr ZerReg
rjmp RESET
.ORG 002
;======================
; Здесь оказываемся при возникновении прерывания от таймера 3 раза в секунду
;======================
; Таймер используется как RTC и для вывода информации EEPR0N
; Увеличение счетчика времени
in SSREG.SREG
subi Time0,1
adc Time1,ZerReg
абс Time2,ZerReg
brcc TimeOk
com Time1
; Если проело переполнение, счетчик времени остановленcom Time2
TimeOk:
;Чтение данных из EEPROM и выдача на внешний порт.
;Процедура обработки прерывания будет вызвана не раннее, чей через 300-3∙4 мс
;после последнего обращения к EEPROM, поэтому проверка готовности EEPROM не
;производится, она должна быть уже готова.
andi TimerEEByte,$3F
out EEAR,TiirerEEByte
sbi EECR,EERE
;set EEPROH Read strobesbi EECR,EERE
;set EEPROH Read strobe 2nd timein IntUse0,EEDR
;get dataandi TimerEEBit,7
brne Bitlop
inc TimerEEByte
Bitlop: inc TimerEEBit
; =1.8mov IntUsel, TimerEEBit
rol IntUse0
BitShift
:; Выбираем посылаемый битror IntUse0
; Используется как текущий считанный EEPROM байтdec IntUse1
; Используется как счетчикbrne BitSbift
in IntUse1,PORTD
bst IntUse0,0
bid IntUse1,0
out PORTD,IntUsel
out SREG.SSREG
reti
;===============
;Здесь оказываемся при включении питания схемы
;===============
RESET:
;Настройка микросхемы и программы.
Idi r31,$8F
; Настраиваем направление работы портовout DDRB,r31
ldi r31,$03
out DDRD,r31
ldi r31,$05;
Настраиваем таймерout TCCRO,r31
ldi r31,$02
out TIMSK,r31
; Разрешаем прерывания при переполнении таймераldi r31.2
mov KeyPass1,r31
; Загружаем пароль по умолчаниюldi r31,3
mov KeyPass2,r31
ldi г31.2
mov KeyPass3,r31
ldi r31,3
mov KeyPass4,r31
ldi r31,2
clr Time
1; Сбрасываем счетчик времениclr Time2
rcall WrireEEPROM
sei
; Разрешаем прерыванияMainloop:
; Подготавливаемся к вводу пароля.
clr r30,0
clr r31,0
ori Flags,1
; При предъявлении пароля пока ошибок не былоclr KeyPass
clr LastKey
Passloop:;
Цикл ввода пароляrcall GetKey
; Записывает в переменную Key код нажатой клавишиbrtc Passloop
; и устанавливает бит Т, если клавиша нажатаcp Key,LastKey
breq Passloop
; Если предыдущая клавиша еще не отпущенаcpi Key,KeyEnter
breq MainLoop
; Если нажат сброс, начинаем ввод строки с началаldi FreqConst,FreqKeyPressed
ldi BeepDuration,5
rcall Beep
; Выдача короткого звукового сигналаmov LastKey,Key
inc r30
ld KeyPass.Z
cpse Key,KeyPass;
Сравниваем введенную цифру и цифру пароля из ОЗУ.andi Flags,~
1; если ошибка, сбрасываем бит успешности пароля.cpi r30,Keylen
; Длина секретного кода.brne PassLoop
; Вывод бита на внешний вывод порта и запись события в EEPROM
ldi EventType,evDenied
bst Flags,0
brtc PasswordDenied
sbi PORTD,1
; Если пароль совпал, включаем соленоидldi EventType,evPassed
PasswordDenied:
rcall WrireEEPROW
; Открытие двери при совпадении кода или цикл ожидания при ошибке
ldi Key,5
Openloop:
rcall Delay100
ldi BeepDuration,Time_7/2
ldi FreqConst,Note_7
rcall Beep
dec Key
sbic PIND,2
; Если сработал концевик (открылась дверь), то выходимbrne Openloop
; или выходим из цикла по тайм-аутуcbi PORTD,1;
Отключаем соленоид; Нажатие на клавишу NewPassKey в этой месте приводит к загрузке
rcall GetKey;
нового секретного кодаbrtc NainLoop
cpi Key,NewPassKey
brne Mainloop
sbrs Flags,0
; Если старый был предъявлен верноrjmp Mainloop
;Ввод нового, секретного кода,
ldi FreqConst,Note_3
;Проигрывание "приглашения" для изменения пароляldi BeepDuration,20
rcall Beep
ldi FreqConst,Note_5
ldi BeepDuration,20
rcall Beep
ldi FreqConst.Note_7
ldi BeepDuration,20
rcall Beep
rcall Delay100
NewPassword:
clr LastKey
clr r30
clr r31
NewPassLoop:
rcall GetKey
brtc NewPassLoop;
Ожидаем нажатия клавишиcp Key,LastKey
breq NewPassLoop
; Если клавиша еще не отпущена, продолжаем циклcpt Key,KeyEnter
breq NewPassword
; Если сброс, начинаем ввод строки с началаmov LastKey,Key
ldi BeepDuration,2*10
ldi FreqConst,2*FreqKeyPressed
rcall Beep
; Удлиненный звуковой сигналinc r30
St Z,Key
; Сохраняем введенную цифруcpi r30,Keylen
; Длина секретного кодаbrne NewPassLoop
rcall Delay100
ldi FreqConst,Note_7
; Проигрывание мелодии, говорящей обldi BeepDuration,20
; успешной изменении пароляrcall Beep
ldi FreqCoost, Note_5
ldi BeepDuration,20
rcall Beep
ldi FreqConst,Note_3
ldi BeepDuration,20
rcall Beep
rjmp MainLoop
;==============
;Дальше идут процедуры, вызываемые из основной программы
;==============
Веер:;
Выдача звукового сигналаldi BeepVar,20
Beep1: mov DelayVar.FreqConst
Delay2: rjmp NopJmp1;
2 +NopJmp1:dec DelayVar;
1 + = 5 мксbrne Delay2;2 +
sbi P0RTB.7
mov DelayVar.FreqConst
Delay3: rjrep NopJmp2
NopJmp2:dec DelayVar
brne Delay3
cbi P0RTB.7
dec BeepVar
brne Beep1
dec BeepDuration
brne Beep
sei
ret
;================
; Задержка на время порядка секунды
Delay100:
ldi BeepOuration,3
D100_3: clr FreqConst
D100_2: clr DelayVar
D100_1: dec DelayVar
brne D100_1
dec FreqConst
brne D100_2
dec BeepDuration
brne D100_3
ret
;================
; проверка приема данных от клавиатуры
GetKey:
clt;
Сброс признака, что была нажата клавишаldi r31,$0Е
; Младшая тетрада — запрос в порт, старшая -rcall GetKeyAnswer
; смещение ответаbrne KeyPressed
ldi r31,$3D
rcall GetKeyAnswer
brne KeyPressed
ldi r31,$6B
rcall GetKeyAnswer
brne KeyPressed
ldi r31,$97
rcall GetKeyAnswer
brne KeyPressed
ret
KeyPressed:
set
swap r31
andi r31,$0F
swap Key
andi Key,$07
CCFind: inc r31
; Поиск, какой конкретно бит установленlsr Key
brcc CCFind
breq NoMu1
clt
; Если нажато несколько клавиш, то не нажата ни однаNoNul: mov Key,r31
; Проверка, нажата ли кнопка Ring, если нажата, то будет выдан звуковой сигнал
; без сообщения об этом вызывающей функции
cpi Key,KeyRiog
breq Ring
rjmp NoRing
Ring: sbrc KeyPass1,0
; Выбор типа мелодии в зависимости от четностиrjmp SimpleRing
; старей цифры секретного кодаrcall Delay100
;Проигрываем сложную мелодию (Отговорила роща золотая)
;1 ми 1/8
ldi FreqConst,Note_mi1
ldi BeepDuration,2*DURATI0N/Note_mi1
rcall Beep_Del
;1 ми 1/8
ldi F reqConst,Note_mi1
ldi BeepDuration,2*DURATION/Note_mi1
rcall Beep_Del
; 1 ми 1/8
ldi FreqConst,Notejnii
ldi BeepDuration.2*DURATION/Note_mi1
rcall Beep_Del
;1 фа 3/8
Idi FreqConst,Note_fa1
ldi BeepDuration,6*DURATI0N/Note_fa1
rcall Beep_Del
;1 ми 1/8
ldi F reqConst,Note_mi1
ldi BeepDuration,2*DURATION/Note_mi1
rcall Beep_Del
;1 фа 3/8
Idi FreqConst,Note_fa1
ldi BeepDuration,6*DURATI0N/Note_fa1
rcall Beep_Del
;1 ми 1/16 (1/8)
ldi FreqCoost,Note_mi1
ldi BeepDuration,2*DURATI0N/Note_mi1
rcall Beep_Del
;1 ре 1/8
ldi FreqConst,Note_re1
ldi BeepDuration,2*DURATlON/Note_re1
rcall Beep_Del
;1 до 1/8
ldi FreqConst,Note_do1
ldi BeepDuration,2*DURATION/Note_do1
rcall Beep_Del
;1 си 1/4
ldi FreqConst,Note_ci0
ldi BeepOuration,4*DURATION/Note_ci0
rcall Beep_Del
; 1 фа 3/8
ldi FreqConst.Note_fa1
ldi BeepDuration,6*DIRATION/Note_fa1
rcall Beep_Del
;1 Фа 1/8
ldi FreqConst,Note_fa1
ldi BeepDuration,2*DURATION/Note_fa1
rcall Beep_Del
; 1 ми 3/8
ldi FreqConst.Note_mi1
ldi BeepDuration,6*DURATIOIN/Note_mi1
rcall Beep_Del
;1 ми 1/6
ldi FreqConst.Note.mil
ldi BeepDoration. 3*DURATI0N/Note_mi1
rcall Beep_Del
; 1 ми 1/8
ldi FreqConst.Note_mi1
ldi BeepDuration,2*DURATIOIN/Note_mi1
rcall Beep_Del
;1 Фа 1/8
ldi FreqConst,Note_fa1
ldi BeepDuration,2*DURATION/Note_fa1
rcall Beep_Del
;1 си 1/8
ldi FreqConst,Note_ci0
ldi BeepOuration,2*DURATION/Note_ci0
rcall Beep_Del
;1 ре 1/8
ldi FreqConst,Note_re1
ldi BeepDuration,2*DURATlON/Note_re1
rcall Beep_Del
;1 Фа 1/8
ldi FreqConst,Note_fa1
ldi BeepDuration,2*DURATION/Note_fa1
rcall Beep_Del
; 1 ми 5/8
ldi FreqConst.Note_mi1
ldi BeepDuration,10*DURATIOIN/Note_mi1
rcall Beep_Del
rjmp EndRing
SimpleRing
:; Проигрываем простую мелодиюldi F reqConst,Note_7
ldi BeepDuration,1
rcall Beep
ldi FreqConst,Note_5
ldi BeepDuration,1
rcall Beep
ldi FreqConst,Note_3
ldi BeepDuration,1
rcall Beep
ldi FreqConst,Note_5
ldi BeepDuration,1
rcall Beep
EndRing:
clt
; Сбрасываем флаг нажатия клавишиNoRing:
ret
;===================
Beep_Del:; Короткая пауза перед нотой и сама нота
ldi BeepVar,50
Del2: clr DelayVar
Del1: dec DelayVar
brne Del1
dec BeepVar
brne Del2
cli
rjmp Beep
;===================
; Сканирование клавиатуры: установка на выходных линиях заданного кода и прием
; ответа вызывается из функции GetKey
GetKeyAnswer:
mov Key,r31
andi Key,$0F
out PORTB,Key
clr DelayVar
Delay1: dec DelayVar
brne Delay1
in Key,PINB
com Key
andi Key,$70
;Если что-то было найдено, флаг Z не нулевойret
;===================
; Запись события EventType в текущую ячейку EEPR0M памяти и обнуление времени
WrireEEPROM:
; Поиск последней записи
clr tmp
ldi EEadr,2
FincNextAdr:
out TCNTO,ZerReg
; Пока не сработал таймер, читающий из EEPROM (через 300 мс). все операции должны быть завершеныsubi EEadr, — 2
cpi EEadr,62
brne EERead
ldi EEadr,4;
Если дошли до 64-ro адреса, начинаем с началаEERead
sbic EECR,EEWE
; Ждем обнуления бита EEWErjmp EERead
out EEAR,EEadr
; Подготавливаем адресsbi EECR,EERE
; Устанавливаем бит для синхронизацииsbi EECR,EERE
; Дваждыin r31,EEDR
; Читаем данныеdec tirp;
Если было 256 неудачных попыток найти битbreq NoZav
; признак последней записи, значит, его нет вообще, значит, пишем по любому адресуsbrs r31,0
rjmp FindNextAdr
NoZav: andi r31,$FE
EEWrite0:;
Запись дня сброса флага, указывающего на последнюю записьsbic EECR,EEWE
rjmp EEWrite0
out EEAR,EEadr
out EEDR,r31
sbi EECR,EEWE
inc EEadr
EEWrite1:;
Запись старшего байта времениsbic EECR,EEWE
rjmp EEWrite1
out EEAR,EEadr
out EEDR,Time2
sbi EECR,EEWE
inc EEadr
EEWrite2:;
Запись времени, типа события и флага последней записиsbic EECR,EEWE
rjmp EEWrite2
out EEAR,EEadr
mov r31,Time1
andi r31,SF8
or r31,EventType
out EEDR,r31
sbi EECR,EEWE
clr Time1
; Счетчик считает время между записями в EEPROM,clr Time2
; поэтому сбрасываем егоret
.EXIT
; Таблица использования линий микроконтроллера
; Порт В используется для подключения клавиатуры и динамика
; PORTB,7 — вывод на динамик
; PORTB,0…3 — выходы на сканирование клавиатуры
; PORTB,4…6 — входы от 12-клавишной клавиатуры, подключены к +5 В через резисторы
; Порт D используется для управления замком, выдачи информации и проверки двери
; PORTD.0 используется для вывода информации из ЕЕРАОН, на нем с частотой
; 3815 Гц (@ 1МГц) побитно выводится все ее содержимое
; PORTD.1 Подключен на электромагнит или двигатель, единица разрешает открытие
; PORTD.2 Подключен на концевику, срабатывающему (=0) при открытии