Arduino RFID and Keypad Lock not working

Hi Everyone
I am trying to build a door lock with an Arduino Mega,RFID RC522,and a 4x4 keypad.
The code is attached.

The above code was made by me by combining two codes:
1)The "servo_motor" code from the MFRC522 library and
2)The "PasswordKeypad" code from the Password Library

My problem is:
The RFID is working but the moment I scan a known tag,I don't get any time to type the Password.
It immediately shows wrong on the Serial monitor.The Master RFID Tag is also working.Both codes individually seem to run perfectly.
Can anyone help me with this?

Keypad_And_MFRC522.ino (22.8 KB)

try to use else if and some delay so you will have the time to enter password

I have tried delay but it still didn't work.Where should I put the else if?

articunos:
I have tried delay but it still didn't work.Where should I put the else if?

Between the if and the else obviously. SMDH

else {
      if ( findID(readCard) ) { // If not, see if the card is in the EEPROM
        lcd.clear();
        lcd.setCursor(0,1);
        lcd.print("Type Password to continue");
        Serial.println("Type Password to continue");
        checkPassword();        
      }

Between the line that says "Type Password" and the line that checks the password, 62.5ns have passed. You gotta be awful quick to get that password typed.

You should be thinking in terms of a state machine instead of linear "story-telling" code. You have a no-tag state, then a tag presented state where you wait for the password, and then a password entered state where you check it.

You should also probably consider asking the mods to move this out to the programming forum where it might get some views. NOBODY reads general discussion. And when they see coding questions here they usually assume that there's something wrong with whoever decided to put a programming question here.

Delta_G:

else {

if ( findID(readCard) ) { // If not, see if the card is in the EEPROM
        lcd.clear();
        lcd.setCursor(0,1);
        lcd.print("Type Password to continue");
        Serial.println("Type Password to continue");
        checkPassword();       
      }




Between the line that says "Type Password" and the line that checks the password, 62.5ns have passed. You gotta be awful quick to get that password typed. 

You should be thinking in terms of a state machine instead of linear "story-telling" code. You have a no-tag state, then a tag presented state where you wait for the password, and then a password entered state where you check it.

I tried adding a delay of 10 seconds and typing the correct password but it still showed Wrong on the Serial Monitor.However,I didn't understand the else if part.Can you please consider explaining it again?
I am not an expert at programming but can just write basic programs.

Delta_G:
You should also probably consider asking the mods to move this out to the programming forum where it might get some views. NOBODY reads general discussion. And when they see coding questions here they usually assume that there's something wrong with whoever decided to put a programming question here.

Sorry but how can I ask the moderator?I am new to the forum

articunos:
Sorry but how can I ask the moderator?I am new to the forum

Do you see right under this text where it says "report to moderator". Try clicking that.

articunos:
I tried adding a delay of 10 seconds and typing the correct password but it still showed Wrong on the Serial Monitor.However,I didn't understand the else if part.Can you please consider explaining it again?
I am not an expert at programming but can just write basic programs.

Sure, a delay of 10 seconds. And during that delay of ten seconds how many of the lines of code that were supposed to gather the user input for the password were able to run? That's right, delay is blocking so the password gathering code couldn't run. Now you have the line that prints, then ten seconds of the Arduino doing nothing, and then immediately check the password.

It's not going to be that simple. You're going to want to learn about that "state machine" concept I mentioned. That's how you fix this. It will be almost a complete rewrite.

Delta_G:
Sure, a delay of 10 seconds. And during that delay of ten seconds how many of the lines of code that were supposed to gather the user input for the password were able to run? That's right, delay is blocking so the password gathering code couldn't run. Now you have the line that prints, then ten seconds of the Arduino doing nothing, and then immediately check the password.

It's not going to be that simple. You're going to want to learn about that "state machine" concept I mentioned. That's how you fix this. It will be almost a complete rewrite.

So this program will have to be written from scratch all over again?
Or is there any way to modify it?

 else {
      if ( findID(readCard) ) { // If not, see if the card is in the EEPROM
        lcd.clear();
        lcd.setCursor(0,1);
        lcd.print("Type Password to continue");
        Serial.println("Type Password to continue");
        keypadEvent();        
      }

I tried adding the keypad event function over here instead of checkPassword() but it gave me a error saying:
too few arguments to function 'void keypadEvent(KeypadEvent)'
What can be done about this?

articunos:
So this program will have to be written from scratch all over again?
Or is there any way to modify it?

Did you read what I wrote? Rewriting this to a state machine will be almost a total rewrite.

With what you just showed, even if it did work, it would only get one character. You want to read in a whole password. You need loop to repeat several times while in that state. Most of those times nothing will be happening.

How did it work for this guy?
Can you explain?

Post the code he used and we will see. Surely he wrote good code is how it worked if it did indeed work.

If his worked and you use the same exact code and electrical setup then it should work the same for you. Is that what you did?

Delta_G:
Post the code he used and we will see. Surely he wrote good code is how it worked if it did indeed work.

If his worked and you use the same exact code and electrical setup then it should work the same for you. Is that what you did?

// include
#include <LiquidCrystal.h>
#include <Keypad.h>
#include <Servo.h>
#include <SPI.h>
#include <RFID.h>
 
// instance
LiquidCrystal lcd(42, 41, 35, 34, 33, 32); // LCD
Keypad myKeypad= Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols); // Clavier
Servo myservo; // Serrure
RFID rfid(53, 5); //RFID
 
 
// variables
 
// Code bonne cle : 84, 6B, 49, 2E, 88
int serNum0=0x84;
int serNum1=0x6B;
int serNum2=0x49;
int serNum3=0x2E;
int serNum4=0x88;
 
// Clavier
const byte numRows= 4;
const byte numCols= 4;
char keymap[numRows][numCols]=
{
{'1', '4', '7', '*'},
{'2', '5', '8', '0'},
{'3', '6', '9', '#'},
{'A', 'B', 'C', 'D'}
};
byte colPins[numRows] = {29,28,27,26}; //Rows 0 to 3
byte rowPins[numCols]= {25,24,23,22}; //Columns 0 to 3
 
// Temoin
int rouge = 8;
int vert = 9;
 
// ----
int index = 0;
String code;
String motdepasse;
bool testCle, testCode;
 
// setup
void setup() {
  lcd.begin(16, 2);
  SPI.begin();
  rfid.init();
 
  code = String("0000");
  motdepasse = String("1235");
 
  pinMode(rouge, OUTPUT);
  pinMode(vert, OUTPUT);
 
  lcd.clear();
 
  myservo.attach(10);
  myservo.write (20);
  lcd.write("CLE");
  testCle = false;
  testCode = false;
}
 
// loop
void loop() {
  digitalWrite(rouge,1);
  char keypressed = myKeypad.getKey();
 
// TEST bonne cle ET bon code
  if (testCode && testCle){
   
    // affichage LCD
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("CODE : ");
    lcd.print(code);
    lcd.setCursor(0, 1);
    lcd.print("CORRECT");
   
    // temoin OK
    digitalWrite(rouge,0);
    digitalWrite(vert,1);
   
    // ouverture serrure
    myservo.write (100);
    delay(5000); // attend 5 secondes
   
    // temoin PAS OK
    digitalWrite(rouge,1);
    digitalWrite(vert,0);
   
    // fermeture serrure
    myservo.write (20);
    testCle = false;
    testCode = false;
    lcd.clear();
  }
 
// TEST bonne cle ET mauvais code  
  if(testCle && !testCode){      
      lcd.setCursor(0, 0);
      lcd.print("CODE ?");
      digitalWrite (rouge,0);
      delay (200);
      digitalWrite (rouge,1);
      if (keypressed != NO_KEY) {
        lcd.setCursor(index, 1);
        lcd.print(keypressed);
        code[index] = keypressed;  
        index++;
      }
      if (index == 4) {
        index = 0;
        if (code == motdepasse) {
          // code OK
          testCode = true;
          }
         else {
          // code PAS OK
          lcd.setCursor(0, 0);
          lcd.print("CODE : ");
          lcd.print(code);
          lcd.setCursor(0, 1);
          lcd.print("INCORRECT");      
          testCode = false;
          testCle = false;
          }
        lcd.clear();
      }
  }
 
// TEST mauvaise cle  
  if (!testCle) {
  lcd.setCursor(0,0);
  lcd.print("CLE");
  if (rfid.isCard()) {
        if (rfid.readCardSerial()) {
            if (rfid.serNum[0] != serNum0
                && rfid.serNum[1] != serNum1
                && rfid.serNum[2] != serNum2
                && rfid.serNum[3] != serNum3
                && rfid.serNum[4] != serNum4
            ) {
                // cle PAS OK
                lcd.clear();
                lcd.write("CLE INCORRECT");
                delay (2000);
                lcd.clear ();
                lcd.write ("CLE");
             } else {
               // cle OK
               lcd.clear();
               testCle = true;
               }
             }
          }
 
    rfid.halt();
  }
 
}

In his example,he doesn't have a master card like in my code.Nor does he use the EEPROM.

Yes, and it isnimplemented as a sort of state machine. This is what I was implying you should do.

Delta_G:
Yes, and it isnimplemented as a sort of state machine. This is what I was implying you should do.

But how can I do it?
He isn't even using the password library

No he coded himself to read the password.

You could just copy his code.

You could spend some time learning how it works. It sounds like this project might be a little over your abilities at this point. Maybe put this one down for a bit and spend some time learning with some simpler things first.

Either way, it will be a near complete rewrite from what you have. It will be easier to start over than to fix.

I rearranged your code to show what it might look like state machine style. Each time through loop() the actions taken depend on the current state. I don't think that it would be too difficult for you to rewrite the existing code.

Eventually you'll have to think about timing out if the password is not entered quickly enough and decide what to do if someone swipes a card while the code is waiting for a password.

BTW, I don't think that you are supposed to call checkPassword() directly since it is called in keypadEvent().

const int startUp = 0;
const int waitForCard = 1;
const int gotCard = 2;
const int waitForPassword = 3;
int currentState = startUp;

///////////////////////////////////////// Main Loop ///////////////////////////////////
void loop () {

  switch ( currentState )
  {
    case startUp:

      lcd.setCursor(2, 0);
      lcd.print("Sanyog's Security");
      lcd.setCursor(8, 1);
      lcd.print("System");
      lcd.setCursor(3, 2);
      lcd.print("Tap your card to");
      lcd.setCursor(8, 3);
      lcd.print("enter");

      currentState = waitForCard;

      break;

    case waitForCard:

      successRead = getID();

      if ( successRead ) currentState = gotCard;

      break;

    case gotCard:

      if (programMode) {
        if ( isMaster(readCard) ) { //If master card scanned again exit program mode
          lcd.clear();
          lcd.setCursor(2, 0);
          lcd.print("Exiting Program Mode");
          Serial.println(F("Master Card Scanned"));
          Serial.println(F("Exiting Program Mode"));
          Serial.println(F("-----------------------------"));
          programMode = false;
        } else if ( findID(readCard) ) { // If scanned card is known delete it
          lcd.clear();
          lcd.setCursor(2, 1);
          lcd.print("This user is no longer authorized");
          Serial.println(F("I know this PICC, removing..."));
          deleteID(readCard);
          Serial.println("-----------------------------");
          delay(1000);
        } else {                    // If scanned card is not known add it
          lcd.clear();
          lcd.setCursor(2, 1);
          lcd.print("Adding a new user....");
          Serial.println(F("I do not know this PICC, adding..."));
          writeID(readCard);
          Serial.println(F("-----------------------------"));
          delay(1000);
        }
        currentState = waitForCard;
      }
  } else {
    if ( isMaster(readCard) ) {   // If scanned card's ID matches Master Card's ID enter program mode
      programMode = true;
      lcd.clear();
      lcd.setCursor(3, 0);
      lcd.print("Hello Master");
      lcd.setCursor(1, 1);
      lcd.print("Program Mode Active");
      delay(2000);
      Serial.println(F("Hello Master - Entered Program Mode"));
      int count = EEPROM.read(0);   // Read the first Byte of EEPROM that stores the number of ID's in EEPROM
      lcd.setCursor(0, 2);
      lcd.print("I have ");
      lcd.print(count);
      if (count > 1) {
        lcd.print(" records on EEPROM");
      }
      else(
          lcd.print(" record on EEPROM")
        );

      Serial.print(F("I have "));
      Serial.print(count);
      Serial.print(F(" record(s) on EEPROM"));
      Serial.println("");
      Serial.println(F("Scan a PICC to ADD or REMOVE"));
      Serial.println(F("-----------------------------"));

    } else {

      currentState = waitForCard;  // will either wait for new card or password

      if ( findID(readCard) ) { // If not, see if the card is in the EEPROM
        lcd.clear();
        lcd.setCursor(0, 1);
        lcd.print("Type Password to continue");
        Serial.println("Type Password to continue");
        currentState = waitForPassword;
      }

    }

    break;

  case waitForPassword;

    // checkPassword() gets called in keypadEvent(), set next state there
    break;

  default:
    break;

  }

}