Кодовый замок на pic
Содержание
Введение……………………………………………………….
- Разработка структурной схемы…………………………….……..……… 3
- Принцип действия замка………………………………….….………. 4
- Разработка принципиальной схемы………………...….……..…………. 6
- Выбор элементов схемы…………………………………..………….. 7
- Обоснование выбора микроконтроллера…………..……....……
…... 9 - Разработка алгоритма управляющей программы.…………………….. 12
- Разработка управляющей программы………………………………….. 13
Заключение……………………………………………………
Список использованной литературы…………………………………….… 29
Приложение 1……...………………………………………………………… 30
Приложение 2…………………………………………………………...…… 31
Приложение 3………………………………………………………………… 32
Введение
Кодовые замки являются эффективным средством предотвращения доступа посторонних лиц к охраняемым помещениям. К их достоинствам можно отнести простоту в обращении, надёжность, возможность обеспечить высокую степень защиты, относительную лёгкость смены кода (по сравнению со сменой обычного механического замка). Также немаловажными являются отсутствие необходимости изготовления ключей при предоставлении доступа большому количеству людей и невозможность физической потери ключа. Недостатком таких систем можно назвать возможность для злоумышленника подсмотреть код или подобрать его. Однако, при большой разрядности кода или наличии конструктивных особенностей, препятствующих подбору кода, таких как ограничение количества попыток или введение временной задержки между неудачными попытками, эта задача сильно затрудняется, поэтому последний недостаток нельзя назвать существенным.
В данном курсовом проекте осуществляется разработка электронного кодового замка с функцией дверного звонка и изменением пароля на микроконтроллере ATtiny2313.
- Разработка структурной схемы
Рисунок 1.1 – Структурная схема устройства
Введение кода доступа происходит посимвольно на клавиатурной матрице размером 4х3 и завершается после окончания контрольного промежутка времени (1с), то есть через 1 секунду после прекращения манипуляций с клавиатурой, при этом фильтруются случайные переключения контактов при нажатии клавиш и одновременном нажатии нескольких клавиш. Длина кода возможна любая, она ограничена только размером ОЗУ и EEPROM микроконтроллера. Матричная организация уменьшает количество занятых выводов МК.
Проверка кода доступа происходит сравнением введённого значения с тем, которое было установлено при конфигурировании кода доступа (которое было записано в EEPROM контроллера).
При нажатии кнопки звонка генерируются мелодии, записанные в памяти микроконтроллера. Они сохраняется в ПЗУ в виде отсчётов сигнала. Генерация звукового сигнала совершается с помощью пьезоэлектрического динамика подачей на него периодического сигнала звуковой частоты.
Изменение пароля происходит следующим образом: ввод старого пароля, проверка введенного пароля, если правильно введён, проверка режима записи, если замок находится в режиме записи, то ввод нового пароля, контрольный промежуток времени (1с.), открытие двери.
- Принцип действия замка
Замок имеет два режима работы. Режим "Записи кода" и режим "Работы". Для выбора режима предназначен переключатель S14 (см. Рисунок 2.1). Если контакты этого переключателя разомкнуты - замок находится в режиме "Работа", если замкнуты - в режиме "Запись кода". В режиме "Записи кода" хозяин квартиры нажимает кнопки набора кода в любом порядке и в любых комбинациях. Микроконтроллер отслеживает все изменения на клавиатуре и записывает их в ОЗУ. Причем не берется во внимание время удержания той либо иной комбинации. В память записывается лишь факт смены комбинаций. Длина кодовой последовательности ограничена только размерами ОЗУ. Сигналом к окончанию ввода кода служит прекращение манипуляций с клавиатурой. Процессор считает, что ввод кода закончился, если состояние клавиатуры не изменилось в течение одной секунды. В процессе набора код записывается в ОЗУ. При обнаружении паузы в 1 секунду процессор переписывает код в свою внутреннюю долговременную память (EEPROM). Этот код представляет собой последовательность байтов, отражающих все состояния клавиатуры во время набора. После того, как коды будут записаны, замок можно перевести в режим «Работа» (разомкнув контакты S14).
В режиме «Работа» замок постоянно находится в ожидании нажатия кнопок (S1...S12). То есть, ждет ввода кода. Для того, что бы дверь открылась, необходимо повторить те же самые манипуляции с кнопками, которые были сделаны в режиме записи кода . Микроконтроллер так же, как и в предыдущем случае отслеживает эти манипуляции, и записывает полученный таким образом код в ОЗУ. По окончании ввода кода (не нажимая
кнопок в течении 1 секунды) программа переходит в режим сверки кода. Она сравнивает код находящийся в ОЗУ и код, записанный в EEPROM. Сначала сравнивается длина обоих кодов. Затем коды сверяются побайтно. Если сравнение прошло успешно, микроконтроллер подает сигнал на ключ механизма открывания замка (VT2). Транзистор открывается и подает питание на реле K1, которое и открывает замок. Тут можно сделать по разному. Например, контакты реле K1 могут включать соленоид замка.
Кроме собственно замка это устройство выполняет так же роль дверного звонка. Для этого в схеме есть кнопка звонка (S13) и звуковой излучатель (VF1). В качестве усилителя звука используется ключ на транзисторе VT1. Программа сделана таким образом, что при прекращении звука на выходе PB3 контроллера всегда устанавливается логический ноль. Ключ закрывается и ток через транзистор и динамик VF1 не идет. Таким образом удалось обойтись без разделительной емкости. Дверной звонок работает независимо от кодового замка. Правда только в режиме ожидания кода. Когда код уже начали набирать, звонок отключается. При нажатии на кнопку звонка звучит одна из восьми записанных в память мелодий. При каждом нажатии новая мелодия. Мелодия звучит, пока нажата кнопка.
- Разработка принципиальной схемы
Рисунок 2.1 – Принципиальная схема кодового замка
- Выбор элементов схемы
Во-первых, за основу возьмём микроконтроллер ATtiny2313 (D1), так как для нашей задачи особо высокопроизводительного микроконтроллера не требуется, а эта модель полностью соответствует нашим требованиям, а также она имеет преимущества и особенности , которые были перечислены выше.
Для более точного подсчёта времени и корректного воспроизведения звука возьмём кварцевый резонатор (Q1) рассчитанный на частоту 4МГц. Для его корректной работы также необходимо выбрать С1 и С2, формирующие цепи согласования кварцевого резонатора. Емкости конденсаторов C1 и C2, подключаемых между выводами резонатора и общим проводом, зависят от частоты и типа резонатора. Для кварцевого резонатора на частоту 4 МГц, например, емкость каждого конденсатора составляет порядка 22 пФ.
Для подключения звукового излучателя (динамика) применяется ключевой каскад на транзисторе VT1. Это самый простой способ получить звук достаточной громкости, учитывая, что наш сигнал это прямоугольные импульсы с амплитудой, почти равной напряжению питания. Транзисторный каскад нужен лишь для повышения нагрузочной способности.
Микроконтроллер имеет два встроенных таймера/счетчика. Для формирования звука лучше подходит шестнадцатиразрядный таймер. Чем больше разрядов, тем с большей точностью можно выбирать его коэффициент деления.
Это очень важно для создания нотного стана. Поэтому для формирования звука выберем шестнадцатиразрядный таймер Т1. Теперь определимся с режимом работы нашего таймера. Для генерации звука удобнее всего использовать режим СТС (сброс по совпадению). Нам просто нужно выбрать такой коэффициент деления, чтобы на выходе таймера получить колебания в звуковом диапазоне частот.
Теперь определимся с тем, как наш сигнал будет попадать на внешний вывод микроконтроллера. Микроконтроллер предусматривает прямой вывод сигнала на один из своих выходов. Причем предусмотрены отдельные выходы для каждого из каналов совпадения. Для канала А подобный выход называется ОС1А. Он совмещен с третьим разрядом порта РВ и является альтернативной функцией данного контакта.
Подключение и отключение сигнала совпадения к внешнему выводу ОС1А производится программным путем. Это позволяет программе в нужный момент включать или выключать звук. Так как для вывода звука мы будем использовать один из разрядов порта РВ, то для подключения датчиков воспользуемся другим портом. А именно портом PD.
Однако подобная схема имеет и свой недостаток. В отсутствие звукового сигнала на выходе PB3 микроконтроллера обязательно нужно установить низкий логический уровень. Высокий логический уровень приведет к тому, что транзистор VT1 будет постоянно открыт. Это вызовет недопустимо большой ток через головку VF1. Постоянно протекающий ток через обмотку динамика вызовет излишнюю потерю мощности и может даже вызвать выход из строя, как транзистора, так и динамика. При составлении программы необходимо учесть этот момент.
Переключатель S14 предназначен для выбора режима работы. Если контакт переключателя S14 (на вход PB7 «0») замкнут, замок переходит в режим «Запись». Разомкнутые контакты (на PB7 «1») соответствуют режиму «Работа».
Переключатель S13 предназначен для звонка. Если контакт переключателя S13 (на вход PB6 «0») замкнут, звонок звенит. Разомкнутые контакты (на PB6 «1») – звонок прекращается.
Схема управления механизмом замка состоит из транзисторного ключа VT1 и электромагнитного реле К1. Резистор R2 ограничивает ток базы ключа. Диод VD1 служит для защиты от напряжения самоиндукции, возникающей на катушке реле. Питание реле осуществляется от отдельного источника + 12 В (питание микроконтроллера +5 В). Если в качестве VT1 применять транзистор КТ315, то электромагнитное реле может иметь рабочее напряжение +12 В и рабочий ток не более 250 мА. Контакты реле должны быть рассчитаны на управление исполнительным механизмом (соленоидом).
Звуковая часть и сам микроконтроллер питаются от напряжения +5 В. А электромагнит замка питается от отдельного источника + 12 В. Напряжение питания, подаваемое на микроконтроллер, обязательно должно
быть стабилизированным. Питание на электромагнит стабилизировать совершенно необязательно. Для повышения громкости звонка и для защиты от помех питание для звуковой схемы можно осуществлять от напряжения, поступающего на вход стабилизатора.
Обычно напряжение на входе стабилизатора равно +7...+11 В. Поэтому можно электромагнит и звуковую схему запитывать от одного нестабилизированного источника +12 В. Те же 12 В можно подавать на вход стабилизатора, с выхода которого снимать напряжение +5 В для микроконтроллера.
Для экономии и уменьшения количества занятых выводов применяем матричную организацию клавиатуры 3х4. Выводы подключаются к порту PORTD.
Каждый вывод строчек клавиатуры подтянут к «плюсу» резистором 2 кОм. Это нужно для того, чтобы в случае, если ни одна кнопка не нажата, на входы контроллера приходила «1». Если этого не сделать – на входе будет так называемое 3-е состояние – не пойми чего. Это не пойми чего, контроллер может понять совершенно произвольно. Может посчитать «нулем», может – «единицей», что вызовет ложные «нажатия» клавиш.
- Обоснование выбора микроконтроллера
Рисунок 2.2 – Расположение выводов ATtiny2313
Микросхема ATtiny2313 представляет собой восьмиразрядный микроконтроллер с внутренней программируемой Flash – памятью размером 2 Кбайт. Выполняя команды за один цикл, ATtiny2313 достигает производительности 1 MIPS при частоте задающего генератора 1 МГц, что позволяет разработчику оптимизировать отношение потребления к производительности.
AVR ядро объединяет богатую
систему команд и 32 рабочих регистра
общего назначения. Все 32 регистра
непосредственно связаны с
ATtiny2313 имеет следующие характеристики:
- 2 Кбайт системной программируемой Flash – памяти программ
- 128 байт EEPROM
- 128 байт SRAM (ОЗУ)
- 18 линий ввода – вывода (I/O)
- 32 рабочих регистра
- однопроводной интерфейс для внутрисхемной отладки
- два многофункциональных таймера/счетчика с функцией совпадения
- поддержка внешних и внутренних прерывании; последовательный программируемый USART – порт
- универсальный последовательный интерфейс с детектором начала передачи
- программируемый сторожевой таймер с внутренним генератором
- три программно изменяемых режима энергосбережения
В режиме Idle происходит приостановка центрального процессора, остальные системы продолжают работать. Выход из этого режима возможен как по внешнему прерыванию, так и по внутреннему. Например, при переполнении таймера.
В режиме Power Down сохраняется содержимое регистров, но приостанавливается работа внутреннего генератора и отключаются все остальные функции микросхемы. Выход из режима возможен по внешнему прерыванию или после системного сброса. Такое решение позволяет совмещать быстрый старт с низким энергопотреблением.
Микросхема изготовлена с использованием уникальной высокоточной технологии фирмы Atmel. Внутренняя Flash – память программ может быть перепрограммирована при помощи ISP – интерфейса без извлечения микроконтроллера из платы. Объединение 8 – разрядного RISC – процессора внутрисистемной перепрограммируемой Flash – памятью на одном кристалле делают микросхему ATtiny2313 мощным средством, которое обеспечивает очень гибкие и недорогие решения многих прикладных задач управления.
- Разработка алгоритма управляющей программы
Рисунок 3.1 – Алгоритм управляющей программы
- Разработка управляющей программы
;------------------------- Псевдокоманды управления
.include "tn2313def.inc" ; Присоединение файла описаний
.list ; Включение листинга
.def drebL = R1 ; Буфер антидребезга младший байт
.def drebH = R2 ; Буфер антидребезга старший байт
.def temp1 = R3
.def temp = R16 ; Вспомогательный регистр
.def data = R17 ; Регистр передачи данных
.def flz = R18 ; Фаза работы замка
.def count = R19 ; Регистр передачи данных
.def addre = R20 ; Текущий адрес в EEPROM
.def prewcode = R21 ; Временный буфер кода
.def Key = R22 ; Код клавиши
.def loop = R23 ; Регистр счетчика
.def fnota = R24 ; Частота текущей ноты
.def dnota = R25 ; Длительность текущей ноты
.DEF LastKey=r9
.DEF DelayVar=r7
;------------------------- Определение констант
.equ bsize = 30 ; Размер буффера для хранения кода
.equ zad = 3000 ; Порог чувствительности
.equ kandr = 20 ; Константа антидребезга
;------------------------- Резервирование ячеек памяти (SRAM)
.dseg ; Выбираем сегмент ОЗУ
.org 0x60 ; Устанавливаем текущий адрес сегмента
bufr: .byte bsize ; Буфер для приема кода
melod: .byte 1 ; Номер текущей мелодии
;------------------------- Резервирование ячеек памяти (EEPROM)
.eseg ; Выбираем сегмент ОЗУ
.org 0x08 ; Устанавливаем текущий адрес сегмента
klen: .byte 1 ; Резервирование ячейки для хранения длины кода
bufe: .byte bsize ; Буфер для хранения кода
;------------------------- Начало программного кода
.cseg ; Выбор сегмента программного кода
.org 0 ; Устанеовка текущего адреса на ноль
start: rjmp init ; Переход на начало программы
reti ; Внешнее прерывание 0
reti ; Внешнее прерывание 1
reti ; Прерывание по захвату таймера T1
rjmp propr ; Прерывание по совпадению T1
rjmp propr ; Прерывание по переполнению T1
reti ; Прерывание по переполнению T0
reti ; Прерывание UART прием завершен
reti ; Прерывание UART регистр данных пуст
reti ; Прерывание UART передача завершена
reti ; Прерывание по компаратору
reti ; Прерывание по изменению на любом контакте
reti ; Таймер/счетчик 1. Совпадение B
reti ; Таймер/счетчик 0. Совпадение B
reti ; Таймер/счетчик 0. Совпадение A
reti ; USI Стартовая готовность
reti ; USI Переполнение
reti ; EEPROM Готовность
reti ; Переполнение охранного таймера
;*****************************
;*
Модуль инициализации
;*****************************
init:
;-------------------------- Инициализация стека
ldi temp, RAMEND ; Выбор адреса вершины стека
out SPL, temp ; Запись его в регистр стека
;-------------------------- Инициализация портов В/В
ldi temp,0x18 ; Инициализация порта PB
out DDRB,temp
ldi temp,0xE7
out PORTB,temp
ldi temp, 0x0F ; Инициализация порта PD
out DDRD, temp
ldi temp, 0x7F
out PORTD, temp
;------------------------ Инициализация (выключение) компаратора
ldi temp, 0x80
out ACSR, temp
;--------------------------- Номер мелодии
ldi temp,0
sts melod,temp
;*****************************
;*
Начало основной программы
;*****************************
main:
;--------------------------- Инициализация таймера
ldi temp,high(zad) ; Записываем коэффициент задержки
out OCR1AH,temp
ldi temp,low(zad)
out OCR1AL,temp
ldi temp,0x03 ; Режим работы таймера
out TCCR1B,temp
m0: rcall incod ; Ввод и проверка кода клавиш
brne m0
m1: in temp,PINB ; Проверка кнопки звонка
sbrs temp,6
rjmp kk1 ; Если нажата, переходим к звуковой части
m2: ldi ZH,high(bufr) ; Установка указателя
ldi ZL,low(bufr) ; на начало буфера
clr count ; Сброс счетчика байт
;---------------------- Цикл ввода кода
m3: cli ; Запретить все прерывания
ldi data,1 ; Вызываем задержку первого типа
rcall wait ; К подпрограмме задержки
m5: rcall incod ; Ввод и проверка кода кнопок
st Z+,Key ; Записываем его в буфер
inc count ; Увеличение счетчика байтов
cpi count,bsize ; Проверяем не конец ли буфера
brsh m7 ; Если конец, завершаем ввод кода
mov prewcode,Key ; Записываем код как старый
ldi data,2 ; Вызываем задержку второго типа
(подготовка к задержке)
rcall wait
m6: rcall incod ; Ввод и проверка кода кнопок
cp Key,prewcode
brne m3 ; Если изменилось, записываем в буфер
cpi flz,1 ; Проверка окончания фазы ввода кода
brne m6
m7: sbic PINB,7 ; Проверка состояния тумблера
rjmp m9 ; Если тумблер в режиме"работы", то на проверку кода
ldi addre,0x08 ; Адрес начала хранения кода
rcall eerd ; Чтение значения ячейки из EEPROM
cpi data,0xFF ; Сравнение со значением FF(пусто)
breq eewrite ; Если равны, то пропускаем проверку и переходим к записи
; ----------------------------- Процедура проверки кода
m9:
ldi addre,klen ; Адрес хранения длины кода
rcall eerd ; Чтение длины кода из EEPROM
cp count,data ; Сравнение с новым значением
brne m13 ; Если не равны, к началу
ldi addre,bufe ; В YL начало буфера в EEPROM
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
rjmp m11
; ----------------------------- Режим записи кода
eewrite:
mov data,count ; Помещаем длину кода в data
ldi addre,klen ; Адрес хранения длины кода
rcall eewr ; Записываем в длину кода EEPROM
ldi addre,bufe ; В регистр адреса начало буфера
ldi ZH,high(bufr) ; В регистровую пару Z записываем
ldi ZL,low(bufr) ; адрес начала буфера в ОЗУ
m8: ld data, Z+ ; Читаем очередной байт из ОЗУ
rcall eewr ; Запись байта в EEPROM
dec count ; Декримент счетчика байтов
brne m8
; ----------------------------- Открывание замка
m11:
sbi PORTB,4 ; Команда "Открыть замок"
ldi data,3 ; Вызываем задержку третьего типа
rcall wait
cbi PORTB,4 ; Команда "Закрыть замок"
m13: rjmp main
;*****************************
;*
Вспомогательные процедуры
;*****************************
; Проверка прием данных от клавиатуры.
incod:
clr r31
clt ; Сброс признака что была нажата клавиша.
ldi r31,$0E ; Младьшая тетрада-запрос в порт, старшая
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 NoMul
clt ; Если нажато несколько клавиш то не нажата ни одна.
NoMul: mov Key,r31
ret
; Сканирование клавиатуры: установка на выходных линиях заданого кода и прием
; ответа вызыватеся из функции GetKey.
GetKeyAnswer:
mov Key,r31
andi Key,$0F
out PORTD,Key
clr DelayVar
Delay1: dec DelayVar
brne Delay1
in Key,PIND
com Key
andi Key,$70 ; Если что то было найдено флаг Z нулевой.
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 ; Сбрасываем флаг задержки
sei ; Разрешаем прерывания
cpi data,2 ; Если это задержка 2-го типа
breq w4 ; Завершаем подпрограмму
w3: cpi flz,1 ; Ожидание окончания задержки
brne w3
w4: ret
; ------------------------------ Запись байта в ячейку EEPROM
eewr:
sbic EECR,EEWE ; Проверяем готовность EEPROM
rjmp eewr ; Если не готов ждем
out EEAR,addre ; Записываем адрес в регистр адреса
out EEDR,data ; Записываем данные в регистр данных
sbi EECR,EEMWE ; Устанавливаем бит разрешения записи
sbi EECR,EEWE ; Устанавливаем бит записи
inc addre ; Увеличиваем адрес в EEPROM
ret
; ------------------------------ Чтение байта из ячейки EEPROM
eerd:
sbic EECR,EEWE ; Проверяем готовность EEPROM
rjmp eerd ; Если не готов ждем
out EEAR,addre ; Записываем адрес в регистр адреса
sbi EECR,EERE ; Устанавливаем бит инициализации чтения
in data, EEDR ; Помещаем прочитанный байт в temp
inc addre ; Увеличиваем адрес в EEPROM
ret
;*****************************
;*
Процедура обработки
;*****************************
propr: ldi flz,1 ; Установка флага задержки
reti ; Завершаем обработку прерывания
;*****************************
;*
Мелодичный звонок
;*****************************
kk1:
;--------------------------- Инициализация таймера T1
ldi temp, 0x09 ; Включаем режим CTC
out TCCR1B, temp
km1: ldi temp, 0x00 ; Выключаем звук
out TCCR1A, temp
;-------------------------- Вычисление номера нажатой кнопки
lds count,melod ; Читаем код текущей мелодии
inc count ; Увеличение номера мелодии на 1
cpi count,4 ; Проверка не последняя ли мелодия
brne km2 ; Если не последняя, переход
clr count ; Обнуление счетчика
km2: sts melod,count ; Помещаем номер в ячейку памяти
;-------------------------- Выбор мелодии
km3:
mov YL, count ; Вычисляем адрес, где
ldi ZL, low(tabm*2) ; хранится начало мелодии
ldi ZH, high(tabm*2)
rcall addw ; К подпрограмме 16-разрядного сложения
lpm XL, Z+ ; Извлекаем адреса из таблицы
lpm XH, Z ; и помещаем в X
;--------------------------- Воспроизведение мелодии
km4: mov ZH, XH ; Записываем в Z начало мелодии
mov ZL, XL
km5: in temp, PINB ; Читаем содержимое порт B
sbrc temp, 6 ; Проверяем нажата ли еще кнопка звонка
rjmp km6 ; Если равно (кнопки отпущены) в начало
lpm temp, Z ; Извлекаем код ноты
cpi temp, 0xFF ; Проверяем не конец ли мелодии
breq km4 ; Если конец, начинаем мелодию сначала
andi temp, 0x1F ; Отделяем от кода частоту
mov fnota, temp ; Записываем в регистр частоту ноты
lpm temp, Z+ ; Еще раз берем код ноты
rol temp ; Сдвигаем так, что бы три старших
rol temp ; разряда стали младшими
rol temp
rol temp
andi temp, 0x07 ; Извлекаем код длительности задержки
mov dnota, temp; Помещаеем ее в ячейку длительности
rcall nota ; К подпрограмме воспроизведения ноты
rjmp km5 ; В начало цикла (следующая нота)
km6: ldi temp, 0x00 ; Выключаем звук
out TCCR1A, temp
rjmp main
;*****************************
;*
Вспомогательные подпрограммы
;*****************************
; ---------------------- Подпрограмма 16-ти разрядного сложения
addw: push YH
lsl YL ; Умножение первого слагаемого на 2
ldi YH, 0 ; Второй байт первого слагаемого = 0
add ZL, YL ; Складываем два слагаемых
adc ZH, YH
pop YH
ret
;----------------------- Подпрограмма исполнения одной ноты
nota: push ZH
push ZL
push YL
push temp
cpi fnota, 0x00 ; Проверка не пауза ли
breq nt1 ; Если пауза, переходим сразу к задержке
mov YL, fnota ; Вычисляем адрес, где хранится
ldi ZL, low(tabkd*2) ; коэффициент деления для текущей ноты
ldi ZH, high(tabkd*2)
rcall addw ; К подпрограмме 16-разрядного сложения
lpm temp, Z+ ; Извлекаем мл. разр. КД для текущей ноты
lpm temp1, Z ; Извлекаем ст. разр. КД для текущей ноты
out OCR1AH, temp1 ; Записать в старш. часть регистра совпадения
out OCR1AL, temp ; Записать в младш. часть регистра совпадения
ldi temp, 0x40 ; Включить звук
out TCCR1A, temp
nt1: rcall wait1 ; Задержка
ldi temp, 0x00 ; Выключить звук
out TCCR1A, temp
ldi dnota,0 ; Сбрасываем задержку
rcall wait1 ; Пауза между нотами
pop temp
pop YL
pop ZL
pop ZH
ret
;----------------------- Подпрограмма задержки
wait1: push ZH
push ZL
push YH
push YL
mov YL, dnota ; Вычисляем адрес, где хранитсяldi ZL, low(tabz*2) ; нужный коэффициент задержкиl
di ZH, high(tabz*2)
rcall addw ; К подпрограмме 16-разрядного сложения
lpm YL, Z+ ; Читаем первый байт коэффициента задержки
lpm YH, Z ; Читаем второй байт коэффициента задержки
clr ZL ; Обнуляем регистровую пару Z
clr ZH ; Цикл задержки
ww1: ldi loop,255 ; Пустой внутренний цикл
ww2: dec loop
brne ww2
adiw R30, 1 ; Увеличиваем регистр Z на единицу
cp YL, ZL ; Проверка младшего разряда
brne ww1
cp YH, ZH ; Проверка старшего разряда
brne ww1
pop YL ; Завершение подпрограммы
pop YH
pop ZL
pop ZH
ret
;*****************************
;*
Таблица задержек
;*****************************
tabz: .dw 128,256,512,1024,2048,4096,
;*****************************
;*
Таблица коэффициентов деления
;*****************************
tabkd: .dw 0
.dw 4748,4480,4228,3992,3768,

- Кодовый замок на микроконтроллере
- Кодоимпульсный аналого-цифровой преобразователь
- Коды, исправляющие дефекты
- Коекуренция: содержание, формы, механизм и результаты
- Кожа и ее производные
- Кожаная обувь
- Кожній редакційно-видавничій організації підібрати таку конфігурацію КВС
- Кодификация римского права
- Кодификация русского права в первой половине 19 века
- Кодификация советского права в 50-70 годы XX века
- Кодификация современного Российского законодательства
- Кодификация Сперанского
- Кодификация Юстиниана
- Кодификация Юстиниана