Система контроля доступа с клавиатурой 4x3 и RFID-RC522

Привет, ребята, у меня есть система контроля доступа, отлично работающая с RFID и клавиатурой.

Я хотел бы реализовать: Если PIN-код введен неправильно более 3 раз, карта отключается.

кто-то может помочь или подсказать?

вот мой код: https://pastiebin.com/5e4c315d97d5e

#include <Keypad.h>                 // Этот скетч использует библиотеку Keypad.h
#include <SPI.h>                    // Этот скетч использует библиотеку SPI.h
#include <MFRC522.h>                // Этот скетч использует библиотеку MFRC522.h

#define SS_PIN 10                   // Определить SS_PIN считывателя RFID RC522 для цифрового контакта 10 Arduino
#define RST_PIN 9                   // Определить RST_PIN считывателя RFID RC522 для цифрового контакта 9 Arduino
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Создать экземпляр MFRC522.

int RedLed    = A3;                 // Выход красного светодиода — аналоговый контакт A3
int GreenLed  = A4;                 // Выход зеленого светодиода — аналоговый контакт A4
int Buzzer    = A5;                 // Выход зуммера — аналоговый контакт A5
unsigned long Timer;                // Переменная для таймера



const byte ROWS = 4;                // Четыре строки
const byte COLS = 3;                // Три столбца


char Keys[ROWS][COLS] = {           // Определяем символы на кнопках клавиатур
  {'1','2','3',},
  {'4','5','6',},
  {'7','8','9',},
  {'*','0','#',}
};

byte rowPins[ROWS] = {5, 4, 3, 2};  // Подключаемся к распиновке ряда клавиатуры
byte colPins[COLS] = {8, 7, 6};     // Подключаем к распиновке колонки клавиатуру
Keypad keypad = Keypad( makeKeymap(Keys), rowPins, colPins, ROWS, COLS); // Инициализировать экземпляр класса NewKeypad

int RightCard;                      // Переменная для известной карты Mifare
int RightPinCode;                   // Переменная для действительного ввода ключа в сочетании с известной картой Mifare
int WrongPinCode;                   // Переменная для неверного ввода ключа в сочетании с известной картой Mifare
int PinCodeCounter;                 // Переменная Counter для подсчета количества вводов пин-кода на клавиатуре

int Code1Correct;                   // Переменная для ввода первой правильной цифры (кода) с клавиатуры
int Code2Correct;                   // Переменная для ввода второй правильной цифры (Код) с клавиатуры
int Code3Correct;                   // Переменная для ввода третьей правильной цифры (Код) с клавиатуры
int Code4Correct;                   // Переменная для ввода четвертой правильной цифры (Код) с клавиатуры
int Code5Correct;                   // Переменная для ввода пятой правильной цифры (Код) с клавиатуры
int Code6Correct;                   // Переменная для ввода шестой правильной цифры (Код) с клавиатуры
int Reset;                          // Сброс для цикла

int MifareCard1;                               // Нам нужна эта конкретная переменная для определения действительного PIN-кода в сочетании с номером UID карты Mifare.
const int Code1MifareCard1 = '6';              // Определите здесь первую цифру вашего 6-значного PIN-кода
const int Code2MifareCard1 = '6';              // Определите здесь вторую цифру вашего 6-значного PIN-кода
const int Code3MifareCard1 = '6';              // Определите здесь третью цифру вашего 6-значного PIN-кода
const int Code4MifareCard1 = '2';              // Определите здесь четвертую цифру вашего 6-значного PIN-кода
const int Code5MifareCard1 = '2';              // Определите здесь пятую цифру вашего 6-значного PIN-кода
const int Code6MifareCard1 = '2';              // Определите здесь шестую цифру вашего 6-значного PIN-кода

int MifareCard2;                               // Нам нужна эта конкретная переменная для определения действительного PIN-кода в сочетании с номером UID карты Mifare.
const int Code1MifareCard2 = '1';              // Определите здесь первую цифру вашего 6-значного PIN-кода
const int Code2MifareCard2 = '1';              // Определите здесь вторую цифру вашего 6-значного PIN-кода
const int Code3MifareCard2 = '1';              // Определите здесь третью цифру вашего 6-значного PIN-кода
const int Code4MifareCard2 = '3';              // Определите здесь четвертую цифру вашего 6-значного PIN-кода
const int Code5MifareCard2 = '3';              // Определите здесь пятую цифру вашего 6-значного PIN-кода
const int Code6MifareCard2 = '3';              // Определите здесь шестую цифру вашего 6-значного PIN-кода





void setup() 

{  
  Serial.begin(9600);                                     // Инициализируем последовательную связь с ПК
  SPI.begin();                                            // Инициализируем шину SPI
  mfrc522.PCD_Init();                                     // Инициализируем MFRC522
  pinMode (RedLed, OUTPUT);                               // Определяем RedLed как ВЫХОД
  pinMode (GreenLed, OUTPUT);                             // Определяем GreenLed как ВЫХОД
  pinMode (Buzzer, OUTPUT);                               // Определяем зуммер как ВЫХОД
}





void loop() {   


//--------------------------------Код для функция сброса петли-------------------------------------------------------------------------- -------------------------------------------------- ----------


if (Reset == 1)                                           // Если Reset имеет значение 1 (HIGH), все переменные будут сброшены на 0, и RFID-считыватель RC522 будет ожидать новую карту Mifare.
{                                                         
  RightCard = 0;
  MifareCard1 = 0; 
  MifareCard2 = 0;                                      
  RightPinCode = 0;
  WrongPinCode = 0;
  Code1Correct = 0;
  Code2Correct = 0;
  Code3Correct = 0;
  Code4Correct = 0;
  Code5Correct = 0;
  Code6Correct = 0;
  PinCodeCounter = 0;  
  delay (50);
  Reset = 0;
}


//--------------------------------Код для контроль действительного пин-кода в течение 7 секунд после предъявления/предложения действительной карты Mifare ---------------------------


if (millis()- Timer > 7000 && RightCard == 1)            // Если таймер будет больше 7 секунд и будет предложена действующая карта Mifare, значение сброса будет высоким.
   {                                                     // Это означает, что после предъявления действительной карты у вас есть 7 секунд, чтобы ввести действительный код, или цикл сбрасывается.
    Reset = 1;
    Serial.println("CardAccesOff");
   }




//-------------------------------Чтение представил/предложил карту Mifare на MFRC522 ------------------------------------------- --------------------------------------------------------------


if   (mfrc522.PICC_IsNewCardPresent() &&                
      mfrc522.PICC_ReadCardSerial())
    { 


//--------------------------------Код для обнаружить первую карту Mifare в базе данных. Это номер UID из 4 пар цифр. Пример: 69 7C 01 9C---------------------------------------------------
     if                                                  
     (mfrc522.uid.uidByte[0] == 0x69   &&                // Заполните первые цифры номера UID вашей карты Mifare
      mfrc522.uid.uidByte[1] == 0x7C   &&                // Заполните цифры секунд номера UID вашей карты Mifare
      mfrc522.uid.uidByte[2] == 0x01   &&                // Заполните третьи цифры номера UID вашей карты Mifare
      mfrc522.uid.uidByte[3] == 0x9C)                    // Заполняем четвертые цифры номера UID вашей карты Mifare

     {
      RightCard = 1;                                     // Предлагаемая карта Mifare известна в базе данных, установите переменную "RightCard" в 1
      MifareCard1 = 1;                                   // Эта карта Mifare известна в базе данных как карта Mifare 2, поэтому установите для переменной MifareCard2 значение 1.
      digitalWrite (Buzzer, HIGH);                       // Подавать звуковой сигнал для принятой карты Mifare
      delay (150);                                       //
      digitalWrite (Buzzer, LOW);                        //

      PinCodeCounter = 0;                                // Сброс PinCodeCounter в 0
      Timer =  millis();                                 // Сброс таймера. Сейчас действует ограничение в 7 секунд для действительного пин-кода.
      Serial.println("CardAccesOn");                     // Печатаем текст "CardAccesOn" на последовательный монитор
      delay (200);                                       // Подождать 200 миллисекунд
      }


//-----------------------------------------------Код для обнаружения второй карты Mifare в базе данных. Это номер UID из 4 пар цифр. Пример: EB 70 C0 BC-------------------------------------------------------------------------- --
     if                                                    
     (mfrc522.uid.uidByte[0] == 0xEB   &&                 // Заполните первые цифры номера UID вашей карты Mifare
      mfrc522.uid.uidByte[1] == 0x70   &&                 // Заполните цифры секунд номера UID вашей карты Mifare
      mfrc522.uid.uidByte[2] == 0xC0   &&                 // Заполните третьи цифры номера UID вашей карты Mifare
      mfrc522.uid.uidByte[3] == 0xBC)                     // Заполняем четвертые цифры номера UID вашей карты Mifare

    {     
      RightCard = 1;                                       // Если предлагаемая карта Mifare известна в базе данных, установите переменную "RightCard" в 1
      MifareCard2 = 1;
      digitalWrite (Buzzer, HIGH);                         // Подавать звуковой сигнал для принятой карты Mifare
      delay (150);                                         //
      digitalWrite (Buzzer, LOW);                          //

      PinCodeCounter = 0;                                  // Сброс PinCodeCounter в 0
      Timer =  millis();                                   // Сброс таймера. Сейчас действует ограничение в 7 секунд для действительного пин-кода.
      Serial.println("CardAccesOn");                       // Печатаем текст "CardAccesOn" на последовательный монитор
      delay (200);                                         // Подождать 200 миллисекунд
    } 

    }   

//-----------------------------------------------Код для принятия действительной карты MifareCard + действительный PIN-код--------------------------------------------------------- -------------------------------------------------- -----



if (Code6Correct == 1 && RightCard == 1)                    // Если пин-код правильный и вы ввели его в течение 7 секунд
  {
    RightPinCode = 1;                                       // Переменная RightPinCode будет установлена в 1

    digitalWrite (GreenLed, HIGH);                          // Сделайте приятный звуковой сигнал для правильного PIN-кода и установите зеленый светодиод на 1 секунду
    delay (150);                                            //
    digitalWrite (Buzzer, HIGH);                            //
    delay (150);                                            //
    digitalWrite (Buzzer, LOW);                             //
    delay (50);                                             //
    digitalWrite (Buzzer, HIGH);                            //
    delay (150);                                            //
    digitalWrite (Buzzer, LOW);                             //
    delay (500);                                            //
    digitalWrite (GreenLed, LOW);                           //

    Serial.println("Correct PinCode");                      // Печатаем текст «Правильный пин-код» на последовательный монитор
    Reset = 1;                                              // Сбросить цикл
  }

//-----------------------------------------------Код за отказ от действительной карты MifareCard + неверный PIN-код--------------------------------------------------------- -------------------------------------------------- ----



if ((Code6Correct == 0) && (PinCodeCounter >= 6) && (RightCard == 1))       // Если вы предложили действующую карту Mifare, а PIN-код неверен, и вы уже ввели 6 цифровые клавиши
  {  
    WrongPinCode = 1;                                                       // Переменная WrongPinCode будет установлена в 1
    Serial.println("WrongCode");                                             // Выводим текст "WrongKey" на последовательный монитор
    Reset = 1;                                                              // Сбросить цикл
  } 


//-----------------------------------------------Код за отказ от неправильного/недействительного PIN-кода или истечения времени таймера (7 секунд)--------------------------------------------------- ----------------------------------------



if ((WrongPinCode == 1) || (millis()- Timer > 7000 && RightCard == 1))      // Если вы предложили действующую карту Mifare и ввели неправильный PIN-код или таймер (7 секунд ) истекает
  { 
    digitalWrite (Buzzer, HIGH);                                            // Сделать длинный звуковой сигнал и установить красный светодиод в ВЫСОКИЙ для неправильного кода или истечения срока действия таймера
    digitalWrite (RedLed, HIGH);                                           //
    delay(1500);                                                            //
    digitalWrite (Buzzer, LOW);                                             //
    digitalWrite (RedLed, LOW);                                             //

    Serial.println("WrongCode or Timer expired");                           // Печатаем текст "WrongCode or Timer expired" в последовательный монитор
    Reset = 1;                                                              // Сбросить цикл
  }


//-----------------------------------------------Код для подсчета вводов на клавиатуре------------------------------------------------------------------------- -------------------------------------------------- -------------



char KeyDigit = keypad.getKey();                                           // Получить DigitKey с клавиатуры

if ((RightCard == 1) &&                                                    // Если вы предложили действующую карту Mifare и на клавиатуре нажата любая клавиша DigitKey
    ((KeyDigit == '1') || 
    (KeyDigit == '2')  || 
    (KeyDigit == '3')  || 
    (KeyDigit == '4')  || 
    (KeyDigit == '5')  || 
    (KeyDigit == '6')  || 
    (KeyDigit == '7')  || 
    (KeyDigit == '8')  || 
    (KeyDigit == '9')  || 
    (KeyDigit == '0')  || 
    (KeyDigit == '*')  || 
    (KeyDigit == '#')))

    {                               
      PinCodeCounter++;                                                       // Значение PinCodeCounter +1 за каждое нажатие на любую цифровую клавишу на клавиатуре
      digitalWrite (Buzzer, HIGH);                                            // Сделать короткий звуковой сигнал для нажатия DigitKey на клавиатуре
      delay (50);                                                             //
      digitalWrite (Buzzer, LOW);                                             //
    }





//-----------------------------------------------Код для определения правильного PIN-кода для MifareCard1---------------------------------------------------------- ------------------------ -------------------------- -------------





if ((KeyDigit == Code1MifareCard1) && (RightCard == 1) && (Code1Correct == 0) && (MifareCard1 == 1))           // Если вы предложили действительную карту MifareCard1, первый PINCode и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code1Correct = 1;                                                                                        // Переменная Code1Correct установлена в 1
      return;                                                                                                  // Возврат в начало цикла
    } 

if ((KeyDigit == Code2MifareCard1) && (Code1Correct == 1) && (Code2Correct == 0) && (MifareCard1 == 1))        // Если вы предложили действительную карту MifareCard1, второй PINCode и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code2Correct = 1;                                                                                        // Переменная Code2Correct установлена в 1
      return;                                                                                                  // Возврат в начало цикла
    } 

if ((KeyDigit == Code3MifareCard1) && (Code2Correct == 1) && (Code3Correct == 0) && (MifareCard1 == 1))         // Если вы предложили действительную карту MifareCard1, третий пин-код и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code3Correct = 1;                                                                                         // Переменная Code3Correct установлена в 1
      return;                                                                                                   // Возврат в начало цикла
    } 

if ((KeyDigit == Code4MifareCard1) && (Code3Correct == 1) && (Code4Correct == 0) && (MifareCard1 == 1))         // Если вы предложили действительную карту MifareCard1, четвертый пин-код и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code4Correct = 1;                                                                                         // Переменная Code4Correct установлена в 1
      return;                                                                                                   // Возврат в начало цикла
    }  
if ((KeyDigit == Code5MifareCard1) && (Code4Correct == 1) && (Code5Correct == 0) && (MifareCard1 == 1))         // Если вы предложили действительную карту MifareCard1, пятый PIN-код и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code5Correct = 1;                                                                                         // Переменная Code5Correct установлена в 1
      return;                                                                                                   // Возврат в начало цикла
    } 

if ((KeyDigit == Code6MifareCard1) && (Code5Correct == 1) && (Code6Correct == 0) && (MifareCard1 == 1))         // Если вы предложили действительную карту MifareCard1, шестой пин-код и вы не ввели его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code6Correct = 1;                                                                                         // Переменная Code6Correct установлена в 1
      return;                                                                                                   // Возврат в начало цикла
    }




//-----------------------------------------------Код для определения правильного PIN-кода для MifareCard2---------------------------------------------------------- -------------------------------------------------- -------------





if ((KeyDigit == Code1MifareCard2) && (RightCard == 1) && (Code1Correct == 0) && (MifareCard2 == 1))              // Если вы предложили действительную карту MifareCard2, сначала PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code1Correct = 1;                                                                                           // Переменная Code1Correct установлена в 1
      return;                                                                                                     // Возврат в начало цикла
    } 

if ((KeyDigit == Code2MifareCard2) && (Code1Correct == 1) && (Code2Correct == 0) && (MifareCard2 == 1))           // Если вы предложили действительную карту MifareCard2, вторая PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code2Correct = 1;                                                                                           // Переменная Code2Correct установлена в 1
      return;                                                                                                     // Возврат в начало цикла
    } 

if ((KeyDigit == Code3MifareCard2) && (Code2Correct == 1) && (Code3Correct == 0) && (MifareCard2 == 1))           // Если вы предложили действительную карту MifareCard2, третья PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code3Correct = 1;                                                                                           // Переменная Code3Correct установлена в 1
      return;                                                                                                     // Возврат в начало цикла
    } 

if ((KeyDigit == Code4MifareCard2) && (Code3Correct == 1) && (Code4Correct == 0) && (MifareCard2 == 1))          // Если вы предложили действительную карту MifareCard2, четвертый PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code4Correct = 1;                                                                                          // Переменная Code4Correct установлена в 1
      return;                                                                                                    // Возврат в начало цикла
    }  
if ((KeyDigit == Code5MifareCard2) && (Code4Correct == 1) &&  (Code5Correct == 0) && (MifareCard2 == 1))         // Если вы предложили действительную карту MifareCard2, пятая PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code5Correct = 1;                                                                                          // Переменная Code5Correct установлена в 1
      return;                                                                                                    // Возврат в начало цикла
    } 

if ((KeyDigit == Code6MifareCard2) && (Code5Correct == 1) &&  (Code6Correct == 0) && (MifareCard2 == 1))         // Если вы предложили действительную карту MifareCard2, шестое PinCode, и вы не вводили его ранее (иначе мы конфликтуем с теми же KeyDigits)
    {
      Code6Correct = 1;                                                                                          // Переменная Code6Correct установлена в 1
      return;                                                                                                    // Возврат в начало цикла
    } 

}

большое спасибо.

, 👍1


3 ответа


2

Добавьте int passCount = '0'; в начало файла, а затем увеличивайте это значение на единицу каждый раз, когда вводится неправильный пароль (например, замените Reset = 1; с passCount ++; в строке 199) И добавьте passCount = '0' к сбросу в строке 85. И добавьте еще один оператор if для сброса цикла, если пароль был введен более 3 раз. if (passCount == 3) {Reset = 1;

Надеюсь, это поможет :-)

ИЗМЕНИТЬ:

Вы можете закомментировать/удалить оператор If в строках 222–232 if ((WrongPinCode == 1) || (millis()- Timer > 7000 && RightCard == 1)).

И добавьте свой код зуммера и светодиода в приведенный выше оператор if (тот же оператор с passCount ++; в нем). Сброс тайм-аута будет выполнен в коде в строках 108–112.

,

не работает :(, @raduken

@raduken Идея Дэвида кажется мне правильной. Но: я бы использовал int passCount = 0; вместо const int passCount = '0';. «const» делает переменную неизменной, а «0» — это не нулевая цифра, а нулевой символ, поэтому вы начинаете отсчет с «0» = 48. Точно так же вы должны сбросить переменную с помощью «passCount = 0» вместо PassCount = '0'., @Peter Paul Kiefer

не сработало, мой код зацикливается и никогда не останавливается :(, не могли бы вы мне помочь? спасибо, @raduken

@raduken Добавьте несколько выходов в стратегически важных местах. Следуйте логике и содержимому переменных вместе с ними. Потратьте некоторое время на размышления, попытайтесь понять. Это один из видов отладки., @the busybee


1

1.инициализировать глобальную переменную int failcount=0,MiFareCardMode=0;

  1. для сброса поместите его в оператор if, который проверяет количество ошибок
       if(failcount==0)
                    {reset code}```
    
  2. в этом фрагменте кода увеличьте количество отказов (строка 195:200) также добавьте оператор if, чтобы проверить, какая карта была обнаружена инициализировать глобальную переменную для установки статуса карты MiFareCardMode(0=разблокировано,1=карта1 заблокирована,2=карта2 заблокирована)
if ((Code6Correct == 0) && (PinCodeCounter >= 6) && (RightCard == 1))      
  {  
    WrongPinCode = 1;                                                        
    Serial.println("WrongCode");                                             
    Reset = 1;
    failcount++       ///здесь увеличиваем значение с каждым неверным паролем
    if (failcount>=3)
     {   if(MifareCard1==1)
              MifareCardMode=1; ///создать переменную для режима (заблокирован ИЛИ не заблокирован)
         if(MiFareCard2==1)
               MifareCardMode=2;
}                                                      
 failcount=0; } 

4. В строках 125:142 поместите их в оператор if, который проверяет переменную MiFareCardMode

       if(MiFareCardMode==0)
                 {
                    lines 125 to 142
                    }
         if(MiFareCardMode==1)
                   { Serial.println("Card 1 blocked permanently");
                    // добавить все, что вы хотите сделать после блокировки }

4. В строках 146:163 поместите их в оператор if, который проверяет переменную MiFareCardMode для карты 2

    if(MiFareCardMode==0)
          {   lines 146:163  }
    if(MiFareCardMode==2)
           {Serial.println("Card2 blocked permanently");}

,

Пожалуйста, отформатируйте свой ответ правильно, чтобы он был читаемым., @chrisl

я немного запутался, не могли бы вы поместить весь этот код в pastebin, пожалуйста? Спасибо., @raduken


1

Ваш код написан сложнее, чем должен быть, и у вас много повторяющегося кода, что затрудняет понимание и изменение кода. Итак, я сначала опишу, как сократить и обобщить ваш код. Это упростит реализацию новых функций, таких как аннулирование карты после трех неправильных вводов PIN-кода.

  • Обработка RFID-карт. В настоящее время вы используете отдельные переменные для каждой карты (например, RightCard). Все ваши операторы if должны ссылаться на эти отдельные переменные для каждой карты, что затрудняет написание повторяющегося кода. Вместо этого вы должны использовать массивы для хранения информации. См. этот фрагмент кода:

    #define MAX_CARD_N        2
    #define SERIAL_LENGTH     4
    uint8_t card_serials[MAX_CARD_N][SERIAL_LENGTH] = {
        {0x69, 0x7C, 0x01, 0x9C},
        {0xEB, 0x70, 0xC0, 0xBC}
    };
    
    #define PIN_LENGTH        6
    char card_pins[MAX_CARD_N][PIN_LENGTH] = {
        {'6','6','6','2','2','2'},
        {'1','1','1','3','3','3'}
    };
    
    int current_card = -1;
    uint8_t current_pin_position = 0;
    bool pin_correct = true;
    

    Что здесь происходит? Сначала мы устанавливаем определения для последующего использования, где мы можем централизованно установить количество карт, которые мы хотим использовать, и длину их серийных данных. Затем мы объявляем двумерный массив, в котором хранится серийный номер для каждой карты (например, в цикле). Теперь мы можем получить доступ к серийным номерам карточек с помощью простых целочисленных индексов. Затем то же самое делаем с PIN-кодами этих карт. (И объявить переменные для хранения текущего индекса карты, текущей позиции вывода и правильности вывода для последующего использования.) Мы можем реализовать функцию, которая даст нам индекс текущей сканируемой карты в наших массивах карт:

    int find_card(){
        if(mfrc522.uid.uidByte[0] == 0x00) return -1;
        for(uint8_t card_index=0; card_index < MAX_CARD_N; card_index++){
            uint8_t found_card_flag = 1;
            for(uint8_t serial_index=0; serial_index < SERIAL_LENGTH; serial_index++){
                if(card_serials[card_index][serial_index] != mfrc522.uid.uidByte[serial_index]){
                    found_card_flag = 0;
                    break;
                }
           }
           if(found_card_flag){
               return card_index;
           }
       }
       return -1;
    }
    

    Эта функция вернет -1, если отсканированный серийный номер карты не может быть найден в нашем массиве card_serials. Если он был найден, функция возвращает индекс карты. Я также добавил оператор if в начале, который запрещает находить карты с первым элементом, равным нулю, что пригодится позже (здесь я использовал только первый элемент для упрощения, но вы также можете проверить каждый из 4 последовательных байтов, если вы хотите запретить нули везде в серийном номере).

  • Организация кода. В настоящее время у вас есть множество отдельных операторов if, для каждого из которых нужны дополнительные переменные, чтобы вы могли выполнять правильный код в нужной ситуации. Лучшим подходом для чего-то подобного является конечный автомат (FSM). Это важная концепция, которая звучит сложнее, чем есть на самом деле. По сути, вы делите свой код на разные состояния, в которых должны происходить определенные вещи. Действия или определенные ситуации могут выполнять переход в другое состояние. Каждое состояние выполняет только свой собственный код. Текущее состояние хранится в переменной, называемой переменной состояния. В моем ответе на этот вопрос я уже подробно объяснял принцип (включая некоторые графики). Вы действительно должны усвоить этот принцип; это полностью изменило мой стиль кодирования в лучшую сторону.

    Я бы использовал 2 разных состояния: WAIT_FOR_CARD и WAIT_FOR_PIN, чтобы мы могли разделить код RFID и код клавиатуры. Посмотрите на этот фрагмент кода:

    enum State {WAIT_FOR_CARD, WAIT_FOR_PIN};
    State state = WAIT_FOR_CARD;
    
    void loop() {
        switch(state){
          case WAIT_FOR_CARD:
              if(mfrc522.PICC_IsNewCardPresent() &&                
                 mfrc522.PICC_ReadCardSerial()){
                  int scanned_card = find_card();
                  if(scanned_card != -1){
                      current_card = scanned_card;
                      current_pin_position = 0;
                      code_correct = true;
                      // Вставьте сюда код для правильной карты (зуммер, установка временной метки, ...)
                      state = WAIT_FOR_PIN;
                  } else {
                      // Вставьте сюда код для неправильной карты
                  }
              }
              break;
          case WAIT_FOR_PIN:
              char KeyDigit = keypad.getKey();
              if(KeyDigit != NO_KEY){
                if(KeyDigit != card_pins[current_card][current_pin_position]) pin_correct = false;
                current_pin_position++;
                if(current_pin_position >= PIN_LENGTH){
                    if(pin_correct){
                        // Вставьте сюда код для правильного пин-кода
                    } else {
                        // Вставьте сюда код неправильного пин-кода
                    }
                    current_card = -1;
                    state = WAIT_FOR_CARD;
                }
              }
              break;
        }
    }
    

    Сначала мы определяем наши состояния как enum, так как это делает код более читабельным. Затем мы объявляем переменную состояния из этого enum. В функции loop() мы используем оператор switch case для выполнения кода, соответствующего текущему состоянию. В состоянии WAIT_FOR_CARD мы постоянно сканируем новую карту. Если мы ее нашли, мы проверяем с помощью функции find_card(), сохранился ли серийный номер этой карты в нашем массиве. Если да, мы соответствующим образом устанавливаем наши переменные, выполняем необходимый код для действительной карты, а затем устанавливаем переменную состояния в следующее состояние. break выводит нас из оператора switch, но на следующей итерации цикла мы теперь выполняем другой случай (поскольку мы изменили переменную состояния). Теперь мы постоянно проверяем нажатую клавишу. Если нажатая клавиша не была той, что определена в нашем массиве PIN-кодов для текущей позиции, мы устанавливаем pin_correct в false (если каждая клавиша верна, она останется true. Если что-то неверно, ему будет присвоено значение false). Мы увеличиваем позицию ПИН-кода, а затем проверяем, достигли ли мы конца ПИН-кода, где мы решаем, был ли ПИН-код правильным или нет, делая соответствующие действия, и в конце сбрасываем нашу переменную current_card и переменная состояния. (Я не упомянул функцию тайм-аута. Когда вы поймете принцип FSM, вам будет легко добавить ее в код.)

    Этот код лучше структурирован и намного короче. Также он может легко обрабатывать расширения (больше карточек, другие функции,...). Вы можете добавить больше состояний и переходов, чтобы вставить новые функции.

  • Отключение карт при 3 неправильных вводах PIN-кода: Я предполагаю, что вы хотите, чтобы 3 неправильных ввода PIN-кода отключили RFID-карту, чтобы она больше не принималась как действительная. Для этого вы можете удалить соответствующий серийный номер из массива card_serials. Сначала нам нужно отследить количество последовательных неправильных вводов PIN-кода. Для этого я бы использовал другой массив и определение для максимального количества неправильных записей (здесь 2, поскольку 2 неправильных ввода все еще разрешены; третья неправильная запись приведет к аннулированию карты):

    uint8_t pin_strikes[MAX_CARD_N] = {0};
    #define MAX_STRIKES    2
    

    Если у нас неправильный PIN-код, вы можете увеличить этот счетчик на 1:

    pin_strikes[current_card]++;
    

    Когда у нас есть правильный PIN-код, мы хотим сбросить этот счетчик:

    pin_strikes[current_card] = 0;
    

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

    if(pin_strikes[current_card] > MAX_STRIKES){
        for(uint8_t i=0; i < SERIAL_LENGTH; i++) card_serials[current_card][i] = 0;
        current_card = -1;
    }
    

    Здесь мы должны сбросить переменную current_card, так как этот индекс больше не указывает на действительную карту . Мы можем аннулировать карту, установив серийный номер равным нулю, поскольку мы исключили все карты с нулем в первом байте в начале функции find_card().

,

Большое спасибо за ваше время и объяснение, я немного запутался, не могли бы вы поместить весь этот код в pastebin, пожалуйста? Спасибо., @raduken

@raduken Почему я должен копировать приведенный выше код в pastebin? Вы можете скопировать код из вопроса. Или вы просите полный рабочий код? Если да, то вы будете разочарованы. У меня нет полного рабочего кода. Я написал приведенные выше фрагменты исключительно для этого ответа. Это ваша часть, чтобы собрать все это вместе. Если что-то в моем ответе сбивает с толку, объясните, пожалуйста, что именно, и я постараюсь объяснить это лучше, @chrisl