Открываем дверь: RDM6300 + Arduino nano

Тема в разделе "Глядите, что я сделал", создана пользователем Dump, 27 окт 2016.

  1. Dump

    Dump Нуб

    Доброго всем здоровья !
    Заморочился на тему установки домой электромеханического замка, который будет открываться ключём от подъезда. Собрал девайс, написал код. Идея была такая: По нажатию кнопки можно записать ID ключа в EEPROM ардуины. "Длина" ключа 14-байт. Пакет данных всегда начинается с "2" и заканчивается "3" это первый и последний байт ключа. Ну а после того, как ключи записаны , собственно можно по ним открывать замок. Ну и классика жанра: В принципе всё работает, но работает не совсем так, как нужно. Одна из основных проблем в том, что когда ключ считывается, он считывается в буфер, размер которого как я понял - 64 байта. Считывается он туда многократно, всё зависит от времени нахождения ключа в зоне катушки. Так вот отсюда начинаются проблемы: реле срабатывает ровно столько раз, сколько раз ключ был считан в буфер :( Хотя должно сработать один раз и всё. Как бы очистить этот буфер после получения одного пакета с данными ?

    Код (C++):
    #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;
       
    }
    Вместо EEPROM временно используется массив testrom[122]


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

    Максимус-Бог Убийца матрёшек

    Код (C++):
    // переменная для хранения времени последней проверки
    unsigned long lastCheking;

    //Директива задержки между срабатывания. (3 сек)
    #define DELAY 3000


    //Открытие замка
    if (lastCheking < millis() - DELAY)
    {
        //Открыть дверь
    }
     
     
    Dump нравится это.
  3. Dump

    Dump Нуб

    немного переписал код с начала. новый мне нравиться больше и работает стабильно, вроде. Дальше добавлю сюда датчик приближения для включения подъездного освещения, а так же световую и звуковую индикацию по событию ( запись ключа, чтение ключа, ключ - вражеский)

    Код (C++):
    #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;
     
    }
     
     
  4. ostrov

    ostrov Гуру

    Считали раз, отключили реакцию на считывание с обнулением буфера serial до того момента когда оно снова потребуется. Например, после закрытия двери. И что то код у вас огромный для такой простой задачи, не читал, но осуждаю.
     
  5. Максимус-Бог

    Максимус-Бог Убийца матрёшек

    Без использования сторонних библиотек.
     
  6. Dump

    Dump Нуб

    Конкретнее ? Как отключить реакцию ? я вот решил это таким способом. может это костыль. но он рабочий. есть советы , жду
     
  7. Dump

    Dump Нуб

    Это хорошо или плохо ? Мне кажется, что для меня это хорошо.
     
  8. Максимус-Бог

    Максимус-Бог Убийца матрёшек

    В качестве обучения хорошо. А для проекта не очень, т.к. тратиться время на написания велосипеда.
     
  9. ostrov

    ostrov Гуру

    Каких еще библиотек? Класс Serial? Предлагаете человеку напрямую через регистры USART писать программу?
     
  10. ostrov

    ostrov Гуру

    Самое простое - выставляете флаг, например, checkRFID. Если он true, то порт опрашивается, если false то нет. И соответственно:
    Код (C++):
    if (checkRFID) num = RfidReader.read();  
    Кстати, я бы просто опрашивал порт как стандартный Serial, этот RFID хорош тем, что просто выдает 14 байт в UART на скорости 9600, что позволяет упростить работу с ридером донельзя. Точнее, до нескольких строк.
     
  11. Dump

    Dump Нуб

    Ок! И что будет управлять этим флагом ? Что будет отвечать за то что он true или false ?

    Ну по сути , именно сам опрос, занимает несколько строк в функции ReadId. Остальное - выделение 12 байт ID ключа

    Опыта маловато, конечно, но я учусь
     
  12. ostrov

    ostrov Гуру

    12 байт выделяет цикл из 5 строк.. Побайтно сравнивается полученные данные с заданными, если все совпадает, то метка та самая. Проще всего увеличивать счетчик на 1 когда байт совпадает, если по окончании цикла счетчик == 12, то метка та самая.

    Что управляет флагом приема я не знаю, это зависит от логики программы. Когда нужно принимать данные - принимаем. Если нет, не принимаем.
     
  13. Dump

    Dump Нуб

    Флагом приёма управлять должен поднесённый ключ. В принципе сейчас у меня всё работает. Дальше будем посмотреть.
     
  14. Dump

    Dump Нуб

    А не подскажите какие библиотеки нужно использовать, чтобы написать аналогичный код , только на Си ???
    Просто я понял, что среда Ардуино - это так, поморгать светодиодом ))) В любом случае, более или менее сложный проект на ардуино, делается уже со знанием языка Си, а если так, то зачем мне использовать ардуино, когда можно запрограммировать сам контроллер
     
  15. rkit

    rkit Гуру

    Ардуино программируют на надмножестве C, если что.

    Чтобы не тратить время и деньги на изготовление своей обвязки, которая будет на 90% совпадать с ардуино.
     
  16. ostrov

    ostrov Гуру

    Про Мини на "нашем всем" стоит 100 с небольшим руб. Чаще всего нет смысла городить свой огород с обвязкой.