Go Down

Topic: RFID compare tags- shortcut works, why? (Read 1 time) previous topic - next topic

anchan

I have an arduino Mega connected to a Parrallax #28140 RFID reader:
http://www.robotshop.com/productinfo.aspx?pc=RB-Plx-129&lang=en-US

I have up to 10 RFID tags that I need to keep track of, so I need to compare RFID tag codes, and do various things- turn on LED's etc.

I am aware of other threads relating to this subject.
http://arduino.cc/forum/index.php/topic,41488.0.html

But I have arrived at a different solution, and would like some feedback on it.  The only catch is that it does not read the entire RFID code.  It basically reads all numerical digits up to the first letter character.  So in my case, I only need to differentiate between 10 tags so its fine.  If you are running a walmart, and need 12-byte resolution, this method is not for you.

In the example below, the full RFID code is something like 8400356D0FXXX, but it will only store the numeric digits.  I basically bring in code as an array of chars, then use atol() to convert it to a long.  I'm not really sure why this works, since atol() seems to require a string, and I do not have a string, rather an array of chars.

Code is basically stock playground code, modified just a bit. Is using atol() like this legit? I'm still a little sketchy with serial.


// RFID reader for Arduino
// Wiring version by BARRAGAN <http://people.interaction-ivrea.it/h.barragan>
// Modified for Arudino by djmatic


int  val = 0;
char code[10];
int bytesread = 0;
unsigned long testNumber = 0;

//if rfid values match, turn on LED's
int lightSenseLED = 2;

void setup() {

  pinMode(lightSenseLED, OUTPUT);


  Serial.begin(9600);   // send output to console so can see it
  Serial1.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
  pinMode(5,OUTPUT);   // Set digital pin 5 as OUTPUT to connect it to the RFID //ENABLE pin
  digitalWrite(5, LOW);                  // Activate the RFID reader



void loop() {

  if(Serial1.available() > 0)
  {          // if data available from reader
    if((val = Serial1.read()) == 10) {   // check for header
      bytesread = 0;
      while(bytesread<10) {              // read 10 digit code
        if( Serial1.available() > 0) {
          val = Serial1.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
        testNumber = atol(code);
        Serial.print("atol()# ");       // partially truncated number stored as long
        Serial.println(testNumber);            // print this number for debugging
      }
      bytesread = 0;
      //testNumber = 0;
      digitalWrite(5, HIGH);                  // deactivate the RFID reader for a moment so it will not flood
      delay(500);                       // wait for a bit
      digitalWrite(5, LOW);              // Activate the RFID reader
    }
    if (testNumber == 8400356)
    {
      digitalWrite(lightSenseLED,HIGH);
      delay(2000);
      digitalWrite(lightSenseLED,LOW);
      delay(2000);
    }
    else
      digitalWrite(lightSenseLED,LOW);
  }

}// end of loop()





Sembazuru


...
In the example below, the full RFID code is something like 8400356D0FXXX, but it will only store the numeric digits.  I basically bring in code as an array of chars, then use atol() to convert it to a long.  I'm not really sure why this works, since atol() seems to require a string, and I do not have a string, rather an array of chars.
...


Ah, yes. But an array of characters _is_ a string (note the lowercase "S", also referred to as a "C string"). Especially if there is a null (value 0x00) as the next element of the array after the last character. Luckily, the way arrays are defined the last element is always null, unless one accidentally overwrites it.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

anchan

#2
May 08, 2013, 03:53 am Last Edit: May 08, 2013, 03:59 am by anchan Reason: 1


Ah, yes. But an array of characters _is_ a string (note the lowercase "S", also referred to as a "C string"). Especially if there is a null (value 0x00) as the next element of the array after the last character. Luckily, the way arrays are defined the last element is always null, unless one accidentally overwrites it.


Ok.  I was thinking that another conversion has to happen to make an array of chars a string.  But good to know, and thank you.  So I take it you don't see anything wrong with this shortcut method for comparing RFID tags, and with this use of atol()?

I was just reading about strtol().  It looks like this might allow me to read and convert the letter values as well, thereby interpreting the entire code, not just the numeric values which atol() restricts me to.

Sembazuru




Ah, yes. But an array of characters _is_ a string (note the lowercase "S", also referred to as a "C string"). Especially if there is a null (value 0x00) as the next element of the array after the last character. Luckily, the way arrays are defined the last element is always null, unless one accidentally overwrites it.


Ok.  I was thinking that another conversion has to happen to make an array of chars a string.  But good to know, and thank you.  So I take it you don't see anything wrong with this shortcut method for comparing RFID tags, and with this use of atol()?

I was just reading about strtol().  It looks like this might allow me to read and convert the letter values as well, thereby interpreting the entire code, not just the numeric values which atol() restricts me to.


If it works with your set of tags, great. But there is always a chance that someone will have a set of tags that has at least two that are close enough together in numbering sequence that those 3 least significant digits are the only difference. When those tags are manufactured they are (probably) assigned consecutive numbers. If you just happen to have two from the same batch they will likely have very close serial numbers.
http://www.catb.org/jargon/html/I/I-didn-t-change-anything-.html

PaulS

Quote
But an array of characters _is_ a string (note the lowercase "S", also referred to as a "C string"). Especially if there is a null (value 0x00) as the next element of the array after the last character.

No!!! An array of characters that is NULL terminated is a string. Without the NULL terminator, the array of chars is NOT a string.

OP: Your code works without NULL terminating the char array because atol() function looks for a NULL terminator OR the first non-numeric value. Since your string contains non-numeric values, you get away without the NULL.

It is not good practice, though. Adding the NULL terminator is trivially simple, and should be done as a matter of practice, every time you add a character to an array.
The art of getting good answers lies in asking good questions.

anchan

How do I add a NULL character in my particular code?  Trivially simple if you know how to do it:) I still have a lot to learn in working with strings. 


Quote

OP: Your code works without NULL terminating the char array because atol() function looks for a NULL terminator OR the first non-numeric value. Since your string contains non-numeric values, you get away without the NULL.

It is not good practice, though. Adding the NULL terminator is trivially simple, and should be done as a matter of practice, every time you add a character to an array.

PaulS

Quote
How do I add a NULL character in my particular code?

First, you need to make the array large enough to hold the additional character:
Code: [Select]
char code[11];

This:
Code: [Select]
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit

can be done in one statement:
Code: [Select]
          code[bytesread++] = val;         // add the digit       

Then, to add the character and keep the array NULL terminated:
Code: [Select]
          code[bytesread++] = val;         // add the digit
          code(bytesread] = '\0';             // add the NULL


Notice that you do not increment the index after adding the NULL.
The art of getting good answers lies in asking good questions.

anchan

Thank you Paul. Works as promised.  Here is the final test code for the "rfid compare shortcut method," with added NULL char, for anyone who may be interested.

Code: [Select]
// RFID reader for Arduino
// Wiring version by BARRAGAN <http://people.interaction-ivrea.it/h.barragan>
// Modified for Arudino by djmatic
// Modified by A. Tomasulo


int  val = 0;
char code[11];
int bytesread = 0;
unsigned long testNumber = 0;

//if rfid values match, turn on LED's
int lightSenseLED = 2;      //change for your particular setup
int touch1LED = 4;        //change for your particular setup
int touch2LED = 6;        //change for your particular setup

void setup() {
// Change to suit your particular setup
  pinMode(lightSenseLED, OUTPUT);
  pinMode(touch1LED, OUTPUT);
  pinMode(touch2LED, OUTPUT);
  digitalWrite(lightSenseLED,0);
  digitalWrite(touch1LED,0);
  digitalWrite(touch2LED,0);

  Serial.begin(9600);   // send output to console so can see it
  Serial1.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
  pinMode(5,OUTPUT);   // Set digital pin 5 as OUTPUT to connect it to the RFID /ENABLE pin
  digitalWrite(5, LOW);                  // Activate the RFID reader



void loop() {

  if(Serial1.available() > 0)         // if data available from reader
  {           
    if((val = Serial1.read()) == 10)
    {   // check for header
      bytesread = 0;
      while(bytesread<10) {              // read 10 digit code
        if( Serial1.available() > 0) {
          val = Serial1.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           
          code[bytesread] = '\0';           // add NULL character
        }
      }
      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
        testNumber = atol(code);
        Serial.print("atol()# ");       // possibly a good TAG
        Serial.println(testNumber);            // print the TAG code
      }
      bytesread = 0;

      digitalWrite(5, HIGH);                  // deactivate the RFID reader for a moment so it will not flood
      delay(500);                       // wait for a bit
      digitalWrite(5, LOW);
    } //end of if((val = Serial1.read()) == 10)
    if (testNumber == 84003576) //RFID test case here. Use #'s before first letter char
    {
      digitalWrite(lightSenseLED,HIGH);
      delay(2000);
      digitalWrite(lightSenseLED,LOW);
      delay(2000);
      testNumber = 0;
    }
    else
      digitalWrite(lightSenseLED,LOW);
         
  }  //end of if(Serial1.available() > 0) 

}// end of loop()

// extra stuff
// digitalWrite(2, HIGH);             // deactivate RFID reader




Go Up