Вот собрал устройство доступа для двери с помощью ключей 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);
}
}
