rfid compare tag code

Hello everybody,

After weeks of intense testing I succeeded in reading tag codes from the 13.56Mhz APSX RW-210 rfid reader! This is the code: http://www.technicum.net/rfid/rfid_read.pde

It sends the read command via software serial to the rfid reader. Next it reads in the Tag code via hardware serial. Finally it prints a nice tag code to the computer!

Now the problematic part;
As a next step I wanted to compare the tag code to a list of known tags and then do a certain action (for example blink a led). I've been struggling with this for a week now so I decided to ask for some help. This is one of my numerous attempts :-[

#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
int serIn;             // var that will hold the bytes-in read from the serialBuffer
byte serInString[12]; // array that will hold the different bytes
int serInIndx  = 0;    // index of serInString[] in which to inser the next incoming byte
int serOutIndx = 0;    // index of the outgoing serInString[] array;
int ledPin = 13;                 // LED connected to digital pin 13
char Tag1[] = "001B4EC1D014E0D57B"; //known tag code, should become a list of 50+ tags

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  mySerial.begin(19200); // set the data rate for the SoftwareSerial port
  Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
  
  
  mySerial.print(0xfa, BYTE); // request tag code
  
  // only if there are bytes in the serial buffer execute the following code
  if(serialAvailable()) {     
    
    //keep reading from serial untill there are bytes in the serial buffer
     while (serialAvailable()){        
        serIn = serialRead();              //read Serial        
        serInString[serInIndx] = serIn; //insert the byte you just read into the array at the specified index
        serInIndx++;                    //update the new index
     }
     
     //feedback that something was received
     Serial.println ("Processing Tag");
  }
  
  //do somenthing else perhaps wait for other data.
  Serial.println ("NO TAG ");
  
  //print out later in the loop the sentence only if it has actually been collected;
  if( serInIndx > 0) {
      Serial.print("Tag ID=");      
      
      //loop through all bytes in the array and print them out
      for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++) {
          Serial.print((serInString[serOutIndx]), HEX );    //print out the byte at the specified index
            if((serInString[12], HEX) == Tag1[19]) { //compare received tag code to known tag code
            digitalWrite(ledPin, HIGH); // if true blink led
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
          }
          //serInString[serOutIndx] = "";            //optional: flush out the content
      }
        
      //reset all the functions to be able to fill the string back with content
      Serial.flush(); //flush serial buffer
      serOutIndx = 0;
      serInIndx = 0;
  }
    
  //slows down the visualization in the terminal
  Serial.println();
  delay(200);
}

The tag code "001B4EC1D014E0D57B" is the code that I have copied from serial monitor after reading a tag. All my attempts won't make the led blink :frowning: Can someone please help me, I would like to put 50+ tags in the memory that trigger a certain action.

Kind Regards,
Loïc

The tag code "001B4EC1D014E0D57B" is the code that I have copied from serial monitor after reading a tag.

This is probably the hex representation of a binary number, not really a string. try initializing your target array like this:

char target[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b };

Also, I just glanced at it but your loop function doesn't look right. You are asking for a new tag every time you run loop and apparently assuming that the data will be returned immediately. This is not necessarily the case. You are also assuming that the data is made available in a single uninterupted stream, and this is almost certainly wrong. Look at the part of the code where you are reading the data; that section probably needs a re-write.

I would like to put 50+ tags in the memory that trigger a certain action.

Hmm, the ATmega8 only has 1k of RAM, and your target strings are about 10 bytes long, so that's half the available memory just to store the strings you are matching against. It'll probably work, as long as the rest of your code isn't too memory intensive, but you should be aware you are approching the limits of the device and method you're using.

Of course, the 168 has twice the RAM and there are methods for storing data in program space (flash), but they're not as straightforward as the methods you use now.

-j

Thank you kg4wsv,

I've been trying your suggestions for the last 24hours but with no success. The code that prints the tag code back to the serial monitor was modified from code I found on the web, I'm not such good coder to be able to rewrite it with a new approach to getting the tag codes reported. But as far as printing nice unique tag codes to the serial monitor this code works perfectly, so I'm not sure the "compare tag code to list" problem I'm having is to find in the way this original code works. But being a "C" noob I could be totally wrong.
Next thing I tried was using the <string.h> library, trying memcmp and strcmp. No succes :frowning: , but again could be my semi-noobness :slight_smile:

The last weeks I've been looking at this basic stamp code that does exactly what I want to do http://www.digitaldawgpound.org/wp-content/uploads/2007/03/rw210_rfid_reader.bse (from this project Account Suspended) trying to understand the data types and sizes to work with (bytes vs chars etc).
Could someone who understands the basic stamp code please help me on the right way? I really appreciate your help.

Regards, Loïc

String functions are not appropriate, as you are working with chinks of binary data, not strings. Specifically, C strings are null terminated arrays, which means a byte containgin 0x00 will occur after the contents of the string. In the example you are playing with, there is a null in the first array element, which means that is a zero length string as far as strcmp() and friends are concerned. memcmp may be better, but I haven't checked the docs on that one myself.

Your look function needs to look something like this:

#define TAG_LEN 8
char target_tag[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b }; 
void loop()
{
    byte bytes_read=0;
    char tag_read[TAG_LEN];
   // code to request tag data goes here

  // loop here until we get the required number of bytes back from the reader
  // this code will fail unpredicably in the event of communication errors
   while (bytes_read < TAG_LEN)
      while (Serial.available() > 0)
          tag_read[bytes_read++] = Serial.read();

   // compare the tag we read to see if it matches
   if (memcmp(tag_read, target_tag, TAG_LEN))
       do_something();
}

This is off the cuff, so there may be errors, especially at the boundary conditions...

-j

Thank you kg4wsv,
I've been trying your suggestions for the last 24hours but with no success.

Ouch, I think most of us know that all too well.

Have you perhaps tried hacking this code:-

http://www.arduino.cc/playground/Learning/PRFID

It's for a parallax, but there might be something in it you could use.

String functions are not appropriate, as you are working with chinks of binary data, not strings.

The Parallax RFID Reader from Grand Designs sends a start byte of 0x0A, then ten hexadecimal digits in ASCII, then a stop byte 0x0D. Its all 'printable ASCII' so string functions are appropriate. Tie off the ID string by replacing the stop byte with 0x00, then use strcmp() to match to your array of valid IDs.

cheers ... BBR

@John Ryan: In the past I've tried to modify the parallax rfid code for weeks in a row without any succes (see my other forum post: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1186246253/15).
After this I finally succeeded in printing the the tag codes to serial monitor by modifying some other code I found on the web. But with this last code (the code I posted at the beginning of this topic) I noticed that by changing the variable "serInString" from char to byte the output was always smaller and more equal in length rather than being always different from tag to tag. This is the output for 3 tags using a "char" variable:
00FFFFFFDDFFFFFF8EFFFFFF96E014FFFFFFE010FFFFFFC8
00FFFFFF989FFFFFF96E014FFFFFFE0FFFFFF857B
001B4EFFFFFFC1D014FFFFFFE0FFFFFFD57B
This is the output for the same 3 tags using a "byte" variable:
00DD8E96E014E010C8
0098996E014E0857B
001B4EC1D014E0D57B
These are all printed with the command "Serial.print((serInString[serOutIndx]), HEX );"
I mention all this because maybe the whole problem of comparing the tags to a list is related to this. I've also spotted in the basic stamp code that the tags are in this format

'Valid tags

Tag1         DATA     $00, $00, $7B, $7D, $90, $F2, $36, $07, $07, $F2, $03, $7D

Tag2         DATA     $00, $00, $7D, $7D, $1E, $1F, $E0, $E6, $EF, $6E, $04, $04

Thus being 12 hex numbers while I only have 9 in two tags and even one tag (0098996E014E0857B) with 17 character that I even can't split into HEX (if you know what I mean)

@brianbr: I've tried the "strcmp" command but with no succes, the led flashes, but only when wrong tags a presented. Maybe it's related to the problems described above.

Does anyone see any light in this mess? :-/ Any help is really appreciated.

Kind Regards, Loic

I've got the same problem, in a round about kind of way. While, my tag checking will be handled outside Arduino, I'd still like a more portable version checking tags inside Arduino.

But, converting char to string I haven't found a means to do that yet, and have spent the better part of two days searching.

@John Ryan: I would be happy to work together to solve this!

I've reworked my previous code based on the all suggestions. Still no luck :frowning:
This is it:

#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

#define TAG_LEN 12

// set up a new serial port
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

int ledPin = 13;
int serIn;
byte code[TAG_LEN];             // var that will hold the bytes-in read from the serialBuffer
byte bytes_read = 0;
char target_tag[] = {0x00, 0x1b, 0x4e, 0xc1, 0xd0, 0x14, 0xe0, 0xd5, 0x7b };

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  mySerial.begin(19200); // set the data rate for the SoftwareSerial port
  Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
  
  
  mySerial.print(0xfa, BYTE); //request Tag code
  
  // only if there are bytes in the serial buffer execute the following code
  if(serialAvailable()) {     
    
    //keep reading from serial untill there are bytes in the serial buffer
     while (serialAvailable() && bytes_read < TAG_LEN){                //read Serial        
        code[bytes_read] = serialRead(); //insert the byte you just read into the array at the specified index
        bytes_read++;                    //update the new index
     }
     
     //feedback that something was received
     Serial.println ("Processing Tag");
  }
  
  //do somenthing else perhaps wait for other data.
  Serial.println ("NO TAG ");
  
  //print out later in the loop the sentence only if it has actually been collected;
  if( bytes_read >= TAG_LEN) {
      Serial.print("Tag ID= ");      
      
      //loop through all bytes in the array and print them out
      for(bytes_read=0; bytes_read < TAG_LEN; bytes_read++) {
          Serial.print((code[bytes_read]), HEX);    //print out the byte at the specified index
          //serInString[serOutIndx] = "";            //optional: flush out the content
      }
    if (memcmp(code, target_tag, TAG_LEN) > 0) { //if received tag code == to listed tag code
          digitalWrite(ledPin, HIGH); //do something (blink a led)
          delay(500);
          digitalWrite(ledPin, LOW);
          delay(500); 
        }
      //reset all the functions to be able to fill the string back with content
      bytes_read = 0;
  }
    
  //slows down the visualization in the terminal
  Serial.flush(); //flush serial buffer
  Serial.println();
  delay(200);
}

I really can't think of anything else to do. Any help is appreciated.

Regards, Loïc

That would be good. I need to compare the char variable that the tag is stored, against literals eg. "3300960185". It's not mission critical in my case, but the problems become a nag that I'd like to solve, and it would be nice to have a portable version.

My latest discoveries:-

So I'll take a look at it this evening and see what it does.

Someone here also got 3 tags individually recognized, the english is broken, and I couldn't find any code.

http://www.sarades.no/index.php?paged=2

ok, so that solved my problem.

Here's the revised code including the TextString library:-

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1185507207/30

I'm reading from 8 input switches, if one is pressed, then a reading is taken from the Parallax RFID. If a tag is recognized, all 8 LED's in the 3rd array of 8 LED's flashes. Otherwise, a LED corresponding to the switch pressed, is flashed.

So that's handy for when I need to demo a standalone version. Otherwise, the intent is to check valid tags against a database of tag's stored in a web based .txt file. That parts handled by processing/php so a connection is needed for it to operate (till I buy an Arduino BT).

Nice! :slight_smile:

I'll try it with my reader code first thing tomorrow. It's 2pm now (Belgium), so I better start off fresh tomorrow morning. I'll keep you updated. Thanx again for helping me out.

Cheers, Loïc

You should be able to use comma's to separate the tags:-

TextString myTags = TextString(5500); // enough for about 500 with comma's

myTags.setArray("1010101010,1010101011,1010101012,");

Then add a comma after the tag is scanned, and use:-

if (myTags.contains("1010101010,")) {
// checks if myString contains the subString "1010101010,"
}

The 168 should hold over a thousand unique tags, not bad considering the readers ex China off eBay store 500 and cost about the same as an Arduino, but don't do all the cool stuff Arduino's can do.

Finally it works!!! This code reads the tag and compares it to a multidimensional array of known tags. If the tag matches to one in the array then an action is executed (blinking a led).
Here's the code:

#include <SoftwareSerial.h>

#define rxPin 7
#define txPin 2

#define TAG_LEN 12
#define ARR_LEN 2
// set up a new serial 
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

int ledPin = 13;
int serIn;
byte code[TAG_LEN];             // var that will hold the bytes-in read from the serialBuffer
int bytes_read = 0;
char target_tag[ARR_LEN][TAG_LEN] = 
{{0x00, 0x00, 0xdd, 0x8e, 0x96, 0x0e, 0x00, 0x01, 0x04, 0xe0, 0x10, 0xc8 },
{0x00,  0x00, 0x1b, 0x4e, 0xc1, 0x0d, 0x00, 0x01, 0x04, 0xe0, 0xd5, 0x7b}}; 

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  mySerial.begin(19200); // set the data rate for the SoftwareSerial port
  Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
}


void loop () {
  
  mySerial.print(0xfa, BYTE); //request Tag code
       
  if(serialAvailable()){
     //keep reading from serial untill there are bytes in the serial buffer
     while (serialAvailable() && bytes_read < TAG_LEN){                //read Serial        
     code[bytes_read] = Serial.read();
     bytes_read++;  // ready to read next digit
     }
  }
  //do somenthing else perhaps wait for other data.
  Serial.println ("NO TAG ");
  
  //print out later in the loop the sentence only if it has actually been collected;
  if( bytes_read >= TAG_LEN){
    for(int i=0; i<bytes_read; i++){
          Serial.print(code[i], HEX);    //print out the byte at the specified index
            Serial.print(",");
    }
    for(int i = 0; i < ARR_LEN; i++)
    {
      if(memcmp(code, target_tag[i], TAG_LEN) == 0 )
      {
          digitalWrite(ledPin, HIGH);
          delay(500);
          digitalWrite(ledPin, LOW);
          delay(500);
      }
    
    }
    Serial.flush(); //flush serial buffer
 }

  Serial.println();
  delay(100);
  bytes_read = 0;
  
  }

Now I'll start cleaning up the code and post a tutorial at the Arduino Playground.
Thank you everybody for the support!
Kind Regards, Loïc

Very nice, congrats!

Big big progress: After I filled the array with more than 60 tags I started to get problems with the 1k byte ram limit of the mega168. Random crashes and the like :cry: I figured that I needed to use PROGMEM to overcome this hurdle. A few hours later in pain I found out that the equivalent of the "memcmp" function when using PROGMEM was "memcmp_P". But here comes the nice part: This function was only added to avr_libc version 1.4.6 and Arduino uses version 1.4.4, couldn't be more convenient ::slight_smile: I compiled the latest avr_libc and replaced parts of the Arduino lib. Guess what, it worked!!! Going rock solid with 75 tags in memory! This is my latest code, cleaned up and filled with comments. With this code you can just copy-paste tags from the serial monitor into the array:

#include <avr/pgmspace.h>
#include <SoftwareSerial.h>

#define rxPin 7 // unused serial pin
#define txPin 2 // software-serial pin used to send the "read uid" command to the reader

#define TAG_LEN 12 // length of a single tag in bytes

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin); // set up a new serial port

int ledPin = 13; //feedback led
int ledPin2 = 6; //feedback led
int checkrfid = 0; // after a scan for tags, this will become:  0 if no tag was read, 1 if tag is recognized, 2 if tag is not recognized, 
byte code[TAG_LEN]; // var that will hold the bytes-in read from the serialBuffer
int bytes_read = 0; // number of bytes read
PROGMEM prog_char target_tag[][TAG_LEN] = //dynamic multidimensional array with known tags. It's stored into flash memory to overcome the 70 tag limit.
{{0x00, 0x00, 0xdd, 0x8e, 0x96, 0x0e, 0x00, 0x01, 0x04, 0xe0, 0x10, 0xc8 },
{0x00,  0x00, 0x1b, 0x4e, 0xc1, 0x0d, 0x00, 0x01, 0x04, 0xe0, 0xd5, 0x7b}};

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT); // setup for software-serial
  pinMode(txPin, OUTPUT); // setup for software-serial
  pinMode(ledPin, OUTPUT); // setup for feedback led
  pinMode(ledPin2, OUTPUT); // setup for feedback led
  mySerial.begin(19200); // set the data rate for the SoftwareSerial port
  Serial.begin(19200);      // opens serial port, sets data rate to 19200 bps
  
}

void loop ()
{
scan(); // do a scan for tags
if(checkrfid == 1) // if tag is recognized
{ 
  fade(); //do function "fade" (see below)
  delay(100);
}
if(checkrfid == 2) // if tag is not recognized
{
  blink(); //do function "blink" (see below)
}
delay(100); //wait before doing a new scan
}



void scan () {
  
  checkrfid = 0; //set "state of recogniton" back to zero
  mySerial.print(0xfa, BYTE); //request Tag code
       
  if(serialAvailable()){ //if data is coming back from the reader
     while (serialAvailable() && bytes_read < TAG_LEN){ //while data is coming back from the reader and not all 12 bytes are read      
     code[bytes_read] = Serial.read(); //add byte
     bytes_read++;  // update number of bytes read
     }
  }
  
  Serial.println ("NO TAG "); //No data has come from the reader so "No Tag" is displayed
  
 
  if( bytes_read >= TAG_LEN) //if 12 bytes were read, print them out
  {
     
      Serial.print("{"); //adds syntax so you can just copy-paste the tag into your code
      for(int i=0; i<bytes_read; i++) //prints all 12 bytes one at a time
      {
          Serial.print("0x"); //more syntax for copy-paste
            Serial.print(code[i], HEX);    //print out the byte in HEX
            Serial.print(", "); //more syntax for copy-paste
      }
      Serial.print("},"); //more syntax for copy-paste
      
      
      
       for(int i = 0; i < ((sizeof(target_tag))/12); i++) //tag is compared to array of known tags, note that the size of the array is dynamic and calculated every time, more ease for copy-paste... 
      {
        if(memcmp_P(code, target_tag[i], TAG_LEN) == 0 ) //uses the PROGMEM variant of memcmp -> memcmp_P This function doesn't work with the standard Arduino 009 IDE, Needs avr-libc 1.4.6.
        {
            checkrfid = 1; //if tag matches, set "checkrfid" to 1
        }
        
      }
      if(checkrfid == 0) //if tag doesn't match, set "checkrfid" to 2
      {
        checkrfid = 2;
      }
      Serial.flush(); //flush serial buffer
     }

    Serial.println(); //print linefeed
    bytes_read = 0; //set number of bytes read back to zero
  }
  
void blink ()
{
  digitalWrite(ledPin, HIGH); // if true blink led
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(500);
}

void fade ()
{ 
  
 int value = 0;
  for(value = 0 ; value <= 255; value+=5) // fade in (from min to max) 
  { 
    analogWrite(ledPin2, value);           // sets the value (range from 0 to 255) 
    delay(30);                            // waits for 30 milli seconds to see the dimming effect 
  } 
  delay(200);
  for(value = 255; value >=0; value-=5)   // fade out (from max to min) 
  { 
    analogWrite(ledPin2, value); 
    delay(30); 
  }
 delay(500); 

 }

Arduino is so great, never thought this would be possible!

Kind Regards, Loïc

Nice one Loic, add it to the playground it would be a great benefit to others searching for RFID options. I think there's a variety of storage options, but I haven't got that far yet ;D

I read something a while back about USB memory sticks or flash memory or something :slight_smile:

Hi,
I am trying to light up LEDs according to the specific Tags read by my Parallax RFID reader. I found your example but i cant get it to work. i dont know how to translate the Tag numbers I am getting i.e. 0415EBD8CC to a char string as this one that you are using:

char target_tag[ARR_LEN][TAG_LEN] =
{{0x00, 0x00, 0xdd, 0x8e, 0x96, 0x0e, 0x00, 0x01, 0x04, 0xe0, 0x10, 0xc8 },
{0x00, 0x00, 0x1b, 0x4e, 0xc1, 0x0d, 0x00, 0x01, 0x04, 0xe0, 0xd5, 0x7b}};

Also the library <avr/pgmspace.h> exists on the web as a text file. Should I copy it somewhere where the Arduino can track it? I have found this link for that library: http://ccrma.stanford.edu/courses/250a/docs/avrgcc/pgmspace_8h-source.html
Is it correct?
]
My code so far that prints out the Tag ID and lights one LED is the basic found in the arduino playground.

#include <SoftwareSerial.h>

int val = 0;
char code[10];
int bytesread = 0;

#define ledPin 12 //need to define it here to read it through the software serial
#define rxPin 7 //connect with SOUT / TX in RFID at 2400bps
#define txPin 9

byte pinState=0;

void setup()
{
Serial.begin(9600); // Hardware serial for Monitor 9600bps

pinMode(ledPin, OUTPUT); //added my pin 12 as an output here

pinMode(2,OUTPUT); // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin
digitalWrite(2, LOW); // Activate the RFID reader
}

void loop()
{
SoftwareSerial RFID = SoftwareSerial(rxPin,txPin);
RFID.begin(2400);

if((val = RFID.read()) == 10)
{ // check for header
bytesread = 0;

while(bytesread<10)
{ // read 10 digit code
val = RFID.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: "); // possibly a good TAG
Serial.println(code); // print the TAG code
Serial.println("");

digitalWrite(ledPin, HIGH); //added this to flicker the LED
delay(30);
digitalWrite(ledPin, LOW);
delay(30);

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

}
}

I hoped that by adding the char string ={{0x00, 0x00, 0xdd, 0x8e, 0x96, 0x0e, 0x00, 0x01, 0x04, 0xe0, 0x10, 0xc8 } nd call it in my loop it would be easy to get my tags, but it looks really complex. any sipmle way to go about this?
thanx