Saving RFID tags as strings

Hey guys, I am a newbie in Arduino and programming. I am creating a project on Arduino uno. I am using the rfid technology with rfid-rc522 readers and mifare 1K tags. I am using multiple readers for my project and I would like to save each tag ID, read from a specific reader in a string variable. However, even though the reader reads the tag id. I cannot succeed to save it as a string. I have tried some stuff and I believe the problem is that I am declaring all the tags that I will use as strings in the beginning. Do you guys have an alternative way for me to define my tags.? I tried using safe string but I dont know how to use it really. I attached here a part of my code. Hope you guys can help me soon so I can continue to extend my code.

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

//defining pins that where used to connect the readers to the arduino. RST PIN is the same for all readers but the SSPIN should be special for each.
#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_1_PIN        10         // Configurable, take a unused pin, only HIGH/LOW required, must be different to SS 2
#define SS_2_PIN        8         // Configurable, take a unused pin, only HIGH/LOW required, must be different to SS 1
 

/**
 * Create an instance for each reader
 */
MFRC522 rfidReader0(SS_1_PIN, RST_PIN); // Instance of the class
MFRC522 rfidReader1(SS_2_PIN, RST_PIN); // Instance of the class

String strUID0; //saves the id of the tag read from reader 0
String strUID1;

String tag1 = "37 197 102 92";   //no. on block: 1
String tag2 = "37 201 142 92";   //no. on block: 2
String tag3 = "37 205 214 92";   //no. on block: 3
String tag4 = "37 210 58 92";    //no. on block: 4
String tag5 = "37 214 181 92";   //no. on block: 5
String tag6 = "37 219 65 92";    //no. on block: 6
String tag7 = "37 223 215 92";   //no. on block: 7
String tag8 = "37 220 215 92";   //no. on block: 8
String tag9 = "37 216 78 92";    //no. on block: 9
String tag10 = "37 211 209 92";  //no. on block: 10
String tag11 = "37 207 100 92";  //no. on block: 1
String tag12 = "37 203 13, 92";  //no. on block: 2
String tag13 = "37, 198 213 92"; //no. on block: 3
String tag14 = "37 197 187 92";  //no. on block: 4
String tag15 = "37 190 197 92";  //no. on block: 5
String tag16 = "37 186 245 92";  //no. on block: 6
String tag17 = "37 183 76 92";   //no. on block: 7
String tag18 = "37 179 209 92";  //no. on block: 8
String tag19 = "37 176 127 92";  //no. on block: 9
String tag20 = "37 173 102 92";  //no. on block: 10

/**     
   Initialize.
*/
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

     // Init Reader 0 
  rfidReader0.PCD_Init(SS_1_PIN, RST_PIN);
  Serial.print(F("Reader0 "));
  Serial.print(F(": "));
  rfidReader0.PCD_DumpVersionToSerial();
  
    // Init Reader 1
  rfidReader1.PCD_Init(SS_2_PIN, RST_PIN);
  Serial.print(F("Reader1 "));
  Serial.print(F(": "));
  rfidReader1.PCD_DumpVersionToSerial();

  Serial.print(" Setup complete!");
}

/**
   Main loop.
*/
void loop() {
  
  // Sets initial color of the  NeoPixel led rings ring to blank.
 
  //if a new tag is on the reader then read it
  if (rfidReader0.PICC_IsNewCardPresent() && rfidReader0.PICC_ReadCardSerial()){
    readOnReader0();
  }

  if (rfidReader1.PICC_IsNewCardPresent() && rfidReader1.PICC_ReadCardSerial()){
    readOnReader1();
}
    
}


/**
 * If a new tag is present on this reader, read it and save its ID as string
 */
void readOnReader0(){
      Serial.print(F("Reader0 "));
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F(": Card UID:"));
      printDec(rfidReader0.uid.uidByte, rfidReader0.uid.size);
      Serial.println();
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = rfidReader0.PICC_GetType(rfidReader0.uid.sak);
      Serial.println(rfidReader0.PICC_GetTypeName(piccType));
      strUID0 = String(rfidReader0.uid.uidByte[0]) + " " + String(rfidReader0.uid.uidByte[1]) + " " + String(rfidReader0.uid.uidByte[2]) + " " + String(rfidReader0.uid.uidByte[3]);
      Serial.println("this is the stringid");
      Serial.println(strUID0); //doesnt work
//    Serial.println(rfidReader0.uid.uidByte[0]); this works
      
      stopReading(rfidReader0);     
}




/**
 * If a new tag is present on this reader, read it and save its id as string
 */
void readOnReader1(){
      Serial.print(F("Reader1 ")); 
      // Show some details of the PICC (that is: the tag/card)
      Serial.print(F(": Card UID:"));
      printDec(rfidReader1.uid.uidByte, rfidReader1.uid.size);
      Serial.println();
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = rfidReader1.PICC_GetType(rfidReader1.uid.sak);
      Serial.println(rfidReader1.PICC_GetTypeName(piccType));
     
      Serial.println("this is the stringid");
      strUID1 = String(rfidReader1.uid.uidByte[0]) + " " + String(rfidReader1.uid.uidByte[1]) + " " + String(rfidReader1.uid.uidByte[2]) + " " + String(rfidReader1.uid.uidByte[3]);
      Serial.println(strUID1);
      stopReading(rfidReader1);
}

When you read the UID, it is referred to as rfidReader0.uid.uidByte[0]), rfidReader0.uid.uidByte[1]) etc. Are you possibly confusing "String" with char arrays?
What would happen if you replaced your attempt to print the String with something like this:?

//    Serial.println(strUID0); //doesnt work
      for(int i = 0; i<4;i++){
        Serial.println(rfidReader0.uid.uidVyte[i]);
      }
You specifically stated that you can print single bytes. What are their values?

You also need to understand that 1 = 1, whereas "1" = 49.. The ASCII table specified numerical characters starting with 0 equaling 48, 1 is 49, etc.

I am answering based on common programming rules and have no specific knowledge of the RFID process you are using. But, I bet this information should help you.

I looked at it again. I see you are using String(...) which should convert numbers to String for you.

Show what you are actually getting as a result where you say Serial.println(strUID0); //doesnt work

I'll see if I can make sense of it then.

Got it. The Arduino reference specifically warns against concatenating to an uninitialized String.

Try declaring your variable initially like this:
String strUID0 = "0 0 0 0"; //saves the id of the tag read from reader 0

Thanks for your reply!

printDec(rfidReader0.uid.uidByte, rfidReader0.uid.size);

this line prints this: 37 205 214 92
so the the decimal values

And this part:

 strUID0 = String(rfidReader0.uid.uidByte[0]) + " " + String(rfidReader0.uid.uidByte[1]) + " " + String(rfidReader0.uid.uidByte[2]) + " " + String(rfidReader0.uid.uidByte[3]);
  //Serial.println("this is the stringid");
  Serial.println(strUID0);

prints exactly the same: 37 205 214 92

I have tried to run my code again and now it works because I commented out some of the strings that I defined in the begging. (As you can see in my code I have defined a bunch of them: tag1,tag2, and so on). I still don't understand why this happens. I need those strings for my code so It would be nice to have a way to use them. I read about safeString but i am not sure how that works.

You are really using the wrong data type for you tags. They are not Strings, but an array of bytes. Use the built in type from the library

MFRC522::Uid tag1 = { 37, 197, 102, 92 };
//String tag1 = "37 197 102 92"; //no. on block: 1
...

Or, if all your tags are only 4 bytes, put them into a uint32_t and treat it like a number

      uint32_t UID0 = rfidReader0.uid.uidByte[0] << 24 + rfidReader0.uid.uidByte[1] << 16 + rfidReader0.uid.uidByte[2] << 8 +rfidReader0.uid.uidByte[3];

The problem with String, as implemented on the Arduino, is that it is inherently flawed and results are often unpredictable. This is fue to the memory management, or lack thereof. Most here will always say to stay away from String on the Arduino. Honestly, I don't see why you NEED them either. Obviously, those IDs are internally a 4 byte array and not a string, so why not use them that way?

byte UId1 = {37,205,214,92};
byte UId2 = {38,206,215,93};
...

Or, better yet, maybe define a structure or at least use multi-dimensional arrays.

Tell me why you think you need String and I will try to suggest a much better alternative for you.

Here on the forum, do not confuse "string" with String. The big S and little s are NOT interchangeable.

Bad idea, you should put the tag ID into either a long int or a long long int depending on the length of your ID.
It makes everything easy to read, compare and sort.

void readOnReader1() {
 // ...
  Serial.println("this is the stringid");
  strUID1 = String(rfidReader1.uid.uidByte[0]) + " " + String(rfidReader1.uid.uidByte[1]) + " " + String(rfidReader1.uid.uidByte[2]) + " " + String(rfidReader1.uid.uidByte[3]);
  Serial.println(strUID1);

I would like this function to save the tag id in a variable that I can use later in teh code. To pass it as a parameter in another function and compare it with another given ID. So I want to check if the tag id that the reader is currently reading (in my case strUID1) equals another already defined ID (e.g.: in my case tag1). Like this:

bool validateTags(String fstNo, String sndNo, String result) {
    if ((fstNo.equals(tag8)) && (sndNo.equals(tag2)) && (result.equals(tag6))) {
      return true;
//...
    }
void blinkLed() {
  if (validateTags(strUID0, strUID2, strUID3)) {
    Serial.println("*** Correct ***");
    for (int i = 0; i < 5; i++) { 
      setColorPixels(green);
//...

I would appreciate it if you guys showed me how to use the right data type in these scenarios. I only used String because I found it easier as a beginner.

That's the problem with String. Beginners, for example with a BASIC background, are familiar with them and use them everywhere like water in a garden. However, they only "work" in those environments where memory is managed differently. Arduino, and other environments as well, lack that advanced memory management because they are, after all, microcontrollers (even when the name starts with "Mega").
Grumpy Mikes experience shows in his advise where he said you should use a 32 bit variable. As I had suggested, using a byte array or structure, you would have to compare both byte1 (or byte[1]) through 4 to see if it is a match. His way, you could simple say if(thisId == thatId).
Try to hone your skills to get away from if ((fstNo.equals(tag8)) && (sndNo.equals(tag2)) && (result.equals(tag6))). If you wanted to test if the tag was one of three that may be ok, but what if it is one of 100s?
Use an array! Write a function similar to this:

bool validId(xxx thisId){
  bool retVal = false;
  for(int i = 0; i < 10; i++){
    if(thisId == validID[i]){
      retVal = true;
      break;}
  }
  return retVal;
}

And then, after reading an Id, simply if(validId(readId))
Does that help?

Several here, including myself, have suggested that String really is the wrong data type. Several have suggested using a single, big, numeric value (long long or uint32_t). That is probably the best solution in this case.
I would further suggest that it is easier to work with those tag numbers in hexadecimal form instead of trying to calculate out that 37 197 102 92 equates to 633693788 in decimal.
In hex, you could define your array of valid tags like this;

uint32_t validIDs = {0x25C5665C, 0x25C98E5C, 0x25CDD65C, 0x25D23A5C, 0x25D6B55C,
                                   0x25DB415C, 0x25DFD75C, 0x25DCD75C, 0x25D84E5C, 0x25D3D15C,
                                   0x25CF645C, 0x25CBD5C, 0x25C6D55C, 0x25C5BB5C, 0x25BEC55C,
                                   0x25BAF55C, 0x25B74C5C, 0x25B3D15C, 0x25B07F5C, 0x25AD665C};

Of course, there are lots of other ways to do it as well... Whatever works for you.

To get the tag number into the long int variable tagId then you need to take each one of the four bytes, and shift them to the position representing the weight of the bytes using the shift left operator <<
Then OR then together with the inclusive OR operator |

tagId = (rfidReader1.uid.uidByte[0]) | (rfidReader1.uid.uidByte[1] << 8) |( rfidReader1.uid.uidByte[2]<< 16) | (rfidReader1.uid.uidByte[3] << 24);
 

Then you can treat a tag ID like any other number.

If you want to see what number this is print it out using the HEX option.

If you are trying to match a tag number with that printed on a tag, you might have to turn this number round, this is because you can store multiple byte numbers in two ways. Little endian with the least significant byte first, as in the example above, or big endian with the most significant byte first like this

tagId = (rfidReader1.uid.uidByte[3]) | (rfidReader1.uid.uidByte[2] << 8) |( rfidReader1.uid.uidByte[1]<< 16) | (rfidReader1.uid.uidByte[0] << 24);
 

Wars have been fought over which of the two ways is the correct one. In the early days of microprocessor there were two big players making processors. Intel used big endian and Motorola used little endian. As one of the first processors I used was Motorola, I think that little endian is the one true way. :slight_smile:

Thanks for your replies. The code looks now like this.
I am still getting a warning because of the way that I have assigned the value to my strUID variables. Could you guys tell me how to fix it so that I don't get that warning?

//these variables will save the tag ID that each reader is currently reading. (4 readers, therefore 4 variables)
byte strUID0[4];
byte strUID1[4];
byte strUID2[4];
byte strUID3[4];

//the tag IDs that I will use for my program:
byte tag1[] = {37, 197, 102, 92};   //no. on block: 1
byte tag2[] = {37, 201, 142, 92};   //no. on block: 2
byte tag3[] = {37, 205, 214, 92};   //no. on block: 3
byte tag4[] = {37, 210, 58, 92};    //no. on block: 4
byte tag5[] = {37, 214, 181, 92};   //no. on block: 5
byte tag6[] = {37, 219, 65, 92};   //no. on block: 6
byte tag7[] = {37, 223, 215, 92};   //no. on block: 7
byte tag8[] = {37, 220, 215, 92};   //no. on block: 8
byte tag9[] = {37, 216, 78, 92};    //no. on block: 9
byte tag10[] = {37, 211, 209, 92};  //no. on block: 10
//...more tags 

// the Method that reads the tag that is being scanned on the reader0. Same way I have written the methods for other readers.
void readOnReader0() {
  Serial.print(F("Reader 0 "));
  Serial.print(F(": Card UID:"));
  printDec(rfidReader0.uid.uidByte, rfidReader0.uid.size);
  Serial.println();
  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfidReader0.PICC_GetType(rfidReader0.uid.sak);
  Serial.println(rfidReader0.PICC_GetTypeName(piccType));
  strUID0[4] = rfidReader0.uid.uidByte; //I get a warning because of this assignment
  stopReading(rfidReader0);
}

this is the warning:

warning: invalid conversion from 'byte* {aka unsigned char*}' to 'byte {aka unsigned char}' [-fpermissive]
   strUID0[4] = rfidReader0.uid.uidByte;

rfidReader0.uid.uidByte is an Array. I didn't read the whole post, but you need to access a single element of this array, if you want to store it in the destination array (or use memcopy).

For example:

// Use whatever index is correct. This example uses index 0.
strUID0[4] = rfidReader0.uid.uidByte[0]

But he doesn't want to do that any more because it is quite frankly it is a useless thing to do. He should be storing his tokens as single unsigned long int .

@vrieeg This means you have to store all your tokens in this format.
You can't simply store the incoming token as a variable and have your other cards stored as arrays. You have to store your other cards in an array of unsigned long int then you can simply iterate through the array comparing each stored card with your incoming card.

Yes you will do. You have defined a byte array to have 4 places in it, that means in array indexes of 0 to 3. Then you have gone and stored a value outside these array limits in index 4!!

Have you totally ignored what I said about using a single variable to store your tokens?

Look I used to design RFID readers and access control software for a living, I know what I am talking about.

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