miguelbalboa / rfid

Arduino RFID Library for MFRC522
The Unlicense
2.77k stars 1.44k forks source link

Improvement: Detection of tag removal #352

Closed metamorphious closed 6 years ago

metamorphious commented 6 years ago

Not sure where to post.. but here is my solution for detection of a removed RFID tag. May not be the optimal solution but works for me. Maybe it helps someone or can be added to the library somehow.

Step 1: Describe your environment

Relevant Code:

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

#define RST_PIN         9          // Configurable, see typical pin layout above
#define SS_PIN          10         // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance

bool rfid_tag_present_prev = false;
bool rfid_tag_present = false;
int _rfid_error_counter = 0;
bool _tag_found = false;

void setup() {
    Serial.begin(9600);     // Initialize serial communications with the PC
    while (!Serial);        // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
    SPI.begin();            // Init SPI bus
    mfrc522.PCD_Init();     // Init MFRC522
}

void loop() {
  rfid_tag_present_prev = rfid_tag_present;

  _rfid_error_counter += 1;
  if(_rfid_error_counter > 2){
    _tag_found = false;
  }

  // Detect Tag without looking for collisions
  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_RequestA(bufferATQA, &bufferSize);

  if(result == mfrc522.STATUS_OK){
    if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue   
      return;
    }
    _rfid_error_counter = 0;
    _tag_found = true;        
  }

  rfid_tag_present = _tag_found;

  // rising edge
  if (rfid_tag_present && !rfid_tag_present_prev){
    Serial.println("Tag found");
  }

  // falling edge
  if (!rfid_tag_present && rfid_tag_present_prev){
    Serial.println("Tag gone");
  }
}
Rotzbua commented 6 years ago

Good point. In theory we have a wiki. It would be good if we can collect such code snippets there. I would prefer the wiki over a new example because your code do not have serial output where you can interactively "see" the code "working". And we already have a lot of examples ;).

I created a new page for useful code snippets: https://github.com/miguelbalboa/rfid/wiki/Useful-code-snippets

I moved your code here: https://github.com/miguelbalboa/rfid/wiki/Useful-code-snippets#detection-of-tag-removal

@metamorphious Ok for you or should I revert it?

metamorphious commented 6 years ago

Thats fine. Just wanted to share my solution if others have the same problem.

Shogun1978 commented 6 years ago

Great solution! Exactly what I need! But I have a short question: I am new to Arduino programming and testing with a nodeMCU. I would like to build some kind of switch. If a NFC/RFID tag or phone (with NFC) is on the sensor, it should send an "on" signal in MQTT. When the tag/phone is removed, it should send an "off" signal via MQTT. Do I need to put the code in the original code from omersiar? And which parts do I need to exchange? It would be great to have some kind of setting in the web interface, what and when a signal will be send. I want to realize a "switch" at the bed. If the phone is placed near the bed, my smart home will be set in sleep/night mode.

metamorphious commented 6 years ago

I tried to post a complete example. So the code above should be enough. Just add your MQTT code inside the corresponding if-statements where the presence of a tag is printed.

Shogun1978 commented 6 years ago

Thank you for the example. I am really new to Arduino programing but figured out a solution and it's already working. Right now it works with RFID tags and NFC in smartphones. The smartphone I tested with changes it's code every minute, so I get a off/on every minute when the smartphone is still placed on the reader. I try to find a solution for that. When everything is ready and working I can share the complete set here (no user logging etc.).

Shogun1978 commented 6 years ago

Update: made it work. It is possible to use the RFID reader in switch and touch mode. Switch: sends "ON" over MQTT when tag is placed on the reader and "OFF" when it is removed Touch: sends "ON" when a tag is placed and removed for the first time and "OFF" at the second time. I will try to share the code as official branch, but I'm very new to Github. So I need some assistance, how to correctly place the code here. Thank you for the snippet, it helped me solve my problem.

mpbejo commented 6 years ago

Hi everybody, from several days I try to find a solution to detect if a card is present or not, and when is detected I need to read a block after the authentication. With your sample i see that when a card is present the if(result == mfrc522.STATUS_OK) is 0 and 3 alternatively. but when i add my istructions to read the sector only the firdt time i have 0 after the read sector i have always 3 so the card result gone. Really I do not understand how to solve below my Sketch. Thank You very much Best Regards Marco


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

#define RST_PIN         22          // Configurable, see typical pin layout above
#define SS_PIN          5         // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance
MFRC522::MIFARE_Key key;

bool rfid_tag_present_prev = false;
bool rfid_tag_present = false;
int _rfid_error_counter = 0;
bool _tag_found = false;

void setup() {
  Serial.begin(9600);   // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init();   // Init MFRC522
  // Prepare the key (used both as key A and as key B)
    // using FFFFFFFFFFFFh which is the default at chip delivery from the factory
    for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = 0xFF;
    }
}

void loop() {

  delay(1000);
  rfid_tag_present_prev = rfid_tag_present;

  _rfid_error_counter += 1;
  if(_rfid_error_counter > 2){
    _tag_found = false;
  }

  // Detect Tag without looking for collisions
  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_RequestA(bufferATQA, &bufferSize);
  Serial.print("result: ");
  Serial.println(result);
  if(result == mfrc522.STATUS_OK){
    if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue   
      return;
    }
    _rfid_error_counter = 0;
    _tag_found = true;        
  }

  rfid_tag_present = _tag_found;

  // rising edge
  if (rfid_tag_present && !rfid_tag_present_prev){
    Serial.println("Tag found");

    Serial.print(F("Card UID:"));
    dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
    Serial.println();
    /*
    Serial.print(F("PICC type: "));
    MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
    Serial.println(mfrc522.PICC_GetTypeName(piccType));

    // Check for compatibility
    if (    piccType != MFRC522::PICC_TYPE_MIFARE_MINI
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println(F("This sample only works with MIFARE Classic cards."));
        return;
    }
    */
      byte sector         = 1;
      byte blockAddr      = 4;
      byte dataBlock[]    = {
        0x01, 0x02, 0x03, 0x04, //  1,  2,   3,  4,
        0x05, 0x06, 0x07, 0x08, //  5,  6,   7,  8,
        0x09, 0x0a, 0xff, 0x0b, //  9, 10, 255, 11,
        0x0c, 0x0d, 0x0e, 0x0f  // 12, 13, 14, 15
      };
      byte trailerBlock   = 7;
      byte buffer[18];
      byte size = sizeof(buffer);

    // Authenticate using key A
    Serial.println(F("Authenticating using key A..."));

    result = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
    if (result != MFRC522::STATUS_OK) 
    {
        Serial.print(F("PCD_Authenticate() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(result));
    }

    result = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
    if (result != MFRC522::STATUS_OK) {
        Serial.print(F("MIFARE_Read() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(result));
    }
    Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
    dump_byte_array(buffer, 16); Serial.println();
    Serial.println();

     // Halt PICC
    mfrc522.PICC_HaltA();
    // Stop encryption on PCD
    mfrc522.PCD_StopCrypto1();
  }

  // falling edge
  if (!rfid_tag_present && rfid_tag_present_prev){
    Serial.println("Tag gone");
  }
}

/**
 * Helper routine to dump a byte array as hex values to Serial.
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
    for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
    }
}
mpbejo commented 6 years ago

Well, I have found a workaround for now, I don't like it but it works! After the istruction mfrc522.PCD_StopCrypto1(); mfrc522.PCD_Reset(); delay(100); mfrc522.PCD_Init(); // Init MFRC522

I hope somebody find a better solution without a reset.

Quarx64 commented 5 years ago

Good workaround, the reader hangs no more after a CRC Error.

oliviereising commented 4 years ago

Hey your code almost works perfectly for me, the only issue i'm having now is the following: When i'm reading the first NFC tag it reads this tag and serial prints hydro, after I remove it it prints Tag gone but when I place the second NFC tag on top of the reader it still prints "hydro" only after I remove the second tag and place it on top of the reader again it serial prints "bio". It's the same problem other way around.

Do you have a clue whats going on here and why it's not serial printing the sentence associated with that specific tag at the first "read out"

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

#define RST_PIN         5          // Configurable, see typical pin layout above
#define SS_PIN          4         // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance

bool rfid_tag_present_prev = false;
bool rfid_tag_present = false;
int _rfid_error_counter = 0;
bool _tag_found = false;

void setup() {
  Serial.begin(9600);   // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init();   // Init MFRC522
}

void loop() {
  String content = "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {

    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  content.toUpperCase();

  rfid_tag_present_prev = rfid_tag_present;

  _rfid_error_counter += 1;
  if (_rfid_error_counter > 2) {
    _tag_found = false;
  }

  // Detect Tag without looking for collisions
  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_RequestA(bufferATQA, &bufferSize);

  if (result == mfrc522.STATUS_OK) {
    if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
      return;
    }
    _rfid_error_counter = 0;
    _tag_found = true;
  }

  rfid_tag_present = _tag_found;

  // rising edge
  if (rfid_tag_present && !rfid_tag_present_prev) {
    Serial.println("Tag found");
    if (content.substring(1) == "04 BA 94 C2 A8 64 80") {
      Serial.println("hydro");
    }
    if (content.substring(1) == "04 C2 94 C2 A8 64 80") {
      Serial.println("bio");
    }

  }

  // falling edge
  if (!rfid_tag_present && rfid_tag_present_prev) {
    Serial.println("Tag gone");
  }
}
Quarx64 commented 4 years ago

@oliviereising move vour content.concat some lines down


void loop() {
  rfid_tag_present_prev = rfid_tag_present;
  _rfid_error_counter += 1;
  if (_rfid_error_counter > 2) {
    _tag_found = false;
  }

  // Detect Tag without looking for collisions
  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_RequestA(bufferATQA, &bufferSize);

  String content = "";

  if (result == mfrc522.STATUS_OK) {
    if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
      return;
    }
    _rfid_error_counter = 0;
    _tag_found = true;

         for (byte i = 0; i < mfrc522.uid.size; i++) {
            content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
            content.concat(String(mfrc522.uid.uidByte[i], HEX));
         }

         content.toUpperCase();

  }
   .
   .
   .

    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();  
}
oliviereising commented 4 years ago

Thanks that fixed the issue!

Martin-Laclaustra commented 2 years ago

Thank you for the contributions in this thread. Inspired in them, and after reviewing the standard, I put together an example that seems to work reliably. You can find it here: https://github.com/Martin-Laclaustra/MFRC522-examples