RFID read module: serial writes duplicates

Hi there,

I am working on a RFID-reading sketch on Arduino, of which three tags can be recognized. These tags will make the Arduino choose between Serial.println("1"), Serial.println("2") or Serial.println("3"). This works, but there is a small problem: the Arduino outputs these values ("1","2"or "3") twice or three times at once! That is not quite the desired effect, as I want the output to be printed only once at a time.

Here is the code:

//Code to read data from Parallax RFID reader/writer 28440 via Arduino
//Program reads data from the old EM4100-based tags and prints their value in the serial monitor.

//Code courtesy from http://prototypeit.blogspot.nl/2011/02/arduino-parallax-rfid-readwrite-module_20.html

// Adapted by Jeroen Rood, as of 19-03-2013
// changes made to this sketch are only for school project 
// purposes.

#include <SoftwareSerial.h>

#define txPin 6
#define rxPin 8

SoftwareSerial mySerial(rxPin, txPin);

int  val = 0; // the variable for temporary storage of a char from the RFID-tag ID (10 times used in a ID loop)
char code[12];    //space for 12 chars in the read result
// blue 08000B1673
// yellow 08000AC96E
// red 280015F22E

char tag1[12] = {
  '0', '8', '0', '0', '0', 'A', 'C', '9', '6', 'E'}; // tag YELLOW
char tag2[12] = {
  '0', '8', '0', '0', '0', 'B', '1', '6', '7', '3'}; // tag BLUE
char tag3[12] = {
  '2', '8', '0', '0', '1', '5', 'F', '2', '2' ,'E'}; // tag RED

int bytesread = 0; // a counter for the amount of bytes that have been read (10 is correct for usage - this is the amount of chars from the RFID ID)
int i = 0; // the representation of the port number that has to be set to HIGH (LED)

void establishContact() { // establish a connection with the RFID reader
  while (mySerial.available() <= 0) { 
    mySerial.print("!RW");   
    mySerial.write(0x0F);    
    mySerial.flush();
    delay(1000);
  }
}
void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  establishContact();
  pinMode(7, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT); 
  pinMode(4, OUTPUT);
  pinMode(txPin, OUTPUT);     //pin 6
  pinMode(rxPin, INPUT);      //pin 8
}


void loop()
{
  bytesread=0;
  if (mySerial.available()>0) {
    while (bytesread<10) {
      val=mySerial.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++;
    } 
    if(strcmp(code,tag1) == 0) {
      Serial.println("1");
      i = 4;
    }
    else if(strcmp(code,tag3) == 0) {
      Serial.println("3");
      i = 12; 
    }
    else if(strcmp(code,tag2) == 0) {
      Serial.println("2");
      i = 7;
    }

    for(int a=13;a>3;a--){
      if((a != 6)&&(a != 8)){
        if(a==i){ 
          digitalWrite(a,HIGH); 
        } 
        else{ 
          digitalWrite(a,LOW); 
        }
      }
    }

  } 
  else {
    establishContact();
  }

}

And here is the output (2=blue tag, 1=yellow tag, 3=red tag ... see the Arduino sketch):

2
2
1
1
3
3

It looks like the Serial.println() lines are somehow called twice or three times in a very short period of time. Could anyone explain to me what is going on, or what I can do to fix this problem?

Thanks!
Jeroen

Perhaps, on a processor running at 16MHz,, Serial.println is getting called several times.
Just a thought.
bytesread gets reset every time through loop.

Thanks for the fast reply! :slight_smile:
Okay, so I delayed the resetting of bytesread, by adding the following piece of code to loop() (and of course declaring int count at the start):

    count++; //count only increases 1 per loop-sequence, so only 1 in 1000 loop-sequences the bytesread variable will be reset
    if(count == 1000){
      bytesread=0;
      count=0;
    }

But... this makes the Arduino "go nuts".. if I delay the bytesread variable reset, it prints even more identical lines at once (dramatically more). I guess if the bytesread is not reset, the code[] array will not be updated, and the same code will be checked all the time (resulting into infinite matches).

That made me think that the code[] array might not be updated at the right rate. So I inserted this code at the end of the "if(mySerial.available()>0)"-statement:

while(bytesread > -1){ //reset bytesread AND code[] array
      code[bytesread] = '0';
      bytesread--;
}

..but it looks like this blocks any Serial.println() ... Any thoughts on what I could do next? Should I try to filter this quirky behavior in Processing? (that's the program I will be using for after-Arduino processing and for interactivity).

I delayed the resetting of bytesread, by adding the following piece of code to loop()

I don't understand what you mean.
Please post your code.

Apologies, here it is. The loop() function was the only piece of code that changed, I posted both changes below:

delayed reset of bytesread

void loop()
{

  if (mySerial.available()>0) {
    while (bytesread<10) {
      val=mySerial.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++;
    } 
      if(strcmp(code,tag1) == 0) {
        Serial.println("1");
        i = 4;
      }
      else if(strcmp(code,tag3) == 0) {
        Serial.println("3");
        i = 12; 
      }
      else if(strcmp(code,tag2) == 0) {
        Serial.println("2");
        i = 7;
      }
    for(int a=13;a>3;a--){
      if((a != 6)&&(a != 8)){
        if(a==i){ 
          digitalWrite(a,HIGH); 
        } 
        else{ 
          digitalWrite(a,LOW); 
        }
      }
    }
    count++; //count only increases 1 per loop-sequence, so only 1 in 1000 loop-sequences the bytesread variable will be reset
    if(count == 1000){
      bytesread=0;
      count=0;
    }
  } 
  else {
    establishContact();
  }

}

..which resulted in dramatically more lines to be printed. Probably because code[] would not be updated so often, which resulted into a lot more matches (and thus more println()'s).

reset of both bytesread and the code[] array

void loop()
{
  if (mySerial.available()>0) {
    while (bytesread<10) {
      val=mySerial.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++;
    } 
      if(strcmp(code,tag1) == 0) {
        Serial.println("1");
        i = 4;
      }
      else if(strcmp(code,tag3) == 0) {
        Serial.println("3");
        i = 12; 
      }
      else if(strcmp(code,tag2) == 0) {
        Serial.println("2");
        i = 7;
      }
    for(int a=13;a>3;a--){
      if((a != 6)&&(a != 8)){
        if(a==i){ 
          digitalWrite(a,HIGH); 
        } 
        else{ 
          digitalWrite(a,LOW); 
        }
      }
    }
    while(bytesread > -1){ //reset both bytesread and code[] array
      code[bytesread] = '0';
      bytesread--;
    }
  } 
  else {
    establishContact();
  }

}

..this does not result into any printed lines.

  bytesread=0;
  if (mySerial.available()>0) {
    while (bytesread<10) {
      val=mySerial.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++;
    }

If there is one byte available, read all 10 of them. No, that will NOT work. Nothing that happens after this matters until you fix this problem.

You are not reading the tag data correctly.

Is that the cause of the duplicate serial prints?

I was able to read the tag data. They were stored in a char[12] array code[]. All that had to be done once reading is that the variable bytesread had to be reset (to start at 0 in the code[] array). Bytesread is a counter for the amount of chars that have been read as well as an index for the array.
But it only worked in the original source code (first post), and attempts to fix it resulted in their own problems (my second/third post).

Printing the array code[] resulted in a collection of chars, which is the tag data.

That the code somehow works under certain circumstances does not mean that it is any good. It means that you got lucky. It'd better to be good than lucky.

You need to determine if there is any data to read, and only read that much data. If there are 4 bytes, don't try to read 10, hoping that the other 6 arrive before you read them.

Until then, troubleshooting the rest of the program is a waste of time.

But it only worked in the original source code (first post),

But the code in the first post also suffers from the same flaw -

if (mySerial.available()>0) {
    while (bytesread<10) {
      val=mySerial.read();

.
Without any long delays in the code, it is difficult to see how that worked.

Hello,

I know this topic is dead, but I figured I would take a chance asking if you ever figured out how to stop the duplicate reads, I have the same issue.

I have the same issue.

You have crappy code, too?

Perhaps but it is the code Parallax provided for their board. I have posted a new topic so people may marvel at how crappy the code becomes when I combine mine with theirs.

Ok I figured it out, the RFID reader is continuing so send serial data no matter how long I wait from a single card read. I added a little loop to wait till the reader stops sending data before continuing on with my program like this.

while (rfidSerial.available() > 0){
  //Sit and do nothing and wait for reader to be empyty
  rfidSerial.read();
  Serial.println(i);
  i++;
  delay(100); 
}

Why do you stuff your head in the sand for so long after reading each character? That does nothing to stop the RFID reader from sending data.