замОк на RFID Reader RDM6300 + Arduino NANO

Dump
Offline
Зарегистрирован: 01.06.2015

Доброго всем здоровья !

Заморочился на тему установки домой электромеханического замка, который будет открываться ключём от подъезда. Собрал девайс, написал код. Идея была такая: По нажатию кнопки можно записать 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;
    
}

Может у кого есть идеи по оптимизации ?

 
Dump
Offline
Зарегистрирован: 01.06.2015
nevkon
Offline
Зарегистрирован: 20.01.2015

Конечно есть. Поставьте временные ограничения на открытие замка. Какое время ставить - вам решать. Оно может быть 10, 20 секунд, может быть несколько минут.

Почитайте про программный антидребезг кнопок - реализация будет той же, только временные рамки иные.

Dump
Offline
Зарегистрирован: 01.06.2015

nevkon пишет:

Конечно есть. Поставьте временные ограничения на открытие замка.

Т.е. ввести переменную, которая будет отсчитывать например 10 секунд с момента открытия, чтобы на это время запретить повторное открытие ?

nevkon пишет:

Почитайте про программный антидребезг кнопок - реализация будет той же, только временные рамки иные.

А функция debounce не является программным антидребезгом ?

nevkon
Offline
Зарегистрирован: 20.01.2015

Все верно поняли. debounce и есть программный антидребезг, ведь ее еще написать надо. Вот только через delay было неверным решением ее писать. Так она блокирует выполнение программы (хоть и 5мс, но тоже время, а если поставить 10с, то программа "зависнет").

Dump
Offline
Зарегистрирован: 01.06.2015

Дебажил, дебажил - совсем всё сломал ))) Буду заново переписывать код )

Последний работает совсем непойми как, работает так, как ему хочется )

#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;
     
}

Да и в функциях нашел ошибки и лишние движения.

Dump
Offline
Зарегистрирован: 01.06.2015

Всё исправил, вот рабочий код. Ключи пишутся в 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;
   
}

Комменты в коде писал для себя, так что не везде они есть. )

 

kuzen_a76
Offline
Зарегистрирован: 09.02.2019

А схемку можно замка.

был бы очень признателен

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kuzen_a76 пишет:

А схемку можно замка.

был бы очень признателен

да какая там схема, ридер на 2 и 3 пине, кнопка на 5, реле на 6 вот и вся схема

kuzen_a76
Offline
Зарегистрирован: 09.02.2019

Спасибо.

Еше один вопрос 

А как запись меток происходит

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

нажатием кнопки

Dump
Offline
Зарегистрирован: 01.06.2015

Я даже не успеваю отвечать )))) все верно , запись происходит нажатием кнопки. Можно прикрутить механизм, чтобы был мастер ключ, прислоняете ма стен, потом новый ключ записываете

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Dump пишет:
Я даже не успеваю отвечать )))) все верно , запись происходит нажатием кнопки. Можно прикрутить механизм, чтобы был мастер ключ, прислоняете ма стен, потом новый ключ записываете

в большом коллективе клювом не щёлкают )))