1

I recently bought an MFRC522 RFID module to use with my Arduino Uno, which came as a kit with a couple of MiFare 1K cards.

The issue I've been having is that, I cannot scan cards consecutively (the same card or two different ones) without resetting the Sketch. I hold a card in front of the reader and it is scanned, but when I hold another card in front of the reader it just doesn't recognize it as being there in the mfrc522.PICC_IsNewCardPresent() function. It does however work when using the example sketch "DumpInfo".

Here is the code I've written (please excuse any of my bad practices/untidiness).

/* Include Required Libraries */
#include <MFRC522.h>
#include <SPI.h>

/* Define Values for MFRC522 */
#define RST_PIN 9
#define SS_PIN 10

/* Instantiate the MFRC522 Object */
MFRC522 mfrc522(SS_PIN, RST_PIN);

/* Initialize Variables */
byte resultBuffer[18];
MFRC522::MIFARE_Key key;
unsigned int integerValue = 0;
char incomingByte;

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  mfrc522.PCD_Init();
  Serial.println(F("Ready to scan card..."));

  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }
}

void loop()
{
  if (!mfrc522.PICC_IsNewCardPresent())
  {
    if (Serial.available() <= 0)
    {
      return;
    }

    integerValue = 0;
    while(true)
    {
      incomingByte = Serial.read();
      if (incomingByte == '\n') break;
      if (incomingByte == -1) continue;
      integerValue *= 10;
      integerValue = ((incomingByte - 48) + integerValue);
    }

    printHeader();
    Serial.println("NEW BLOCK READ VALUE :");
    Serial.println(integerValue);
  }

  if (!mfrc522.PICC_ReadCardSerial())
  {
    return;
  }

  readAndPrint(integerValue);
}

void printHeader()
{
  Serial.println(" ");
  Serial.println("----------------------------------------");
}

int authenticateKeyA(int blockNumber)
{
  printHeader();
  Serial.println("Authenticating with key A...");

  int largestModulo4Number = blockNumber / 4 * 4;
  int trailerBlock = largestModulo4Number + 3;

  byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));

  if (status != MFRC522::STATUS_OK)
  {
    Serial.println("ERROR : Authentication was unsuccessful.");
    return 0;
  }
  else
  {
    Serial.println("SUCCESS : Authentication was successful.");
    return 1;
  }
}

int authenticateKeyB(int blockNumber)
{
  printHeader();
  Serial.println("Authenticating with key B...");

  int largestModulo4Number = blockNumber / 4 * 4;
  int trailerBlock = largestModulo4Number + 3;

  byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));

  if (status != MFRC522::STATUS_OK)
  {
    Serial.println("ERROR : Authentication was unsuccessful.");
    return 0;
  }
  else
  {
    Serial.println("SUCCESS : Authentication was successful.");
    return 1;
  }
}

int readBlock(int blockNumber, byte *resultBuffer)
{
  printHeader();
  Serial.println("Starting read block function...");

  int authSuccess = authenticateKeyA(blockNumber);
  Serial.println(" ");

  if (!authSuccess)
  {
    Serial.println("ERROR : Terminating function.");
    return 0;
  }

  byte bufferSize = 18;

  byte status = mfrc522.MIFARE_Read(blockNumber, resultBuffer, &bufferSize);

  if (status != MFRC522::STATUS_OK)
  {
    Serial.println("ERROR : Read failed.");
    return 0;
  }
  else
  {
    Serial.print("SUCCESS : Block ");
    Serial.print(blockNumber);
    Serial.print(" was read successfully.");
    return 1;
  }

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

void readAndPrint(int blockNumber)
{
  readBlock(blockNumber, resultBuffer);

  printHeader();
  Serial.println("RESULT :");
  for (int j=0 ; j<16 ; j++)
  {
   Serial.print(resultBuffer[j], HEX);
   Serial.print(" ");
  }
  Serial.println(" ");

  delay(2000);
  printHeader();
  Serial.println("Ready to scan card...");
}

Before scanning the card for the first time, the serial output looks like this :

First capture of serial monitor.

After scanning the card for the first time, the serial output looks like this :

Second capture of serial monitor.

After scanning the card for the second time, the serial output doesn't change from image 2. I tried running Serial.println("no card detected"); when the code inside if (!mfrc522.PICC_IsNewCardPresent()) is ran, just to check if the program was frozen (I'd heard someone else had an issue where the program froze after scanning the first card) - it wasn't frozen, both before and after scanning the first card, it printed out 'no card detected' repeatedly.

I would greatly appreciate any help as I have no clue as to how I should proceed.

Cheers,

4
  • What is printed in the serial monitor? Post the image in your question. Commented Jun 20, 2016 at 15:11
  • @TisteAndii Images have been added to the question. Cheers
    – fpackard
    Commented Jun 22, 2016 at 2:31
  • Do not return from 'loop()', it should loop forever.
    – aaa
    Commented Jun 23, 2016 at 8:45
  • If you return it still loops.
    – Nick Gammon
    Commented Oct 21, 2016 at 5:51

1 Answer 1

1

The correct condition, for what you intend, should be if (mfrc522.PICC_IsNewCardPresent()), so that the code in the IF block is run when a card is present, though this isn't the best structure. Like you discovered, your program isn't frozen. One of the 2 return statements (I'm not sure which) is causing it to abort loop() before calling readAndPrint(). With your current code:

  • the first return will always be executed whenever no card is detected. Since you don't seem to be sending anything with the Serial monitor, Serial.available() will return 0 and so loop() returns.
  • The second return will be executed if the reader fails to obtain the UID of the card with a SELECT. The SELECT will fail only if you don't first call PICC_RequestA() for 'new' cards (just coming within range), or PICC_WakeupA() for HALTed cards (cards already within range but sleeping).

I don't know if you're trying different cards or just one. If its just one card, you may have to take it out of range and then bring it within range again for the reader to detect it a second time. But, if you want to read the card's data more than once, without taking it out of range, you have to call PICC_WakeupA() instead of PICC_IsNewCardPresent() since, as the names indicate, you're waking a sleeping card, not detecting a new card entirely. Also structure your loop() like this:

void loop(){
  if (!mfrc522.PICC_IsNewCardPresent()) {  // replace the condition with PICC_WakeupA()   
    return;  // if you dont want the card to leave the reader's range
  }

  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  // all the code that should be executed if a card has been detected and its UID read

}

However, there's usually little sense in HALTing a card and then waking it in the very next iteration, so you might want to do all the sector reading and writing at once, HALT the card, and then wait for a new card to enter the field; at least that's what's desired in most applications.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.