Звонок для входной двери.
-------------------------
При нажатии на кнопку генерится звуковой сигнал,
линию отводимую для ZV надо усилить и подключить
к ней динамик.
//программа звонка
//распределение входов/выходов:
//PIN.0 - кнопка к общему проводу, ZV - динамик
//
GL
LOOP:
IF(PIN.0==0) ZV
GOTO LOOP
EGL
При старте программы PIN будет настроен на ввод, а линия ZV на выход,
поэтому не требуется начальная настройка с помощью DDR.
При нажатой кнопке вход PIN.0 будет равен 0 т.к. кнопка подключена
между ним и общим проводом, при отпускании (пассивное состояние)
на PIN.0 еденица, т.к. по сбросу подключены внутренние резисторы,
вообщем это удобно, т.к. не надо ставить внешнего резистора
между PIN.0 и +5в. Подавления дребезга кнопки сдесь несущественно,
так что драйвер можно подключить, а можно и нет.
Программа постоянно в цикле опрашивает нажатие
кнопки и если нажата, то генерит звук. Поскольку оператор ZV
работает 0.25сек, то задержка генерации звука при отпускании кнопки
может достигать этого значения, но это в данном случае не существенно.
В устройстве звонка не используется SEEP и AT, а также после
отладки программы не требуется связь с PC и значит соответствующие
микросхемы могут быть благополучно изьяты. Для уменьшения размеров
можно использовать процессор в корпусе SOIC.
Чем мне нравится программируемость устройств, так это тем, что
без всякого паяльника можно перенастроить его работу, давайте
попробуем что-нибудь изменить в ранее приведенной программе.
Пусть при нажатии на кнопку генерится сигнал ограниченное время,
например 1 сек, если кнопка будет удерживаться и дальше, то
звонка не будет, для дальнейшего входа в режим генерации
кнопку требуется кратковременно отпустить, думаю что паузу
специально подбирать не требуется, достаточно подключить
подавитель дребезга, это где то 50мс. Эта программа уже
сложнее и не столь очевидна как предыдущея, поэтому
не плохо бы рассмотреть поподробнее алгоритм работы перед
его переводом в текст программы. Итак получается, что
требуется один битик для запоминания ситуации при котором
при нажатой кнопке генерация может быть, а может и не быть.
Пусть например этот бит (или флаг, что тоже самое) для
конкретности 0 - запрет генерации, 1 - разрешение генерации,
и разместим его в регистре R11, а еще конкретнее в его младшем
бите, можно было бы конечно использовать его целиком, но поскольку
ресурсы контроллера не велики, то экономия не помешает. Регистры
R12-R15 используются для сообщений, так что выбрал R11 как ближайший
к ним, вообще совет по возможности придерживаться смыслового
значения регистров, так например если решили, что в данной
программе R11 будет для флагов, то если в какой либо другой
программе потребуются флаги, то используйте также R11, это
поможет уменьшить кол-во ошибок. Также неплохо в начале программы
(/подпрограммы) в коментарии указывать какие регистры используются
и для чего. Итак R11.0 - флаг разрешения звонка, проверяем нажата ли
кнопка и если не нажата то устанавливаем флаг и зацикливаем до тех
пор, пока не будет нажата кнопка, в этом случае проверяем флаг и
если он установлен, то генерим звук 1 сек, сбрасываем флаг для
дальнейшего запрета генерации и идем на начало
цикла.
//программа кратковременного звонка
//распределение входов/выходов:
//PIN.0 - кнопка к общему проводу, ZV - динамик
//R11.0 - флаг разрешения звонка =1
//
GL
LOOP:
//если кнопка не нажата, разрешить звонок
IF(PIN.0==1) R11.0=1, GOTO LOOP
//кнопка нажата, проверить флаг
IF(R11.0==1) ZV,ZV,ZV,ZV, R11.0=0
GOTO LOOP
EGL
Звук растягивается до 1 сек путем повторения оператора ZV 4 раза,
т.к. каждый из них выполняется фиксированное время 0.25 сек.
Продолжим примеры модификации звонка. Пусть чужой не сможет
включить звонок, а свой сможет. Например пусть свой нажмет
2 коротких и один длинный, тогда звонок включится на 3 сек,
все другие варианты будут игнорированы. Длительность паузы
между нажатиями и длительность коротких звонков пусть не превышает
1 сек, а длинный должен быть от 2-х секунд. Эти задержки можно
подобрать экспериментально при отладке.
Алгоритм получается вроде такой:
1. пауза любой длительности (вход в исходное состояние) <----!
2. короткий звонок !
3. короткая пауза !
4. короткий звонок !
5. короткая пауза !
6. длинный звонок !
7. включение звонка на 3 сек --------------------------------!
Если длительности не соответствуют, то переходим к пункту 1 из
любого 2-6.
//программа избирательного звонка
//распределение входов/выходов:
//PIN.0 - кнопка к общему проводу, ZV - динамик
//R1,R2,R3 - константы времени
//R10 - частного использования
//DT - счетчик тиков по 16 мс (точнее по 16384 мкс)
//
//программа избирательного звонка
//распределение входов/выходов:
//PIN.0 - кнопка к общему проводу, ZV - динамик
//R1,R2,R3 - константы времени
//R10 - частного использования
//DT - счетчик тиков по 16 мс (точнее по 16384 мкс)
//
GL
ER:
STOPDT
//чтоб DT не остановился, т.к. по сбросу CDT=0=DT -> останов
CDT=$FFFF
//максимальная длительность короткого нажатия 1000/16=62
R1=62
//максимальная длительность короткой паузы 1000/16=62
R2=62
//минимальная длительность длинного нажатия 2000/16=125
R3=125
//
L1:
//ожидать отпускания кнопки
IF(PIN.0==0) GOTO L1
//
L2:
//ожидать нажатия кнопки
IF(PIN.0==1) GOTO L2
//
//накопление активности кнопки, первое нажатие
STARTDT(PUSTO)
M2:
IF(PIN.0==1) GOTO M3
IF(DT>R1) GOTO ER
GOTO M2
//накопление пассивности кнопки, первое отпускание
M3: STARTDT(PUSTO)
M4:
IF(PIN.0==0) GOTO M5
IF(DT>R2) GOTO ER
GOTO M4
//
//накопление активности кнопки, второе нажатие
M5: STARTDT(PUSTO)
M6:
IF(PIN.0==1) GOTO M7
IF(DT>R1) GOTO ER
GOTO M6
//накопление пассивности кнопки, второе отпускание
M7: STARTDT(PUSTO)
M8:
IF(PIN.0==0) GOTO M9
IF(DT>R2) GOTO ER
GOTO M8
//
//накопление активности кнопки, третье нажатие
M9: STARTDT(PUSTO)
M10:
IF(PIN.0==1) GOTO ER
IF(DT//растянуть звук на 3 сек (12 повторов ZV)
CLP(R10=0,11)
ZV
ECL
//на начальную синхронизацию, с обновлением констант
GOTO ER
EGL
//п/п таймера, никогда не срабатывает т.к. прерывания запрещены
//требуется только для соблюдения синтаксиса STARTDT(имя)
SUBDT=PUSTO
EDT
Таким образом программа стала гораздо длиннее, но не намного
сложнее, т.к. по сути повторяется одно и тоже:
определение ошибки (метка ER) при превышении длительности
нажатия/отпускания кнопки. Минимальное время нажатия/отпускания
не установлено, подавитель дребезга должен быть обязательно
подключен, т.к. алгоритм работы данного варианта основывается
на последовательности нажатий.
Звук растягивается до 3-х секунд с помощью цикла, работает
он так:
При входе в цикл, переменной цикла R10 присваивается 0,
конечное значение становится 11, затем выполняется ZV и
наконец в ECL к R10+1 и проверяется на R10>=11 и если
это условие истенно, то цикл завершается.
При сбросе прерывания запрещены (DI), так что прерывание от
таймера никогда не сработает, запись п/п сдесь только
для синтаксических целей.
Для уменьшения размера выходного
кода можно блок от метки M2 до M4 оформить в виде подпрограммы,
так как они идентичны, а флаг ошибки например держать в R11.0.
Если все же требуется услышать чужака, то сдесь напрашивается
решение генерить звук разных частот, при этом алгоритм видемо
можно оставить прежним, только при выходе по меткам ER
сгенерить звук чужака, например на 1 сек. Вопрос сдесь
заключается в том, что простейший драйвер пищалки не может
установить произвольно длительность и частоту. Возможно
воспользоваться таймером DT, но звук будет низким 16мс+16мс=32мс
период и следовательно частота 31 Гц. Более подходищим способом
является организация временной задержки непосредственно в программе.
Скорость выполнения одной строки где то 100 мкс, поэтому можно
организовать цикл задержки полупериода.
GL
LOOP:
PORT.10=1
CLP(R10=0,10)
ECL
//
PORT.10=0
CLP(R10=0,10)
ECL
//
GOTO LOOP
EGL
Для определения длительности эти 2 цикла полупериодов можно взять
во внешний цикл или использовать таймер DT.
На основе этого можно даже проиграть какуе нибудь мелодию,
записав ее предварительно в eeprom с помощью оператора SEEP,
или даже просто подставляя константы в выше приведенный блок,
но оформив его как подпрограмму.
Звук во всех вариантах получается дребезжащим из-за системных
прерываний в контроллере, в основном от tmr1.
В звонок возможно также добавить систему накопления информации,
по крайней мере будете знать кто звонил свой/чужой, в какое
время это было и какую проявил при этом настойчивость.
Сделать это элементарно, т.к. соответствующий драйвер накопления
событий представлен оператором SOB/ISOB по которому событие запоминается
в eeprom (и не боится сбросов по питанию). Перед включением звука надо
добавить следующее:
R12=константа чужой (например 20)
SOB
или
R12=константа свой (например 21)
SOB
Числа 20/21 и соответствующее абсолютное время будут запоминаться
в энергонезависимом буфере и будут там сколь угодно долго,
до переполнения буфера или при старте программы на РС, куда
они (в базу данных) и будут благополучно перекачены. Далее
возможен просмотр этих событий. Можно также подложить
датчик на замыкание под коврик перед дверью, и посмотреть не
топтался ли кто, присвоив данному событию например номер 22.
Как видите от простейшей задачи пришли к более продвинутой
используя только кнопку и усилитель с динамиком, причем
все модификации чисто программные, возможно и что немаловажно,
совместить программу звонка с каким нибудь другим устройством,
если позволят ресурсы контроллера. Сам не знаю, почему мне
пришел в голову звонок, давайте посмотрим еще что нибудь.
Кодовый замок
-------------
Поскольку я занимался системой доступа, то давайте посмотрим
нечто подобное.