Several beginner programming questions about RFID reader code

I am brand new to coding in general and the spark photon in particular. I’ve got an MFRC522 RFID reader and the appropriate chips. My code will read chips and transmit their UID to the particle console, but I can’t figure out how to do much else. Currently I’m just trying to make it blink the Photon’s onboard LED a different color depending on whether a card is recognized or not. The current build causes the error message “rfidv2.cpp:76:14: error: ‘masterID’ was not declared in this scope”

My specific questions are:

  1. Why is this error occuring when masterID is declared during setup?
  2. What does the for statement in the middle do to the UID? I know the code won’t run right without it but I don’t understand why the compound addition operator is required.
    3)Aside from the error, should this code cause the light to blink a different color if the card is the masterID card?

[code]#include “MFRC522/MFRC522.h”

/*
Function Core Pin MRFC522 Pin
Reset D2 RST
SPI SS D1 SDA
SPI MOSI A5 MOSI
SPI MISO A4 MISO
SPI SCK A3 SCK
*/

#define SS_PIN D1
#define RST_PIN D2
#define LED_PIN D7

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

void setup() {

mfrc522.setSPIConfig();
mfrc522.PCD_Init(); // Init MFRC522 card

RGB.control(true); // take control of onboard RGB led
String masterID = “77b392ab”;

}

void blinkAccess() {
RGB.color(0, 0, 255);
delay(150);
RGB.color(0, 0, 0);
delay(100);
RGB.color(0, 0, 255);
delay(150);
RGB.color(0, 0, 0);
}

void blinkDeny() {
RGB.color(0, 255, 0);
delay(150);
RGB.color(0, 0, 0);
delay(100);
RGB.color(0, 255, 0);
delay(150);
RGB.color(0, 0, 0);
}

void blinkReady() {
RGB.color(255, 0, 0);
delay(150);
RGB.color(0, 0, 0);
delay(100);
RGB.color(255, 0, 0);
delay(150);
RGB.color(0, 0, 0);
}

void loop() {
// Look for new cards
if ( mfrc522.PICC_IsNewCardPresent()) {
// Serial.println(“New card present…”);
if ( mfrc522.PICC_ReadCardSerial()) {
// Dump debug info about the card. PICC_HaltA() is automatically called.

  String UID = "";
  
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    UID += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    UID += String(mfrc522.uid.uidByte[i], HEX);
  }
  mfrc522.PICC_HaltA();
  Particle.publish("rfid-read", UID, 5, PRIVATE); // publish UID to rest of system
  
if (UID==masterID) {

  blinkReady();
}
}

}
}
[/code]

Thanks for your time!

  1. This one is easy. You declare masterID inside setup so that means it is a local variable, and can’t be used outside that function (which you do). You should declare that at the top of the file outside any function to make it a global.

  2. I’m not sure what’s going on with the for loop, because I don’t know what kind of data you get from reading the chip. If all the bytes are greater than 0x10, then it will just build up the string from the individual bytes (in the second UID += statement).

  3. It should blink the color defined in blinkReady(), but you never call any of those other blink methods, so I don’t think I would say it would blink a different color.

This just translates the individual bytes received from the reader into its HEX representation.
The first UID += ... line just prepends a leading zero if the value would be a single HEX "digit".
But I rather dislike this kind of String nonsense.

I'd rather go with something like this

  char UID[3*mfrc522.uid.size + 1]; 
  memset(UID, 0, sizeof(UID)); // clear the bytes

  for (byte i = 0; i < mfrc522.uid.size; i++) {
    sprintf((char*)&UID[i*3], "%02x ", uid.uidByte[i]); // append a new 2 digit HEX number plus trailing blank
  }
1 Like

ScruffR:

Why is this manipulation of the card data necessary for the publish function to, uh, function? If I don’t have it and try to publish the UID I get null. As I understand it, the function mfrc522.PICC_ReadCardSerial() gets the data from the card and the next line String UID="" populates the variable UID with the data. Why can’t I just use that data?

If I’m understanding correctly, the code you wrote creates the char UID, which has the size pulled from the library plus one space, then added a new hex number in that space?

Changes to the code: added #define masterID, added code to blinkDeny() if the card is not the master card.

#include "MFRC522/MFRC522.h"

/*
  Function           Core Pin      MRFC522 Pin
  Reset             D2            RST
  SPI SS            D1            SDA
  SPI MOSI          A5            MOSI
  SPI MISO          A4            MISO
  SPI SCK           A3            SCK
*/

#define SS_PIN D1
#define RST_PIN D2
#define LED_PIN D7
#define masterID

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

void setup() {
    
  mfrc522.setSPIConfig();
  mfrc522.PCD_Init(); // Init MFRC522 card

  RGB.control(true); // take control of onboard RGB led
  masterID = "77b392ab";


}

void blinkAccess() {
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkDeny() {
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkReady() {
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void loop() {
  // Look for new cards
  if ( mfrc522.PICC_IsNewCardPresent()) {
       if ( mfrc522.PICC_ReadCardSerial()) {
      // Dump debug info about the card. PICC_HaltA() is automatically called.
     

      String UID = "";
      
      for (byte i = 0; i < mfrc522.uid.size; i++) {
        UID += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
        UID += String(mfrc522.uid.uidByte[i], HEX);
      }
      mfrc522.PICC_HaltA();
      Particle.publish("rfid-read", UID, 5, PRIVATE); // publish UID to rest of system
      
    if (UID==masterID) {
    
      blinkReady();
    }
    if (UID~=masterID) {
    
        blinkDeny();
       }
    }
}
}

error log now reads as below. The errors are different now which I believe counts as progress.

rfidv2.cpp: In function 'void setup()':
rfidv2.cpp:25:12: error: expected primary-expression before '=' token
 MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
            ^

rfidv2.cpp: In function 'void loop()':
rfidv2.cpp:76:22: error: expected primary-expression before ')' token
       
                      ^

rfidv2.cpp:80:12: error: expected ')' before '~' token
       }
            ^

rfidv2.cpp:80:22: error: conversion from 'String' to 'bool' is ambiguous
       }
                      ^

rfidv2.cpp:67:14: note: candidates are:
 
              ^
In file included from ../wiring/inc/spark_wiring_stream.h:30:0,
                 from ../wiring/inc/spark_wiring.h:39,
                 from ./inc/application.h:36,
                 from MFRC522/MFRC522.h:77,
                 from rfidv2.cpp:1:
../wiring/inc/spark_wiring_string.h:140:2: note: String::operator String::StringIfHelperType() const
  operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
  ^
../wiring/inc/spark_wiring_string.h:99:9: note: String::operator const char*() const
         operator const char*() const { return c_str(); }
         ^
make[1]: *** [../build/target/user/platform-6rfidv2.o] Error 1
make: *** [user] Error 2
Ready. 

Thanks again for your help!

It's no manipulation but translation.
The PID can be any combination of bits, even 0x00 bytes that would terminate the string prematurely and the transport for Particle.publish() only allows a subset of the usual 256 possible bit combinations a byte could have - that's a common restriction for web based communication.

But sorry, I had forgotten some bits when typing that directly into the post without actually compiling it.
e.g. it should actually be

  char UID[3*mfrc522.uid.size + 1]; // times three to take two HEX digits plus one blank per raw byte and a zero-terminator

About your error messages

#define masterID
...
void setup() {
  ...
  masterID = "77b392ab";
}

You cannot do that. #define defines a compiler macro and not a variable, so you can't assign a value to it that way.

You'd need something like that

#define masterID "77b392ab"
// or
String masterID = "77b39ab";
// or
String masterID;
...
void setup() {
  ...
  masterID = "77b39ab";
}

Or here

    if (UID==masterID) {
      blinkReady();
    }
    if (UID~=masterID) {
        blinkDeny();
    }

not equal is != and not ~=.
But since you already got a equality check you'd just use an else branch anyway

    if (UID==masterID) {
      blinkReady();
    }
    else {
        blinkDeny();
    }

There is no data in UID at this point in the code. The line, String UID = "", sets UID to an empty string, it doesn't populate it with data. That's what the subsequent for-loop does. The data that's received from the call to PICC_ReadCardSerial() is in the form of a C struct that looks like this,

typedef struct {
	byte		size; // Number of bytes in the UID. 4, 7 or 10.
	byte		uidByte[10];
	byte		sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;

The code in the for-loop takes the individual bytes in the uidByte array, interprets them as hex digits, and builds the UID string up out of those hex digits.

You both have been a huge help so far. Thanks again.

Currently the code performs almost as desired but I feel I am storing the information for the cards incorrectly, and I fear I badly misunderstand the loop control syntax- the LED doesn’t blink quite right. This may also be a symptom of the fragmented sends.

Also there is something wrong with the publish function, as it will send fragments of the card data to the console log many times per complete send.

#include "MFRC522/MFRC522.h"

/*
  Function           Core Pin      MRFC522 Pin
  Reset             D2            RST
  SPI SS            D1            SDA
  SPI MOSI          A5            MOSI
  SPI MISO          A4            MISO
  SPI SCK           A3            SCK
*/

#define SS_PIN D1
#define RST_PIN D2
#define LED_PIN D7
#define masterID "77b392ab"
#define alanCard "fe7da8f6"
#define bobCard "b21b93ab"


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

void setup() {
    
  mfrc522.setSPIConfig();
  mfrc522.PCD_Init(); // Init MFRC522 card

  RGB.control(true); // take control of onboard RGB led
  


}

void blinkAccess() {
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkReady() {
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkDeny() {
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void loop() {
  // Look for new cards
  if ( mfrc522.PICC_IsNewCardPresent()) {
       if ( mfrc522.PICC_ReadCardSerial()) {
      // Dump debug info about the card. PICC_HaltA() is automatically called.
     

      String UID = "";
      
      for (byte i = 0; i < mfrc522.uid.size; i++) {
        UID += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
        UID += String(mfrc522.uid.uidByte[i], HEX);
        
      mfrc522.PICC_HaltA();
      Particle.publish("rfid-read", UID, 5, PRIVATE); // publish UID to rest of system
       
    if (UID==masterID) {
      blinkReady();
    }
        }
    if (UID==(alanCard,bobCard)){
        blinkAccess();
        }
    if (UID!=(alanCard,bobCard))
        blinkDeny();
       }
       }  
  }

This code verifies and flashes succesfully.

Your code would be easier to diagnose if you line up the braces properly. I see three problems. The if (UID==masterID) is inside the for-loop’s ending curly brace; it should be moved outside of it. Second, your last if statement will run if UID==masterID (as well as the first one, so you’re going to call blinkReady and blinkDeny). Third, you can’t compare UID with two other variables like you are with a comma separated list; it compiles, but it only “sees” the second variable. You should use else-if/else statements rather than a series of ifs.

if (UID==masterID) {
    blinkReady();
}else if (UID==alanCard || UID==bobCard) {
    blinkAccess();
}else{
    blinkDeny();
}

These two lines,

  mfrc522.PICC_HaltA();
  Particle.publish("rfid-read", UID, 5, PRIVATE); // publish UID to rest of system

should also be moved outside the ending curly brace of the for-loop

The code now functions as desired. Thanks again!

However, I am hoping to make the code more general so it can be used in several locations at once with the same access list. I see that using webhooks I can have the device publish data, but is there a similar process in reverse?

#include "MFRC522/MFRC522.h"

/*
  Function           Core Pin      MRFC522 Pin
  Reset             D2            RST
  SPI SS            D1            SDA
  SPI MOSI          A5            MOSI
  SPI MISO          A4            MISO
  SPI SCK           A3            SCK
*/

#define SS_PIN D1
#define RST_PIN D2
#define LED_PIN D7
#define STK_PIN D0
#define masterID "77b392ab"
#define alanCard "fe7da8f6"
#define bobCard "b21b93ab"


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

void setup() {
    
  mfrc522.setSPIConfig();
  mfrc522.PCD_Init(); // Init MFRC522 card
  pinMode(STK_PIN,OUTPUT);
  RGB.control(true); // take control of onboard RGB led
  


}

void blinkAccess() { //blink the LED 
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 0, 255);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkReady() {
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(0, 255, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void blinkDeny() {
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
  delay(100);
  RGB.color(255, 0, 0);
  delay(150);
  RGB.color(0, 0, 0);
}

void loop() {
  // Look for new cards
  if ( mfrc522.PICC_IsNewCardPresent()) {
       if ( mfrc522.PICC_ReadCardSerial()) {
      // Dump debug info about the card. PICC_HaltA() is automatically called.
     

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

if (UID==masterID) {
    blinkReady();
    Particle.publish("rfid-read", UID, 5, PRIVATE);
}

else if (UID==alanCard || UID==bobCard) {
    blinkAccess();
    Particle.publish("rfid-read", UID, 5, PRIVATE);
    digitalWrite(STK_PIN,HIGH);
    delay(5000);
    digitalWrite(STK_PIN,LOW);
}

else{
    blinkDeny();
    Particle.publish("rfid-read", UID, 5, PRIVATE);
}
}
}      
}

You'll have to explain what you mean by "a similar process in reverse".

BTW, notice that you have the same publish statement in all 3 branches of your if/else if/else block; you only need one that should be put after the block ends.

The final plan is for three locks, each with its own photon. I’d like to get the list of permitted ID data from a central location so multiple photons can access it and I only have to update it once if permissions change. I saw how webhooks can send data on status changes to the console, I was thinking there might be some way to propagate permissions changes without reflashing every photon.

Thanks, I’ve fixed that.

I am not aware of any third party sites that would allow you send up data that you could then get back to your Photons via a webhook. Another way to accomplish your goal, would be to use another Photon, a central one that would act like a server. You would keep that one updated with any new changes, and publish that info to your other Photons, which would all subscribe to that event. You could also use that central Photon to gather data from all your lock Photons if you wanted to (via publishes from the lock Photons).

I very much like that idea and will probably be using it in the final product. While the user data is created as "#define namecard “data” is it possible to modify it fro\m inside the loop?

I don't understand what you mean by this question. Please explain what you want to modify, inside what loop, and why you want to do that.

No, #define is a compile time directive and the value can't be changed at runtime.

That's one of the reasons why I said exactly that earlier

1 Like

Hi,
Im working on MFRC522 through SPI interface with PIC microcontroller. I got a sample code from Github for Arduino boards, I have modified SPI communication for PIC controller and added MFRC522.c & MFRC522.h files.

Below code im using in main function, (i have LCD display, for that i have modified to display card number)

if (RFID_findCard(0x52,&s)==MI_OK)
        {
           if ( RFID_anticoll(SPI_Array)==MI_OK)
            {
                for(Temp=0;Temp<5;Temp++)
                {
                    lcd_clear();
                    Clear_LcdArray();
                    lcd_goto(0);	// select first line
                    lcd_puts("MASTER RECEIVED ");
                    GaucLcd_Data[0]=SPI_Array[Temp]+0x30;
                    lcd_goto(0x40);	// Select second line
                    lcd_puts(GaucLcd_Data);
                    __delay_ms(1000);
                }
            } //else printf("ERR\n");
        }

According the above code, its not finding any cards, seems not returning MI_OK from RFID_findCard().

Please help anyone.

I tested another Library - have an eye to this:

@bsivam, you do realise that this forum is for Particle devices and not PIC?

2 Likes

Hi,
Thanks for your sharing, Im using that RFID kit only interfacing with PIC microcontroller.

Thanks for your reply.
Microcontroller is not a matter, we may change anything but the concept of SPI communication between RFID kit and controller having problem.