Getting erratic behavior with RFID reader

Hey,

I'm trying to modify an alarm for an old car. From the factory it was simply disabled when the ignition was "ON", my plan is to use an RFID reader hidden somewhere in the car and make the arduino switch a relay only if the card is present (disabling the alarm and providing power to the ignition)
For realiability reasons, if the ignition has been switched "ON" while the card was present I want the system to enter a state where it can't turn "OFF" the relay unless the ignition switch is first set to "OFF".

I already made a sketch and tried it, at first it seemed to do what I wanted, if the ignition is "ON", it does what it should do (or at least it looks like it) but when it's "OFF", it does weird things.
If it's in the "OFF" position it may work for a few itterations, sometimes for 5 min straight, sometimes for 3 seconds but suddently it seems to stop detecting the tag and I can't figure out why...

I'm fairly new to coding so any help would be really appreciated, thanks

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST 9
#define CS 10
#define RELAY 8
#define CONTACT 7

int CardLastState = 0;
int ContactState = LOW;

MFRC522 mfrc522(CS, RST);


void setup() {

  pinMode(RELAY, OUTPUT);
  pinMode(CONTACT, INPUT_PULLUP);
  digitalWrite(RELAY, HIGH);

  Serial.begin(9600);
  while (!Serial);

  SPI.begin();

  mfrc522.PCD_Init();

}

void loop() {
  ContactState = digitalRead(CONTACT);

  if (mfrc522.PICC_IsNewCardPresent()) //if there's a card
  {
    if (CardLastState == 0) //if the state changed
    {
      CardLastState = 1;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }

    if (ContactState == LOW) //if there's no ignition
    {
      Serial.println("contact is off");
      delay(500);
      mfrc522.PICC_HaltA();

    }

    else if (ContactState == HIGH)//if there's ignotion
    {
      while (1)
      {
        ContactState = digitalRead(CONTACT);

        if (ContactState == LOW) //if there's no more ignition
        {
          Serial.println("contact cut off");

          delay(500);
          break; //get out of the loop
        }

        delay(500);
        Serial.println("contact is on");
      }
    }
  }

  else
  {
    if (CardLastState == 1) //if the state changed
    {
      CardLastState = 0;
      Serial.println("no card anymore");
      digitalWrite(RELAY, HIGH);
    }

    delay(500);
    Serial.println("no card");
  }
}

edit: forgot to add it but I'll add a check for the card ID later, it should not be that hard once it works like this

(I can make a diagram of the circuit if needed but it's pretty straight forward)

Somewhere you can actually place the token.

A relay means you are drawing (typical) 70 mA more than you really want when the car is not running, but I suppose you do not intend to leave it in that state.

Mind you, the RFID reader draws some current itself. Maybe not too much.

So if the code fails and the relay drops out, is the car usable?

What is that?

Did you read the instructions?

Sorry I didn't read the instructions first, I edited the post to comply

For the current consumption concern it should'nt be a problem since the car won't sit long enough to drain the battery and I don't plan to leave the relay in the "ON" state when the car isn't running, I also plan to look into reducing current consumption once the main function works.

As for the code failing, no the car wont be usable if it happens but the objective is to make it reliable enough so that it's actually usable (but I'll put some kind of switch to bypass the system for the first drives, just in case)

Hey, I just tried rewriting it (quite a few times actually) and I just can't get it to work properly, after some digging I found out a few people tried to do something similar and had similar looking issues.
Despite trying many of the different solutions I've found nothing that seems to work for me, I'm starting to suspect some hardware issues but that seems kind of strange.
If somebody could try this code and tell me if it behaves properly

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

#define SS_PIN 10
#define RST_PIN 9
 
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class

bool locked = false;

void setup() { 
  Serial.begin(9600);
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522 
  delay(4);

  // Clear the information stored about locked cards.
  rfid.uid.size = 0;

  Serial.println(F("This code scan the MIFARE Classsic NUID and reports removal."));
}

void loop() {
  // Wake up all cards present within the sensor/reader range.
  bool cardPresent = PICC_IsAnyCardPresent();
  
  // Reset the loop if no card was locked an no card is present.
  // This saves the select process when no card is found.
  if (! locked && ! cardPresent)
    return;

  // When a card is present (locked) the rest ahead is intensive (constantly checking if still present).
  // Consider including code for checking only at time intervals.

  // Ask for the locked card (if rfid.uid.size > 0) or for any card if none was locked.
  // (Even if there was some error in the wake up procedure, attempt to contact the locked card.
  // This serves as a double-check to confirm removals.)
  // If a card was locked and now is removed, other cards will not be selected until next loop,
  // after rfid.uid.size has been set to 0.
  MFRC522::StatusCode result = rfid.PICC_Select(&rfid.uid,8*rfid.uid.size);

  if(!locked && result == MFRC522::STATUS_OK)
  {
    locked=true;
    // Action on card detection.
    Serial.print(F("locked! NUID tag: "));
    printHex(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
  } else if(locked && result != MFRC522::STATUS_OK)
  {
    locked=false;
    rfid.uid.size = 0;
    // Action on card removal.
    Serial.print(F("unlocked! Reason for unlocking: "));
    Serial.println(rfid.GetStatusCodeName(result));
  } else if(!locked && result != MFRC522::STATUS_OK)
  {
    // Clear locked card data just in case some data was retrieved in the select procedure
    // but an error prevented locking.
    rfid.uid.size = 0;
  }

  rfid.PICC_HaltA();
}

/**
 * Helper routine to dump a byte array as hex values to Serial. 
 */
void printHex(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(((buffer[i])>>4)&0x0F,  HEX);
    Serial.print(buffer[i]&0x0F, HEX);
    Serial.print(" ");
  }
}

// This convenience function could be added to the library in the future

/**
 * Returns true if a PICC responds to PICC_CMD_WUPA.
 * All cards in state IDLE or HALT are invited.
 * 
 * @return bool
 */
bool PICC_IsAnyCardPresent() {
  byte bufferATQA[2];
  byte bufferSize = sizeof(bufferATQA);
  
  // Reset baud rates
  rfid.PCD_WriteRegister(rfid.TxModeReg, 0x00);
  rfid.PCD_WriteRegister(rfid.RxModeReg, 0x00);
  // Reset ModWidthReg
  rfid.PCD_WriteRegister(rfid.ModWidthReg, 0x26);
  
  MFRC522::StatusCode result = rfid.PICC_WakeupA(bufferATQA, &bufferSize);
  return (result == MFRC522::STATUS_OK || result == MFRC522::STATUS_COLLISION);
} // End PICC_IsAnyCardPresent()

This example code comes from here:

(on my setup it works fine the first few times but after, maybe 5-10 reads it stops working, sometimes it just stops while a card is on the sensor)

PS: It is getting kind of late where I live (2A.M.) so I'll edit this post tomorrow so that the code is directly accessible from it and you don't have to go to GitHub, I'll also probably make an other post with an "updated" piece of my code (or just edit the original)

edit: by make an other post I meant a new message, sorry for the confusion

Don't do that or the moderators will have to re-join it to this and issue you with a warning! :astonished:

And don't edit earlier posts (except to properly post code :+1:) as that may make following ones sound like nonsense. Just add what you need.

Thank you for editing to include your code. I may or may not be able to check out your new version. While there is some serious work I need to do with it and a couple of modules are sitting in a container right in front of me, (they are not the only things on my desk and) the MFRC522 is not my current project. :cold_sweat:

Thanks a lot,

So there's a part of my code, I removed the part that work correctly (when the ignition's on because I'm not checking the card's presence during that phase)

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST 9
#define CS 10
#define RELAY 8
#define CONTACT 7

bool CardLastState = false;
int ContactState = LOW;

bool lastPresenceState = false;
int absence_count = 0;

MFRC522 mfrc522(CS, RST);

void ContactOFF();

bool PICC_IsAnyCardPresent();

void setup() {

  pinMode(RELAY, OUTPUT); //set to LOW to activate
  pinMode(CONTACT, INPUT_PULLUP); //this will have to change to PULLDOWN
  digitalWrite(RELAY, HIGH); //makes sure relay's OFF

  Serial.begin(9600);
  while(!Serial);

  SPI.begin();

  mfrc522.PCD_Init();
  delay(4);
  mfrc522.uid.size = 0; // Clear the information stored about lastPresenceState cards

}

void ContactOFF()
{
  absence_count = 0; //reset the counter

  while(1)
  {
    ContactState = digitalRead(CONTACT);
    bool cardPresent = PICC_IsAnyCardPresent();

    if (! cardPresent && ! lastPresenceState) //no card detected 2 consecutive times
    {
      Serial.println("counter ++");
      absence_count++;
    }

    else if (cardPresent && absence_count != 0) //reset the counter
    {
      Serial.println("counter reset");
      absence_count = 0;
    }

    if (absence_count > 2) //get back to main the loop
    {
      Serial.println("getting out");

      mfrc522.PICC_HaltA();
      mfrc522.PCD_StopCrypto1();
      break;
    }

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
    
    lastPresenceState = cardPresent;

    Serial.print("there's a card, ");
    Serial.println("ignition's OFF");

    delay(1000);
  }
}

void loop() {
  
  ContactState = digitalRead(CONTACT);

  bool cardPresent = PICC_IsAnyCardPresent();

  if (! cardPresent) //if there's no card
  {
    if(CardLastState) //if the card got removed
    {
      CardLastState = false;
      Serial.println("no card anymore");
      digitalWrite(RELAY, HIGH); //switch the relay OFF
    }

    Serial.println("there's no card");
    mfrc522.PICC_HaltA();
    delay(500);
    return; //reset the loop
  }

//if a card has been detected

  else if (ContactState == LOW)
  {
    if (! CardLastState) //if a card has been placed
    {
      CardLastState = true;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }

    ContactOFF();
  }
  
  mfrc522.PICC_HaltA();
}


bool PICC_IsAnyCardPresent() {
  byte bufferATQA[2];
  byte bufferSize = sizeof(bufferATQA);
  
  // Reset baud rates
  mfrc522.PCD_WriteRegister(mfrc522.TxModeReg, 0x00);
  mfrc522.PCD_WriteRegister(mfrc522.RxModeReg, 0x00);
  // Reset ModWidthReg
  mfrc522.PCD_WriteRegister(mfrc522.ModWidthReg, 0x26);
  
  MFRC522::StatusCode result = mfrc522.PICC_WakeupA(bufferATQA, &bufferSize);
  return (result == MFRC522::STATUS_OK || result == MFRC522::STATUS_COLLISION);
}

Is that a full functioning code?

If not, I don't think you are going to make friends here with snippets! :roll_eyes:

Yes it is fully functionning, I just forgot to remove the check for ignition.
But here's the full code anyway

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST 9
#define CS 10
#define RELAY 8
#define CONTACT 7

bool CardLastState = false;
int ContactState = LOW;

bool lastPresenceState = false;
int absence_count = 0;

MFRC522 mfrc522(CS, RST);

void ContactOFF();
void ContactON();

bool PICC_IsAnyCardPresent();

void setup() {

  pinMode(RELAY, OUTPUT); //set to LOW to activate
  pinMode(CONTACT, INPUT_PULLUP); //this will have to change to PULLDOWN
  digitalWrite(RELAY, HIGH); //makes sure relay's OFF

  Serial.begin(9600);
  while(!Serial);

  SPI.begin();

  mfrc522.PCD_Init();
  delay(4);
  mfrc522.uid.size = 0; // Clear the information stored about lastPresenceState cards

}

void ContactOFF()
{
  absence_count = 0; //reset the counter

  while(1)
  {
    ContactState = digitalRead(CONTACT);
    bool cardPresent = PICC_IsAnyCardPresent();

    if (! cardPresent && ! lastPresenceState) //no card detected 2 consecutive times
    {
      Serial.println("counter ++");
      absence_count++;
    }

    else if (cardPresent && absence_count != 0) //reset the counter
    {
      Serial.println("counter reset");
      absence_count = 0;
    }

    if (absence_count > 2) //get back to main the loop
    {
      Serial.println("getting out");

      mfrc522.PICC_HaltA();
      mfrc522.PCD_StopCrypto1();
      break;
    }

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();

    
    if (ContactState == HIGH) //switch to the other loop
    {
      ContactON();
    }    
    
    
    lastPresenceState = cardPresent;

    Serial.print("there's a card, ");
    Serial.println("ignition's OFF");

    delay(1000);
  }
}

void ContactON()
{
  while (ContactState == HIGH)
  {
    ContactState = digitalRead(CONTACT);

    Serial.print("there's a card, ");
    Serial.println("ignition's ON");
    delay(500);
  }
}

void loop() {
  
  ContactState = digitalRead(CONTACT);

  bool cardPresent = PICC_IsAnyCardPresent();

  if (! cardPresent) //if there's no card
  {
    if(CardLastState) //if the card got removed
    {
      CardLastState = false;
      Serial.println("no card anymore");
      digitalWrite(RELAY, HIGH); //switch the relay OFF
    }

    Serial.println("there's no card");
    mfrc522.PICC_HaltA();
    delay(500);
    return; //reset the loop
  }

//if a card has been detected

  if (ContactState == HIGH)
  {
    if (! CardLastState) //if a card has been placed
    {
      CardLastState = true;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }
    
    ContactON();
  }
  

  else if (ContactState == LOW)
  {
    if (! CardLastState) //if a card has been placed
    {
      CardLastState = true;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }

    ContactOFF();
  }
  
  mfrc522.PICC_HaltA();
}

bool PICC_IsAnyCardPresent() {
  byte bufferATQA[2];
  byte bufferSize = sizeof(bufferATQA);
  
  // Reset baud rates
  mfrc522.PCD_WriteRegister(mfrc522.TxModeReg, 0x00);
  mfrc522.PCD_WriteRegister(mfrc522.RxModeReg, 0x00);
  // Reset ModWidthReg
  mfrc522.PCD_WriteRegister(mfrc522.ModWidthReg, 0x26);
  
  MFRC522::StatusCode result = mfrc522.PICC_WakeupA(bufferATQA, &bufferSize);
  return (result == MFRC522::STATUS_OK || result == MFRC522::STATUS_COLLISION);
}

edit: I might have got things mixed up in this one, I tried a previous version of this code (without the PICC_IsAnyCardPresent() function) and it seemed to work.
I'll do some test in the afternoon and come back to report but it might've just been that I was underestimating the coil's power draw trying to power it through the arduino, might be time to finally get that old PSU I've had lying around to use

This version seems to work properly (-ish), might have been partly due to powering the coil from the arduino but I'm not convinced.
(still powering it from an external source can't hurt, especially because that's how it's going to be when in the car)

I still have a weird issue that I haven't yet looked into, if the card isn't present when powering/resetting the board it won't detect it, but if it is present while resetting it works as intended, detecting removal and everything.

I'll stress test the system as it is to make sure it's stable and try to resolve the issue on startup, obviously comming back here to report if I find the solution.
Help would be appreciated but as I've yet to look for the "new" issue it might be pretty simple.

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>

#define RST 9
#define CS 10
#define RELAY 8
#define CONTACT 7

bool CardLastState = false;
int ContactState = LOW;

MFRC522 mfrc522(CS, RST);

void ContactOFF();
void ContactON();

bool PICC_IsAnyCardPresent();
void printHex(byte *buffer, byte bufferSize); //useless here

void setup() {

  pinMode(RELAY, OUTPUT); //set to LOW to activate
  pinMode(CONTACT, INPUT_PULLUP); //this will have to change to PULLDOWN
  digitalWrite(RELAY, HIGH); //makes sure relay's OFF

  Serial.begin(9600);
  while(!Serial);

  SPI.begin();

  mfrc522.PCD_Init();
  delay(4);
  mfrc522.uid.size = 0; // Clear the information stored about lastPresenceState cards

}

void ContactOFF()
{ 
  int count = 0;

  while (1)
  {
    ContactState = digitalRead(CONTACT);

    bool cardPresent = PICC_IsAnyCardPresent();

    if(! CardLastState && ! cardPresent)
    {
      count++;
      Serial.println(count);
    }

    else if (cardPresent && count != 0)
    {
      Serial.println("count reset");
      count = 0;
    }

    if (count >2)
    {
      break;
    }

    if (ContactState == HIGH)
    {
      Serial.println("contact switched ON");
      delay(1000);
      ContactON();
    }

    CardLastState = cardPresent;

    Serial.print("there's a card, ");
    Serial.println("ignition's OFF");
    delay(500);
  }

    CardLastState = false;
    Serial.println("the card has been removed");
    digitalWrite(RELAY, HIGH); //switch the relay OFF

}

void ContactON()
{
  while (ContactState == HIGH)
  {
    ContactState = digitalRead(CONTACT);

    Serial.print("there's a card, ");
    Serial.println("ignition's ON");
    delay(500);
  }

  Serial.println("contact switched OFF");
  delay(1000);

}

void loop()
{
ContactState = digitalRead(CONTACT);

  bool cardPresent = PICC_IsAnyCardPresent();

  if (! cardPresent) //if there's no card
  {
    if(CardLastState) //if the card got removed
    {
      CardLastState = false;
      Serial.println("the card has been removed");
      digitalWrite(RELAY, HIGH); //switch the relay OFF
    }

    Serial.println("there's no card");
    mfrc522.PICC_HaltA();
    delay(500);
    return; //reset the loop
  }

//if a card has been detected

  else if (ContactState == HIGH)
  {
    if (! CardLastState) //if a card has been placed
    {
      CardLastState = true;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }

    ContactON();
  }

  else if (ContactState == LOW)
  {
    if (! CardLastState) //if a card has been placed
    {
      CardLastState = true;
      Serial.println("a wild card appeared!");
      digitalWrite(RELAY, LOW);
      delay(500);
    }

    ContactOFF();
  }
  
  mfrc522.PICC_HaltA();
}

void printHex(byte *buffer, byte bufferSize)  //useless here 
{
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(((buffer[i])>>4)&0x0F,  HEX);
    Serial.print(buffer[i]&0x0F, HEX);
    Serial.print(" ");
  }
}

bool PICC_IsAnyCardPresent() {
  byte bufferATQA[2];
  byte bufferSize = sizeof(bufferATQA);
  
  // Reset baud rates
  mfrc522.PCD_WriteRegister(mfrc522.TxModeReg, 0x00);
  mfrc522.PCD_WriteRegister(mfrc522.RxModeReg, 0x00);
  // Reset ModWidthReg
  mfrc522.PCD_WriteRegister(mfrc522.ModWidthReg, 0x26);
  
  MFRC522::StatusCode result = mfrc522.PICC_WakeupA(bufferATQA, &bufferSize);
  return (result == MFRC522::STATUS_OK || result == MFRC522::STATUS_COLLISION);
}

I have looked more into it and the problem seems to come from the library I'm using, I've found an alternative and it works absolutely fine (the code is almost the same).
Still it's really weird and the alternative seems to be less complete (might be ok for what I'm doing tho).
The exact issue now (with the first library) is that when starting the program with the card present it detects it and works fine afterwards, I also have a small tag, with it it works just fine unless I start the arduino, wait a bit and present the card first, if I start the arduino with the tag or the card present it works with both.

The library I'll probably end up using:

The one I was using:

I might look more into it later, it's kind of frustrating not finding out what the issue is

Ok, so I don't know what it is but the problem has to do with later versions of the library (1.4.X) but it'll work up to version 1.3.6 (still don't know why I had not tried this before...).

It's a cheap module I bought on Aliexpress (~4€ I think), I'm joining pictures of it, just in case someone has a similar issue and finds this thread.


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