Вот собрал устройство доступа для двери с помощью ключей iButton
на Arduino
Что умеет делать:
— открытие/закрытие двери с помощью iButton
— режим администратора (с помощью admin iButton) : просмотр ключей, добавление, удаление
— режим начального запуска или сброса (когда нет или утерян admin iButton)
Для проекта использовались:
ORDUINO-NANO
СИМВОЛЬНЫЙ LCD ЭКРАН 16X2 WH1602B-YEI-CTV
Модуль реле
Стабилизатор напряжения L7805, L7808
Конденсаторы 22мкФ
Резисторы 4.7 кОм, 10 кОм
резистор подстроечный 10кОм
Кнопки 2 шт — красная и зеленая
Ключи iButton
Контактная площадка для ключей iButton
Корпус
Электромагнитная защелка AT-ES01
Пьезоизлучатель для воспроизведения музыкального фрагмента
Схема электрическая
Дисплей WH1602B-YEI-CTV.
#include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
Долгое время не мог понять почему изображение блеклое (видимость близкая к нулю). Надо читать datasheet — подстроечный резистор для управления контрастностью подключается не к 0 и 5В, а к -5 и 5В. Приемлемое значение получается при отрицательном напряжении.
iButton.
Используем pin 10
#include <OneWire.h> OneWire ds(10);
Питание
12В понижаем до 8 (L7808), а затем до 5 (L7805).
Электрозамок
Здесь не сам электромагнитный замок, а защелка электромагнитная на замок. При подаче напряжения 12В открывает замок, при подаче 0 — блокирует.
Блок реле
питание 5В, коммутация до 250В 10А. Блок имеет 4 контакта GND, Vcc, NG, CSI. Для замыкания контактов реле необходимо подать 1 на вывод SCI.
В цикле loop() программа сканирует клавиатуру, сразу проверяя на дребезг, а также проверяет подключение iButton.
При подключении ключа проверяем его код с кодами разрещенных ключей из памяти EEPROM. Функция prov_key() (см. листинг 2.?) возвращает номер ключа в списке, либо 0, при отсутствии.
При удачном открыть защелку (подача 0) и вывод музыкального фрагмента 1 на пьезоизлучатель (подробно можно посмотреть, например, здесь) и вывод сообщения на дисплей
При неудачном — вывод сообщения на дисплей bad key и второго музыкального фрагмента
Понятно, что вывод на дисплей не виден (коробка с другой стороны — это для проверки админа)
Повторный ввод ключа — закрытие замка.
При вводе ключа админа (проверка с базой ключей, хранящихся в EEPROM) входим в режим администратора.
Здесь следим за кнопками
красная — выбор следующего режима
Режимы
add key — новый ключ заносится в базу EEPROM
delete — ? подтвердить
и подтверждение удаления
зеленая — просмотр ключей в базе перебором (номер и 64 бит побайтно).
Режим начальной установки
проверка что список ключей пуст EEPROM — 1 считанный ключ становится ключом администратора
или сброса(делал для себя) — держим красную кнопку 5 сек — очистка EEPROM
И код
#include <OneWire.h> OneWire ds(10); // на digital pin 10 #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12, 11, 7, 6, 5, 4); #include <EEPROM.h> int count_keys=0; int address = 0; byte value; int count=0; int admin=0; // int type1=0; // 0-view;1-prog;2-del int click11=0; int click12=0; int pos11=2; long endmillis11=0; long endmillis12=0; // int address1=0; int address2=8; byte addr[8]; byte door=1; // ноты мелодии (пробел - это пауза) char notes1[]="GECgabCaCg "; // пробел - это пауза char notes2[]="EFEDGEDC"; // длительность для каждой ноты и паузы int beats1[] = { 4, 4, 4, 4, 1, 1, 1, 2, 1, 4, 2, 4, 4, 4, 4, 1, 1, 1, 2, 1,4, 2, 1, 1, 1, 1, 2, 1, 1, 4, 2, 1, 2, 1, 2, 1, 1, 4, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 4, 4, 4} ; int beats2[] = { 4, 4, 4, 4, 1, 1, 1, 2, 1, 4, 2, 4, 4, 4, 4, 1, 1, 1, 2, 1,4, 2, 1, 1, 1} ; // подключить динамик к pin 17 int speakerPin = 17; // темп воспроизведения int tempo1 = 50; int tempo2 =50; // подключить реле к pin 19 int relayPin = 18; void setup(void) { int i1;byte val1; pinMode(8, INPUT); // назначить выводу порт ввода pinMode(9, INPUT); // назначить выводу порт ввода // for(i1=8;i1<512;) { val1=EEPROM.read(i1); Serial.println(val1,HEX); if(val1==0xFF) break; else count++;; i1=i1+8;} EEPROM.write(address1,count); if(count==0) {admin=2;type1=1;} Serial.begin(9600); for(i1=8;i15000) // нажата более 5 сек { clear_EEPROM(); lcd.clear(); lcd.print("iButton v0.1"); lcd.setCursor(0,7); lcd.print("act_keys=0"); admin=1;type1=1; } if(admin==1) {// режим программирования - проверяем кнопки // чтение pin8 if(click11==1 && millis()-endmillis11>1000 && count>0) // нажата более 1 сек {type1=0; endmillis11=millis(); pos11++; if(pos11>count) pos11=min(2,count); lcd.clear(); lcd.setCursor(0,0); lcd.print(" tekkey= "); view_key1(pos11); } else ; // чтение pin9 // нажата более 1 сек if(click12==1 && millis()-endmillis12>1000 && type1==2) // подтверждение удаления {if(pos11>1) delete_key(pos11); else admin_display(" empty ",0); type1=0; endmillis12=millis(); admin_display("admin = ",0); view_key1(1); } else if(click12==1 && millis()-endmillis12>1000 && type1==1) // режим - удалить? { type1=2; endmillis12=millis(); admin_display("delete ? ",0); view_key1(pos11); } else if(click12==1 && millis()-endmillis12>1000 && type1==0) // вход в режим программирования { type1=1; endmillis12=millis(); admin_display("add key ",0);} else ; } // byte present = 0; //byte data[12]; //byte addr[8]; if ( !ds.search(addr)) { Serial.print("empty"); ds.reset_search(); delay(1000); return; } res1=prov_key(); if(res1==1) {admin=1-admin;view_key(res1);playYES(); digitalWrite(relayPin, 1-door);} else if(res1>1) {view_key(res1); playYES();door=1-door; if(door==1) digitalWrite(relayPin, HIGH); else digitalWrite(relayPin, LOW); } else if(admin>0 && type1==1) {add_new_key(count+1);type1=0;admin =1;playYES();} else {admin_display("bad key ! ",0); for( i = 0; i < 8; i++) { lcd.setCursor((7-i)*2,1); lcd.print(addr[i],HEX); playNO(); } } } // ********************* проверка наличия ключа в EEPROM int prov_key() { byte i1; byte i2; int count11; for( i1 = 1; i1 <= count; i1++) {count11=0; for( i2 = 0; i2 < 8; i2++) { if(addr[i2]==EEPROM.read(i1*8+i2)) count11++; } if(count11==8) return i1; } return 0; } // ********************* добавление ключа в EEPROM void add_new_key(int nnew) { byte i1; if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("CRC is not valid!\n"); return; } if ( addr[0] != 0x01) { Serial.print("Device is not a DS1990A family device.\n"); return; } count++; lcd.setCursor(0,0); lcd.print("key_new = "); lcd.print(count,HEX); for( i1 = 0; i1 < 8; i1++) { lcd.setCursor((7-i1)*2,1); lcd.print(addr[i1],HEX); EEPROM.write(nnew*8+i1, addr[i1]); } ds.reset(); delay(1000); } // ********************* вывод прислоненного ключа в lcd void view_key(int rr) { byte i; Serial.print(" nkey = "); lcd.clear(); lcd.setCursor(0,0); if(admin==1 && rr==1) lcd.print("admin ="); else lcd.print(" user = "); lcd.setCursor(8,0); lcd.print(rr); for( i = 0; i < 8; i++) { lcd.setCursor((7-i)*2,1); lcd.print(addr[i],HEX); //EEPROM.write(i1*8+i, addr[i]); } ds.reset(); delay(1000); return; } // ********************* вывод ключа из EEPROM void view_key1(int rr) { byte i; lcd.setCursor(8,0); lcd.print(rr); for( i = 0; i < 8; i++) { lcd.setCursor((7-i)*2,1); lcd.print(EEPROM.read(rr*8+i),HEX); } delay(1000); return; } // ********************* индикация режимов админа void admin_display(String str1,int stroke) { Serial.print(str1); lcd.clear(); lcd.setCursor(0,stroke); lcd.print(str1); //delay(1000); } // удаление ключа из EEPROM void delete_key(int nn) { byte val1; for(int i1=nn;i1<=count;i1++) { for(int i2=0;i2<8;i2++) { val1=EEPROM.read((i1+1)*8+i2); Serial.print(i1*8+i2,DEC); Serial.print(" "); Serial.print(val1,HEX); Serial.println(); EEPROM.write(i1*8+i2,val1); } } count--; } // ********************* очистка EEPROM void clear_EEPROM() { for (int i1 = 8; i1 < 512; i1++) EEPROM.write(i1, 0xFF); EEPROM.write(address1,0); count=0; } // мелодия YES void playYES() { for (int i = 0; i < sizeof(notes1); i++) { if (notes1[i] == ' ') //tone(speakerPin,0, beats1[i]*tempo1* 1000L); // пауза delay(beats1[i] * tempo1); // пауза else playNote(notes1[i], beats1[i] * tempo1); } } // мелодия NO void playNO() { for (int i = 0; i < sizeof(notes2); i++) { if (notes2[i] == ' ') //tone(speakerPin,0, beats1[i]*tempo2* 1000L); // пауза delay(beats2[i] * tempo2); // пауза else playNote(notes2[i], beats2[i] * tempo2); } } // проиграть ноту void playNote(char note, int duration) { // массив для наименований нот (до ре ми ... и т.д. в пределах двух // октав) char names[]={'c','d','e','f','g','a','b','C','D','E','F','G','A','B'}; int tones[]={3830,3400,3038,2864,2550,2272,2028,1912,1700, 1518,1432,1276,1136,1014 }; // проиграть тон, соответствующий ноте for (int i = 0; i < sizeof(tones); i++) { if (names[i] == note) playTone(tones[i], duration); } } void playTone(int tone, int duration) { for (long i = 0; i < duration * 1000L; i += tone * 2) { digitalWrite(speakerPin, HIGH); delayMicroseconds(tone); digitalWrite(speakerPin, LOW); delayMicroseconds(tone); } }