замОк на RFID Reader RDM6300 + Arduino NANO
- Войдите на сайт для отправки комментариев
Доброго всем здоровья !
Заморочился на тему установки домой электромеханического замка, который будет открываться ключём от подъезда. Собрал девайс, написал код. Идея была такая: По нажатию кнопки можно записать ID ключа в EEPROM ардуины. "Длина" ключа 14-байт. Пакет данных всегда начинается с "2" и заканчивается "3" это первый и последний байт ключа. Ну а после того, как ключи записаны , собственно можно по ним открывать замок. Ну и классика жанра: В принципе всё работает, но работает не совсем так, как нужно. Одна из основных проблем в том, что когда ключ считывается, он считывается в буфер, размер которого как я понял - 64 байта. Считывается он туда многократно, всё зависит от времени нахождения ключа в зоне катушки. Так вот отсюда начинаются проблемы: реле срабатывает ровно столько раз, сколько раз ключ был считан в буфер
Хотя должно сработать один раз и всё. Как бы очистить этот буфер после получения одного пакета с данными ?
#include <SoftwareSerial.h>
#include <EEPROM.h>
//#include <Bounce2.h>
//#define BUTTON_PIN 5
#define LED_PIN 13
SoftwareSerial RfidReader(2, 3);
int num = 0;
int count = 0;
int prekey[14];
int key[12];
int testrom[122];
int index = 0;
int i, a, b, h;
int keys =0;
bool keyOk = false;
bool CheckOk = false;
bool wrmem = false;
int switchPin = 5;
int Relay = 6;
boolean lastButton = HIGH;
boolean currentButton = HIGH;
void setup(){
Serial.begin(9600);
RfidReader.begin(9600);
// Setup the button with an internal pull-up :
pinMode(switchPin,INPUT_PULLUP);
pinMode(LED_PIN,OUTPUT);
pinMode(Relay, OUTPUT);
}
boolean debounce(boolean last)
{
boolean current = digitalRead(switchPin);
if (last != current)
{
delay(5);
current = digitalRead(switchPin);
}
return current;
}
void ReadID()
{
count = 0;
for (count =0; count <=13; count++)
{
if (RfidReader.available() > 0) //Если присутствуют данные со считывателя карт
{
Serial.print("ReadID Function");
num = RfidReader.read(); // Присваеваем переменной num первый считанный байт
prekey[count] = num ; // Заполняем массив от 0 до 13 значениями полученных байт в num
Serial.print("count=");
Serial.println(count);
Serial.print("num=");
Serial.println(num, DEC);
if(count >= 13) //Если считали 14 байт, ....
{
if (prekey[0] == 2 && prekey[13] == 3) // Если первый элемент массива равен 2 а последний 3
{
keyOk = true;
Serial.print ("keyOk=");
Serial.print (keyOk);
Serial.println (' ');
Serial.print ("key=");
for (a=0; a<=11; a++)
{
b = a+1;
key[a] = prekey[b];
Serial.print (key[a]);
}
return;
}
else
{
Serial.print ("Key is not very" );
keyOk = false;
count = 0;
num =0;
}
delay (1000);
Serial.println (' ');
Serial.print("prekey=");
for(i=0; i<=13; i++)
{
int x= prekey[i];
Serial.print(x);
}
Serial.println(' ');
count = 0;
delay (1000);
}
}
else
{
count = 0;
num = 0;
keyOk = false;
break;
}
}
}
void CheckMem () // функция проверки наличия ключа в памяти
{
Serial.println("CheckMem function");
keys = testrom[0]; // num - ячейка количества записанных ключей
int n = keys*12+2; // n - номер первой чистой ячейки
int k;
int g;
int j;
int CheckCount =0;
for (k=0; k<=(n-1); k=k+12) // цикл пересчитывает блоки ключей, каждый блок 12 байт
{
Serial.print("k=");
Serial.println(k);
for (j=0; j<=11; j++) // цикл пересчитывает, сравнивает каждый байт массива ключа и массива памяти
{ g = (j+k+2); // переменная указывает на нужный байт в памяти соответствующий или не соответствующий байту ключа
Serial.print("key_j=");
Serial.println(key[j]);
Serial.print("testrom_g=");
Serial.println(testrom[g]);
if (key[j] == testrom[g]) // сравнение ключа с сохранённым в памяти побайтово
{
CheckCount ++; // прибавляет единицу если байты соответствуют друг другу
Serial.print("CheckCount=");
Serial.println(CheckCount);
}
else
{
CheckCount =0; // если нет совпадения в байтах, сбросить счётчик в 0
}
}
if (CheckCount == 12) //Если все 12 байт подряд равны,
{
CheckOk = true; //Меняем значение переменной в true
Serial.println(' ');
Serial.print("Key found in memory");
break; //Прекращаем цикл, так как такой ключ есть в памяти устройства
}
else
{
Serial.println(' ');
Serial.println("key not found");
CheckOk = false; // Стафим флаг , о том что такого ключа не найдено
}
}
}
void WriteMem () // Функция сохранения в энергонезависимой памяти устройства
{
Serial.println("WriteMem Function");
keys = testrom[0]; // В нулевой ячейке памяти сохраняется количество записанных ключей . Присваеваем переменной keys это значение
int n = (keys*12+2); // Переменная n соответствует значению первой свободной ячейки памяти для записи нового ключа
Serial.print("n=");
Serial.println(n);
for (int j=0; j<=11; j++) // Цикл записи байт данных в память
{
Serial.print("j=");
Serial.println(j);
int g = (n+j);
Serial.print("g=");
Serial.println(g);
testrom[g] = key[j];
}
for( int m=2; m<=13; m++)
{
Serial.print("Testrom=");
Serial.println(testrom[m]);
Serial.println(' ');
}
testrom[0]= testrom[0] + 1; // Увеличиваем ячейку памяти 0 на единицу
wrmem = true;
}
void loop()
{
currentButton = debounce(lastButton);
if (lastButton == HIGH && currentButton == LOW)
{
digitalWrite(LED_PIN, HIGH );
delay(100);
while(wrmem == 0 || CheckOk ==0)
{
ReadID();
if ( keyOk == 1)
{
CheckMem();
if ( CheckOk == 0)
{
WriteMem();
}
else
{
Serial.println("I have this key");
break;
}
}
else
{}
}
digitalWrite(LED_PIN, LOW );
}
lastButton = currentButton;
ReadID();
if ( keyOk == 1)
{
Serial.println (' ');
Serial.print("CardNumberIS:");
for (a=0; a<=11; a++)
{
Serial.print (key[a]);
}
Serial.println (' ');
CheckMem();
if ( CheckOk == 1)
{
Serial.println(' ');
Serial.print("Open Door");
digitalWrite(Relay, HIGH );
delay(2500);
digitalWrite(Relay, LOW );
}
else
{
}
}
int prekey[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int key[] = {0,0,0,0,0,0,0,0,0,0,0,0};
num = 0;
count = 0;
index = 0;
i, a, b, h =0;
keyOk = false;
CheckOk = false;
wrmem = false;
}
Может у кого есть идеи по оптимизации ?
https://www.youtube.com/watch?v=KCt7vpDJEVw
Конечно есть. Поставьте временные ограничения на открытие замка. Какое время ставить - вам решать. Оно может быть 10, 20 секунд, может быть несколько минут.
Почитайте про программный антидребезг кнопок - реализация будет той же, только временные рамки иные.
Конечно есть. Поставьте временные ограничения на открытие замка.
Т.е. ввести переменную, которая будет отсчитывать например 10 секунд с момента открытия, чтобы на это время запретить повторное открытие ?
Почитайте про программный антидребезг кнопок - реализация будет той же, только временные рамки иные.
А функция debounce не является программным антидребезгом ?
Все верно поняли. debounce и есть программный антидребезг, ведь ее еще написать надо. Вот только через delay было неверным решением ее писать. Так она блокирует выполнение программы (хоть и 5мс, но тоже время, а если поставить 10с, то программа "зависнет").
Дебажил, дебажил - совсем всё сломал ))) Буду заново переписывать код )
Последний работает совсем непойми как, работает так, как ему хочется )
#include <SoftwareSerial.h> #include <EEPROM.h> //#include <Bounce2.h> //#define BUTTON_PIN 5 #define LED_PIN 13 SoftwareSerial RfidReader(2, 3); int delaySet = 3000; int num = 0; int count = 0; int prekey[14]; int key[12]; int testrom[122]; int index = 0; int i, a, b, h; int keys =0; bool keyOk = false; bool CheckOk = false; bool wrmem = false; int switchPin = 5; int Relay = 6; boolean lastButton = HIGH; boolean currentButton = HIGH; unsigned long lastCheck ; void setup(){ Serial.begin(9600); RfidReader.begin(9600); // Setup the button with an internal pull-up : pinMode(switchPin,INPUT_PULLUP); pinMode(LED_PIN,OUTPUT); pinMode(Relay, OUTPUT); } boolean debounce(boolean last) { boolean current = digitalRead(switchPin); if (last != current) { delay(5); current = digitalRead(switchPin); } return current; } void ReadID() { count = 0; for (count =0; count <=13; count++) { if (RfidReader.available() > 0) //Если присутствуют данные со считывателя карт { Serial.print("ReadID Function"); num = RfidReader.read(); // Присваеваем переменной num первый считанный байт prekey[count] = num ; // Заполняем массив от 0 до 13 значениями полученных байт в num Serial.print("count="); Serial.println(count); Serial.print("num="); Serial.println(num, DEC); if(count >= 13) //Если считали 14 байт, .... { if (prekey[0] == 2 && prekey[13] == 3) // Если первый элемент массива равен 2 а последний 3 { keyOk = true; Serial.print ("keyOk="); Serial.print (keyOk); Serial.println (' '); Serial.print ("key="); for (a=0; a<=11; a++) { b = a+1; key[a] = prekey[b]; Serial.print (key[a]); } return; } else { Serial.print ("Key is not very" ); keyOk = false; count = 0; num =0; } Serial.println (' '); Serial.print("prekey="); for(i=0; i<=13; i++) { int x= prekey[i]; Serial.print(x); } Serial.println(' '); count = 0; } } else { count = 0; num = 0; keyOk = false; break; } } } void CheckMem () // функция проверки наличия ключа в памяти { Serial.println("CheckMem function"); keys = testrom[0]; // num - ячейка количества записанных ключей int n = keys*12+2; // n - номер первой чистой ячейки int k; int g; int j; int CheckCount =0; for (k=0; k<=(n-1); k=k+12) // цикл пересчитывает блоки ключей, каждый блок 12 байт { Serial.print("k="); Serial.println(k); for (j=0; j<=11; j++) // цикл пересчитывает, сравнивает каждый байт массива ключа и массива памяти { g = (j+k+2); // переменная указывает на нужный байт в памяти соответствующий или не соответствующий байту ключа Serial.print("key_j="); Serial.println(key[j]); Serial.print("testrom_g="); Serial.println(testrom[g]); if (key[j] == testrom[g]) // сравнение ключа с сохранённым в памяти побайтово { CheckCount ++; // прибавляет единицу если байты соответствуют друг другу Serial.print("CheckCount="); Serial.println(CheckCount); } else { CheckCount =0; // если нет совпадения в байтах, сбросить счётчик в 0 } } if (CheckCount == 12) //Если все 12 байт подряд равны, { CheckOk = true; //Меняем значение переменной в true Serial.println(' '); Serial.print("Key found in memory"); break; //Прекращаем цикл, так как такой ключ есть в памяти устройства } else { Serial.println(' '); Serial.println("key not found"); CheckOk = false; // Стафим флаг , о том что такого ключа не найдено } } } void WriteMem () // Функция сохранения в энергонезависимой памяти устройства { Serial.println("WriteMem Function"); keys = testrom[0]; // В нулевой ячейке памяти сохраняется количество записанных ключей . Присваеваем переменной keys это значение int n = (keys*12+2); // Переменная n соответствует значению первой свободной ячейки памяти для записи нового ключа Serial.print("n="); Serial.println(n); for (int j=0; j<=11; j++) // Цикл записи байт данных в память { Serial.print("j="); Serial.println(j); int g = (n+j); Serial.print("g="); Serial.println(g); testrom[g] = key[j]; } for( int m=2; m<=13; m++) { Serial.print("Testrom="); Serial.println(testrom[m]); Serial.println(' '); } testrom[0]= testrom[0] + 1; // Увеличиваем ячейку памяти 0 на единицу wrmem = true; } void loop() { currentButton = debounce(lastButton); if (lastButton == HIGH && currentButton == LOW) { digitalWrite(LED_PIN, HIGH ); delay(100); while(wrmem == 0 || CheckOk ==0) { ReadID(); if ( keyOk == 1) { CheckMem(); if ( CheckOk == 0) { WriteMem(); } else { Serial.println("I have this key"); break; } } else {} } digitalWrite(LED_PIN, LOW ); } lastButton = currentButton; ReadID(); if ( keyOk == 1) { Serial.println (' '); Serial.print("CardNumberIS:"); for (a=0; a<=11; a++) { Serial.print (key[a]); } Serial.println (' '); CheckMem(); if ( CheckOk == 1 && (lastCheck < (millis() - delaySet))) { Serial.println(' '); Serial.println("Open Door"); lastCheck = millis(); digitalWrite(Relay, HIGH ); } else { digitalWrite(Relay, LOW ); Serial.println("lastCheck > millis-delay"); } } int prekey[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int key[] = {0,0,0,0,0,0,0,0,0,0,0,0}; num = 0; count = 0; index = 0; i, a, b, h =0; keyOk = false; CheckOk = false; wrmem = false; }Да и в функциях нашел ошибки и лишние движения.
Всё исправил, вот рабочий код. Ключи пишутся в EEPROM. Ложные - повторные срабатывания устранены. Антидребезг оставил таким какой он был.
#include <SoftwareSerial.h> //подключаем библиотеку програмного последовательного порта #include <EEPROM.h> // подключаем библиотеку EEPROM // #define LED_PIN 13 #define DELAY 3000 //время задержки повторного срабатывания реле SoftwareSerial RfidReader(2, 3); // подключаем RDM6300 к пинам 2,3 bool KeyOk = false; // флаг правильного прочтения ключа int key[12]; // массив содержаший ID считанного ключа int prekey[64]; // массив данных полученный после чтения ключа // int EEPROM[64]; bool CheckOk =false; // флаг проверки ключа с имеющимся в памяти bool wrmem = false; // флаг осуществления записи в EEPROM int switchPin = 5; // кнопка на 5 пине int Relay = 6; // реле на 6 пине boolean lastButton = HIGH; // антидребезг... boolean currentButton = HIGH; // антидребезг... unsigned long lastCheck ; // задержка повторного срабатывания void setup () { Serial.begin(9600); // стартум последовательный порт RfidReader.begin(9600); // стартуем программный последовательный порт pinMode(switchPin,INPUT_PULLUP); // режим ввода с внутренней подтяжкой HIGH pinMode(LED_PIN,OUTPUT); // режим пина на вывод для светодиода pinMode(Relay, OUTPUT); // режим пина на вывод для реле } void ReadId() // Ф-ция чтения ключа { if (RfidReader.available() > 0) // Если есть данные на порту { for (int count =0; count<=63; count++) // Считываем 64 байта из буфера { int num = RfidReader.read(); // Записываем байт в переменную prekey[count] = num; // записываем байт в массив if (count >= 63) // если записали 64 байта { if (prekey[0] == 2 && prekey[13] ==3) // если первый байт равен 2, а 14 байт равен 3 (начало и конец данных получаемых с ключа) { KeyOk = true; // ключ считан верно Serial.print ("key="); for (int i=0; i<=11; i++) // выделяем ID ключа из полученного массива { int pk = i+1; key[i] = prekey[pk]; Serial.print (key[i]); } count = 0; return; } else { Serial.println (' '); Serial.print ("Bad key" ); KeyOk = false; count = 0; break; } } } } } void CheckMem () // Ф-ция проверки наличия ключа в энергонезависимой памяти { int keys = EEPROM[0]; // Количество записанных в память ключей храниться в первой ячейке памяти, вторая ячейка оставлена "про запас" int n = (keys*12+2); // первый чистый байт в энергонезависимой памяти для записи ID ключа int CheckCount =0; CheckOk = false; // ставим флаг сравнения в 0 for (int k=2; k<=(n-1); k=(k+12)) // Цикл устанавливается на начало первого блока с ключами и "переключает" по 12 байт в зависимости от количества ключей (n) { CheckCount =0; for (int j=0; j<=11; j++) // Сравнение считанного и имеющегося в памяти ключа { int f=(k+j); Serial.println(' '); Serial.print("Key="); Serial.println(key[j]); Serial.print("EEPROM="); Serial.println(EEPROM[f]); if (key[j] == EEPROM[f]) { CheckCount++; } } if (CheckCount ==12) // Если совпали все 12 байт, значит ключ найден { Serial.println("CheckOk"); CheckOk =true; // Ставим флаг сравнения в 1 break; } } } void WriteMem () // Функция записи в энергонезависимую память { int keys = EEPROM[0]; int n = (keys*12+2); for (int j=0; j<=11; j++) { int g = (n+j); EEPROM[g] = key[j]; } EEPROM[0]= EEPROM[0] + 1; Serial.println("WriteOK"); wrmem = true; } boolean debounce(boolean last) //Функция антидребезга { boolean current = digitalRead(switchPin); if (last != current) { delay(5); current = digitalRead(switchPin); } return current; } void loop () { currentButton = debounce(lastButton); if (lastButton == HIGH && currentButton == LOW) { digitalWrite(LED_PIN, HIGH ); delay(100); while(wrmem == 0) { ReadId(); if ( KeyOk == 1) { CheckMem(); if ( CheckOk == 0) { WriteMem(); Serial.print("wrmem="); Serial.println(wrmem); } else { Serial.println("I have this key"); break; } } else {} } wrmem = false; digitalWrite(LED_PIN, LOW ); } lastButton = currentButton; ReadId(); if ( KeyOk == 1) { Serial.println (' '); Serial.print("CardNumberIS:"); for (int a=0; a<=11; a++) { Serial.print (key[a]); } Serial.println (' '); CheckMem(); if ( CheckOk == 1) { if (lastCheck < (millis() - DELAY)) { Serial.println(' '); Serial.println("Open Door"); digitalWrite(Relay, HIGH ); delay (2000); digitalWrite(Relay,LOW); lastCheck = millis(); } } else { digitalWrite(Relay, LOW ); } } int key[] = {0,0,0,0,0,0,0,0,0,0,0,0}; KeyOk = false; CheckOk = false; wrmem = false; }Комменты в коде писал для себя, так что не везде они есть. )
А схемку можно замка.
был бы очень признателен
А схемку можно замка.
был бы очень признателен
да какая там схема, ридер на 2 и 3 пине, кнопка на 5, реле на 6 вот и вся схема
Спасибо.
Еше один вопрос
А как запись меток происходит
нажатием кнопки
Я даже не успеваю отвечать )))) все верно , запись происходит нажатием кнопки. Можно прикрутить механизм, чтобы был мастер ключ, прислоняете ма стен, потом новый ключ записываете
в большом коллективе клювом не щёлкают )))
привет, подскажи пожалуйста, как именно происходит запись
Здравствуйте, подскажи пожалуйста, на 131 строчки при компиляции выдаёт ошибку как исправить.и как писать ключи.пишет bad key/
и еще вопрос?вы можете поправить чтобы при считывание пин 6 сработал.а при повторном считывание пин 7.и по новой пин 6 пин 7.
Доброго дня! К сожалению ардуину в руки не брал года 3-4, подзабыл что и как там, думаю проще тебе изучить код и самому все поправить.
последний скетч не пишет ключи!!!!
кнопку нажимаешь ? добавь вывод в терминал, посмотри, что происходит
на 131 строчки при компиляции выдаёт ошибку как исправить.и как писать ключи.пишет bad key/
на 131 строчки при компиляции выдаёт ошибку
Мошт потому, что в строке "003" дефайн закоментирован?
Что делать? Не хочет писать ключ. bad key
почему закоментирована строка int EEPROM[64]; ?
Я понимаю это команда записи в епром?