RFID (ID-12) strcmp tag mismatch

Hi folks,

I am working on a basic RFID project. When I hold my ID-12 reader up to a known card, I should be able to find out which card it is over the serial monitor.

I've found some helpful sketches online but can't get my code to produce the right effect. The serial monitor's readout always declares that I'm holding up "TAG2" and only shows the card being read as 8 characters long. My cards hold 10 characters. I've fiddled around with both the number of digits in the known tag arrays and in the length of the char strings to no avail.

Thanks in advance for all of your help.

Here's the readout when I scan both cards:

TAG code is: 5100FEA6
TAG1 code is: 5100FEA6F6
TAG2 code is: 5100FE9BA2
Tag 2
TAG code is: 5100FEFB
TAG1 code is: 5100FEA6F6
TAG2 code is: 5100FE9BA2
Tag 2

and here's the code I modified from andrethegiant: RFID cat door and http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1266771881:

int val = 0;
char code[11];
int bytesread = 0;
char tag1[11] = {'5','1','0','0','F','E','A','6','F','6'}; // Tag 1
char tag2[11] = {'5','1','0','0','F','E','9','B','A','2'}; // Tag 2

void setup() {

Serial.begin(9600);

}

void loop() {

if(Serial.available() > 0) { // if data available from reader
if((val = Serial.read()) == 10) { // check for header
bytesread = 0;
while(bytesread<10) { // read 10 digit code
if( Serial.available() > 0) {
val = Serial.read();
if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}
code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}
}
if(bytesread == 10) { // if 10 digit read is complete
Serial.print("TAG code is: ");
Serial.println(code);
Serial.print("TAG1 code is: ");
Serial.println(tag1);
Serial.print("TAG2 code is: ");
Serial.println(tag2);
{

if(strcmp(code,tag1) == 0) //compare tag1 to the tag read
{
Serial.println("Tag 1");
}

if(strcmp(code,tag2) == 0);
{
Serial.println("Tag 2");
}

}
bytesread = 0;
delay(1000); // wait for a second
}
}}}

Hello, a few months back I did a project using this RFID module and it was very hard to make it work on the beginning. But in the end everything worked.

One thing that I noticed was that I had to put a little delay between each serial read. Have you tried that? I'm on a bus right now, but as soon as I get home I'll take a look on my code and a better one on yours and I'll report back if the issue is still open. Cheers.

    if(strcmp(code,tag2) == 0);
//  Get rid of this semicolon ^
//  It makes this block execute unconditionally
       {     
        Serial.println("Tag 2");
       }

Thanks cdonate and dxwood for your helpful hints!

dxwood has solved my repeating "Tag 2" problem. I'm prone to over-semicoloning.

I'm still struggling with the length of the tags being read and the length of the known tags though (tag length displayed from reader: 8, known tag length: 10 + 2 digit checksum). Can anyone spot a problem in the code? (Nothing changes when I increase the char code from 12 to 14 digits.)

Thanks a million!

Nothing changes when I increase the char code from 12 to 14 digits.

What, exactly, did you change?

You are reading at most 10 characters:

     while(bytesread<10) {              // read 10 digit code
       if( Serial.available() > 0) {
         val = Serial.read();
         if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
           break;                       // stop reading
         }
         code[bytesread] = val;         // add the digit           
         bytesread++;                   // ready to read next digit 
       }
     }

Changing the size of the bucket that you put the data in from 10 to 12 to 14 to 1000 won't change that fact.

Hi PaulS,

Thanks for spotting that. I've modified the serial read portion of the code to read 12 characters rather than 10 and seem to be getting a whole string's worth of data now. Unfortunately, I still can't get the readout to let me know which tag was read by name.

Here's my readout:
TAG code is: 5100FE9BA2
TAG1 code is: 5100FEA6F6
TAG2 code is: 5100FE9BA2

The code being read now matches the second tag, but the serial monitor isn't naming which tag it is.

Here's my modified code:

int val = 0;
char code[12];
int bytesread = 0;
char tag1[12] = {'5','1','0','0','F','E','A','6','F','6'}; // Tag 1
char tag2[12] = {'5','1','0','0','F','E','9','B','A','2'}; // Tag 2

void setup() {

Serial.begin(9600);

}

void loop() {

if(Serial.available() > 0) { // if data available from reader
if((val = Serial.read()) == 10) { // check for header
bytesread = 0;
while(bytesread<12) { // read 10 digit code
if( Serial.available() > 0) {
val = Serial.read();
if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}
code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}
}
if(bytesread == 12) { // if 10 digit read is complete
Serial.print("TAG code is: ");
Serial.println(code);
Serial.print("TAG1 code is: ");
Serial.println(tag1);
Serial.print("TAG2 code is: ");
Serial.println(tag2);
{

if(strcmp(code,tag1) == 0) //compare tag1 to the tag read
{
Serial.println("Tag 1");

}

if(strcmp(code,tag2) == 0)
{
Serial.println("Tag 2");

}

}
bytesread = 0;
delay(1000); // wait for a second
}
}}}

You might want to change the code from:

int  val = 0; 
char code[12]; 
int bytesread = 0; 
char tag1[12] = {'5','1','0','0','F','E','A','6','F','6'}; // Tag 1
char tag2[12] = {'5','1','0','0','F','E','9','B','A','2'}; // Tag 2

to:

int  val = 0; 
char code[12]; 
int bytesread = 0; 
const char tag1[12] = "5100FEA6F6";
const char tag2[12] = "5100FE9BA2";

I at least find it easier to use the string notation, rather that initializing each byte. The const keyword says to the compiler that the value will not change, and on some systems, it could be the value into read-only memory.

Note, I've seen one LCD library that did not have the const keyword in the prototypes, and it would not allow string literals to be passed, but your use of the tags seems to be only in calling strcmp.

I at least find it easier to use the string notation, rather that initializing each byte.

There is another difference using the string notation, too. Using the string notation, the array is NULL terminated. Using the individual byte method, it is not.

That lack of a NULL means that tag1 and tag2 are not appropriate input to strcmp().

The data that is read from a tag usually has a byte at the beginning that is a 2, and one at the end that contains a 3.
Those values that are not in the range '0' to '9' and are not in the range 'A' to 'F' should not be stored in the array.

You can see that those values are being stored in the array because they cause the funny symbols in front of the good data that you print.

Changing the length of the array, and the number of characters read, without changing the data in the array doesn't make a lot of sense.

If the good tag value contains 10 characters, then reading 12 characters doesn't make sense.

PaulS:

I at least find it easier to use the string notation, rather that initializing each byte.

There is another difference using the string notation, too. Using the string notation, the array is NULL terminated. Using the individual byte method, it is not.

Yes correct. If you are call str* functions, you want them null terminated.

In the OP's example, since the length was 12 bytes, but the string was only 10 bytes, the last two bytes would be null for global initializations. If it was an auto initialization, it would be undefined.