Rfid causes LED to blink/RFID interfering with code

#include <Keypad.h>
#include <LiquidCrystal.h>
#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 16
#define RST_PIN 17
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

const byte ROWS = 4;
const byte COLS = 3;
int lcdRow = 0;

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {5, 4, 3, 2};
byte colsPins[COLS] = {A3, A2, A1};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colsPins, ROWS, COLS);
String password;

int ledPin = 20; // Assuming pin 20 controls an LED
int buttonPin = 26; // Assuming pin 26 is for a button

unsigned long lastButtonPressTime = 0;
bool ledOn = false;
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.

void setup() {
  Serial.begin(115200);
  lcd.begin(16, 2); // Assuming 16x2 LCD, adjust according to your setup
  lcd.print("Enter Password: ");
  delay(1000);
  lcd.clear();
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH); // Ensure LED is initially off
  pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up resistor for button
  pinMode(LED_BUILTIN, OUTPUT);
  SPI.begin();      // Initiate  SPI bus
  mfrc522.PCD_Init();   // Initiate MFRC522
}

void loop() {
  handleKeypad();
  handleButton();
  handleRfid();
}

void handleKeypad() {
  char key = keypad.getKey();

  if (key) {
    lcd.print(key);
    lcd.setCursor(++lcdRow, 0);
    password += key;

    if (key == '#') {
      lcd.clear();
      lcd.print("Checking");
      lcd.setCursor(0, 1);
      lcd.print(password);
      delay(1000);

      if (password == "111#") {
        lcd.clear();
        lcd.print("Accepted");
        delay(1000);
        digitalWrite(ledPin, LOW); // Turn on LED
        ledOn = true;
        delay(5000);
        digitalWrite(ledPin, HIGH); // Turn off LED
        ledOn = false;
        lcd.clear();
      } else {
        lcd.clear();
        lcd.print("Denied");
      }
      password = "";
    }

    if (key == '*') {
      lcd.print("Execute Order66");
      delay(1000);
      lcd.clear();
      password = "";
      lcdRow = 0; // Reset LCD row
    }
  }
}

void handleButton() {
  int buttonState = digitalRead(buttonPin);
  unsigned long currentTime = millis();

  if (buttonState == LOW && currentTime - lastButtonPressTime > 1000) {
    lastButtonPressTime = currentTime;
    digitalWrite(ledPin, LOW); // Turn off LED
    delay(5000);
    digitalWrite(ledPin, HIGH); // Turn on LED
  }
}

 void handleRfid() {
 static unsigned long lastAccessTime = 0;
  static bool accessGranted = false;
  static bool ledStateBeforeAccess = HIGH; // Assuming the LED is initially off

  // Look for new cards
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }
  // Select one of the cards
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  // Show UID on serial monitor
  Serial.print("UID tag: ");
  String content = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    content.concat(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  Serial.print("Message: ");
  content.toUpperCase();
  if (content.substring(1) == "35EB5843") { // Change here the UID of the card/cards that you want to give access
    Serial.println("Authorized access");
    if (!accessGranted) {
      ledStateBeforeAccess = digitalRead(ledPin); // Save current LED state
      digitalWrite(ledPin, LOW); // Turn off the LED
      lastAccessTime = millis();
      accessGranted = true;
    }
  } else {
    accessGranted = false;
  }

  if (accessGranted && millis() - lastAccessTime >= 5000) {
    digitalWrite(ledPin, ledStateBeforeAccess); // Restore original LED state
    accessGranted = false;
    Serial.println("Access ended");
    Serial.println("LED state restored");
  }
}

So basically I'm in highschool creating a security system using a button, Keypad, RFID, and motion sensor. I was successfully able to integrate the Button and Keypad together, but The RFID has been causing me all sorts of problems. Its continuously making the LED flash in 5 second intervals without any prompt to do so and throught my numerous tweaks its still doing the same exact thing. The code I have presented is what I beleive to be the closest to the anwser.

tldr: RFID make code no worky

Now with all that yappin out the way, I would like to ask for guidance on how to continue from this point on.

Isn't pin 13 (onboard LED), also used for SPI? It would seem so. Use some other pin for your LED.
edit - I'm probably wrong, as I see you're using an ELEGOO something, maybe a Mega, not an Uno.
It's a bit more friendly to tell us which Arduino you're using, by the way.

its the arduino ide 2.3.2, and we will try this new pin out to see if it makes a difference, thank you
and apologies for not specifying, we are still new to all of this

By which Arduino, I meant, which exact board, because the pinout for SPI, onboard LED, etc. varies.
And no, if it's a Mega or compatible, SPI pins are elsewhere, so I'm out of ideas.

Well, which LED are you referring to? The one connected to pin 20, right? If I understand your situation correctly, that LED keeps flashing with 5 seconds cycle, so you could just check the code for all the digitalWrite() function calls.

But, even if I haven't dig the whole code to check for any possible correction, if you suspect the RFID is the culprit, to double ckack that have you ever tried commeting out "handleRfid();" loop call and see what happens? can you do it now and let me know?

Apart from this, there's just one thing I noticed here:

  if (buttonState == LOW && currentTime - lastButtonPressTime > 1000) {
    lastButtonPressTime = currentTime;
    digitalWrite(ledPin, LOW); // Turn off LED
    delay(5000);
    digitalWrite(ledPin, HIGH); // Turn on LED
  }

Let's see the behaviour. You here check the button state, and if you press it (LOW) you save the current time/millis as "lastButtonPressTime ", then you turn the LED off, wait 5 seconds ("delay(5000);")and then turn it back on.
But doing so, "lastButtonPressTime" will ever be more than 1 second from "currentTime", making the LED on the next cycle to be turned off again for 5 seconds and then back on.

My general suggestion is to avoid using delays when possible, turning the code into a finite state machine, but in this case you could start by saving current time at the end of the delay, and (just my adding without knowing more about the exact code behaviour) you could/should keep it off while waiting for the button release, then turn it back on for a while):

  if (buttonState == LOW && currentTime - lastButtonPressTime > 1000) {
    digitalWrite(ledPin, LOW); // Turn off LED
    delay(5000);
    while(buttonState == LOW) delay(50);
    digitalWrite(ledPin, HIGH); // Turn on LED
    delay(500);
    lastButtonPressTime = millis();
  }

In general, it's a good idea to use Serial.println("what is supposed to change");
often through your sketch for debugging. Every led state change, every line in problematic areas to help narrow it down, that what's happening is what you intended to happen.
I like to make two copies, one with all the serial printing and a lighter one with only the ones you intend to leave in in the final project.

Yeah, but it's simpler using #define and #ifdef to let you decide if the compiler should add all the "debug stuff" needed... :wink:

2 Likes

Oh yeah? Cool, I didn't know that. I'm not a true C/C++ programmer. I'm just starting to get to the point where I'm looking for more elegant techniques in the languages that Arduino is based on. I started with Arduino knowing nothing and I'm always looking for better ways to get things done.
I'll have to look into what you said and add it to my toolbox. Thanks!

Just as an example of those "preprocessor directives", if you write:

// comment this out to stop debug outputs
#define DEBUG
...
#ifdef DEBUG
  Serial.print("data=");
  Serial.println(data);
#endif

The prints will be compiled. On the "production version" you will just comment out the #define and the compiler won't add them to output:

// comment this out to stop debug outputs
//#define DEBUG
...
#ifdef DEBUG
  // Those statements will be skipped when compiling...
  Serial.print("data=");
  Serial.println(data);
#endif

You can also use "#ifndef" to include code if that symbol has NOT been defined.
More info here:

1 Like

Sweet! Thanks! I've seen those around but never really knew when or how to use them.
gij

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.