Calculating duration (ms) that RFID tag is present at Parallax RFID reader

Hello all, first post for me today. Please forgive me, as it will be a long post. Let me know if this belongs in the ‘programming’ section instead of the ‘projects’ section, and I will gladly move it. I am usually pretty good about troubleshooting my own issues, but I’m a bit stumped this time.

Here’s what I am trying to do: I have some cows with RFID tags in their ears. I want to use an RFID reader to determine how much time the cows spend in specific parts of their pen via an arduino.

I have an Arduino Mega 2560 that I have interfaced with a Parallax RFID read/write serial module (#28440). See http://www.parallax.com/product/28440 for product and http://www.parallax.com/sites/default/files/downloads/28440-RFID-Read-Write-Documentation-v1.0.pdf for supporting documentation.

The connections are very simple and straight-forward:
Arduino 5v → Parallax VCC
Arduino GND → Parallax GND
Arduino pin 9 → Parallax SIN
Arduino pin 10 → Parallax SOUT

I used <SoftwareSerial.h> to establish the serial connection on pins 9 and 10.

I found enough demo code online that I am able to read and write to RFID tags (http://www.parallax.com/product/32399) without issue. These tags have 29 addresses to read/write to, with 4 data bytes per address, totaling 116 bytes of user-definable data.

Here are the steps that need to happen in the code:


1. Enable the RFID reader (in read mode)

The reader needs to constantly be in ‘read mode’. This step is fairly easy, actually.

2. Read any incoming tags (incoming tags have 5 bytes, 1 status byte and 4 data bytes)

This step is okay too. The first byte received is the status byte indicating whether the read had any errors. If status == 1, then read had no errors. I wrote the first and last data byte of each tag at address 3 to be ‘254’ as check values, and the second and third values of each tag at address 3 represent a unique ID number.

3. Check status byte for errors

This is easy enough. As long as the first byte received == 1, good to go.

4. Validate tag using first and last byte as 'check values’

If the first and last data bytes of address 3 == 254, proceed.

3. If read has no errors and tag is valid, while tag is present, begin a timer (likely using the millis() function)

I can do the if statement, but the while and timer are difficult for me.

4. When tag is no longer present, stop the timer

… Can’t stop the timer if I never get it started…

5. Send a line of data including the tag number and the elapsed time to serial (likely to an SD, but not yet implemented)

This step shouldn’t be very difficult if I can manage to get the time calculated and stored as a long variable.

6. Repeat the process ad infinitum


The problem I am having is with the ‘while tag is present, begin a timer’ and ‘when tag is no longer present, stop the timer’ functionality. I’m not sure how to keep a real-time indicator of whether or not a valid tag is present. I thought my attempt would do it, but apparently not.

My attempt to achieve this is below:

#include "SoftwareSerial.h"
#define RFID_READ 0x01   // command byte to put RFID module in 'read' mode
#define txPin 9          // to SIN
#define rxPin 10         // to SOUT

SoftwareSerial mySerial(rxPin, txPin);

int ADDRESS = 3;         // Which line on the RFID tag to read
int readStatus = 0;      // Variable to hold status byte
int printAddress = 1;    // Print address when printing tag data? (1 = Yes; 0 = No)
int tag[4];              // Character array to hold 4 bytes of data
int validTag = 0;        // Logic indicating whether a valid tag is present (0 = False)
long startTime;          // Variable to store millis() when timer is activated
long duration = 0;       // Variable to store duration of each valid RFID event
int msDelay = 1000;      // delay (ms) between tag reads 

void setup()
{
  Serial.begin(9600);               // Begin serial communications at 9600 baud
  Serial.println("RFID Read Test"); // Print header
  //Serial.print("ID, ");           // Print column names for .csv output
  //Serial.println("Time(ms)");
  mySerial.begin(9600);             // Begin serial communications for mySerial at 9600 baud
  pinMode(txPin, OUTPUT);           // Declare txPin as OUTPUT
  pinMode(rxPin, INPUT);            // Declare rxPin as INPUT
}



void loop()
{
  enableRFID();        // Put RFID module in active read mode
  readRFIDTag();       // Read RFID tag
  validateTag();       // Ensure that check values on tag are valid
  tagTime();           // Calculate elapsed time that tag is present
  sendTagTime();       // Send elapsed time and ID to serial
  //printTag();          // Print tag ID and address if valid tag
  //delay(msDelay);      // interval delay between RFID reads (for testing purposes)
}


// Function to activate RFID reader

void enableRFID() {
   mySerial.print("!RW");
   mySerial.write(byte(RFID_READ));
   mySerial.write(byte(ADDRESS));
}
 
// Function to suppress the "null result" from being printed if no RFID tag is present 
  
void suppressAll()                               
{
    if(mySerial.available() > 0){ 
        mySerial.read();
        suppressAll();
    }
}


// Function to read RFID Tag

void readRFIDTag() {
  
  // supress all tag reads with status code != 1 (status code = 1 means no error)
  if(mySerial.available() > 0) {
     readStatus = mySerial.read();
     if (readStatus != 1){
       suppressAll();
     }
  }
  
  if (readStatus == 1) {
  
  // Extract first byte of data
  if(mySerial.available() > 0) {
     tag[0] = mySerial.read();
     }
     
  // Extract second byte of data
  if(mySerial.available() > 0) {
     tag[1] = mySerial.read();
     }
     
  // Extract third byte of data
  if(mySerial.available() > 0) {
     tag[2] = mySerial.read();
     }
     
  // Extract fourth byte of data
  if(mySerial.available() > 0) {
     tag[3] = mySerial.read();
     }
  }
  else {
    tag[0] = 0;
    tag[1] = 0;
    tag[2] = 0;
    tag[3] = 0;
  }
  
  }
 
// Function to indicate valid tag is present

void validateTag() {
if (tag[0] == 254 & tag[3] == 254) {
  validTag = 1;
}
else {
  validTag = 0;
}

}
  
// Function to send RFID code to serial.print()
 
void printTag() {

  // Check that a tag read had no errors and is a valid tag
  
  if (readStatus == 1 & validTag == 1) {
 
  // Send read address to serial
  if(printAddress != 0) {
     Serial.print("Address:");
     Serial.println(ADDRESS);
     }
 
  // Send byte 1 and byte 2 (2-digit ID) to serial
  Serial.print("TAG:");
  Serial.print(tag[1], DEC);
  Serial.print(tag[2], DEC);
  Serial.println();
 
  }
}

// Function to begin count when a valid tag is present

void tagTime() {
  
  if (validTag == 1) {
    startTime = millis();
    
    while (validTag == 1) { 
      duration = millis() - startTime;
        if (validTag == 0) {
          break;
        }
    }
  }
}

// Function to send Tag and elapsed time to serial

void sendTagTime() {
 if (duration >= 100) {
  Serial.print(tag[1]);
  Serial.print(tag[2]);
  Serial.print(", ");
  Serial.println(duration);
 } 
}

I’ve commented out the tagTime() and sendTagTime() functions in the loop(), as they aren’t working at the moment, but my attempts at the functions are included.

Any help with getting the arduino to ‘know’ a valid tag is present, and then time the event would be greatly appreciated. Thank you all in advance.

You aren't reading the tag in tagTime, so it will never change, and thus, never exit the while(), and of course, never return to loop().

I'm not famailiar with RFID, but it would seem to me that enabling the reader would need to be done only once, so it probably should be moved to setup().

tagTime() should probaably not use a while loop, unless you want to call your read and validate functions from within the while(). Another way is this: If tagTime() simply checks the latest result of reading the tag, and it's still valid, and stil the same tag number, just make duration equal the current duration. If you find the tag no longer there, send duration. As well, you startTime should be a global variable so it isn't initialized each time tagTime() is called. It's currently a global variable, but tagTime() never changes the global, but only changes the local variable of the same name. Here's a sample.

void tagTime() {
   if (validTag == 1 && tag_is_timing)  {   // boolean global variable added (validTag could be boolean too)
      duration = millis() - startTime;
   }
   else {
      break;
   }
}

There are a few other problems you will run into. You should only start timing if you have a validTag detected. You should only report the time if it [u]was[/u] timing, but no validTag is detected.

lar3ry:

Thanks so much for your response. I've got a few questions for you (please forgive my ignorance):

You aren't reading the tag in tagTime, so it will never change, and thus, never exit the while(), and of course, never return to loop().

I'm not sure why I would have to. As I understand it, the global variable validTag is all I referenced in order to start the timer function. Why would I need to read the tag in tagTime if the tag itself as well as the validTag and readStatus are global variables?

I'm not famailiar with RFID, but it would seem to me that enabling the reader would need to be done only once, so it probably should be moved to setup().

I tried, and the reader activated momentarily, but did not stay activated. It's a power-saving feature, essentially. You have to turn it on every time you want to use it.

If tagTime() simply checks the latest result of reading the tag, and it's still valid, and stil the same tag number, just make duration equal the current duration. If you find the tag no longer there, send duration

I think this is what I am trying to do. Essentially, the global variable startTime should be the current millis() when validTag changes from 0 to 1, and duration should be the difference between current millis() and startTime when validTag switches back to 0.

As well, you startTime should be a global variable so it isn't initialized each time tagTime() is called. It's currently a global variable, but tagTime() never changes the global, but only changes the local variable of the same name.

I declared startTime as a global variable because I wanted that variable, whatever value it may take on, to be available to all functions. How do I get tagTime() to change the global variable instead of just a local variable by the same name? Probably a stupid questions that I should already know the answer to.

void tagTime() {
   if (validTag == 1 && tag_is_timing)  {   // boolean global variable added (validTag could be boolean too)
      duration = millis() - startTime;
   }
   else {
      break;
   }
}

What were you intending by the tag_is_timing? Did you mean to create a boolean global variable that indicates whether or not the timer is running? Why would I need it there?

I'll try out what you gave me for the tagTime() function and see what happens, minus the tag_is_timing logic. Thanks again for your help, and I hope to hear from you soon.

sellersmd: I've got a few questions for you (please forgive my ignorance)

Of course! We are all beginners for a while, in anything we try.

I'm not sure why I would have to. As I understand it, the global variable validTag is all I referenced in order to start the timer function. Why would I need to read the tag in tagTime if the tag itself as well as the validTag and readStatus are global variables?

Well, here's what happens. Normally, loop() will keep running, repeating the read and validate, but when you get into tagTime(), you loop with a while (validTag == 1), and keep looping until it's 0. Unfortunately, you are stuck in that loop until validTag == 0, which means that you have to read the tag again, then validate it again. You can do that one of two ways.

  1. Call enableRFID(), readRFIDTag(), and validateTag() within your while loop. OR
  2. Allow tagTime to exit, returning to the next statement in loop(). When the enable, read, verify comes around again, validTag will have a chance to be updated.

I'm not famailiar with RFID, but it would seem to me that enabling the reader would need to be done only once, so it probably should be moved to setup().

I tried, and the reader activated momentarily, but did not stay activated. It's a power-saving feature, essentially. You have to turn it on every time you want to use it.

Fair enough. Best leave it right where you flang it then.

I declared startTime as a global variable because I wanted that variable, whatever value it may take on, to be available to all functions. How do I get tagTime() to change the global variable instead of just a local variable by the same name? Probably a stupid questions that I should already know the answer to.

Of course, you're right. I have no idea whay I thought startTime was being re-declared. You are changing the global variable. My humble apologies.

What were you intending by the tag_is_timing? Did you mean to create a boolean global variable that indicates whether or not the timer is running? Why would I need it there?

I was thinking that if you keep the enable, read, validate in loop(), you will need to know when you start timing, and on subsequent calls, you will need to know that you are timing, so that when validTag becomes zero, you can report the time. You don't need to worry about that if you call the enable, read, validate from within the while loop.

Thanks again, lar3ry. People like you make these forums go 'round. I think I am starting to understand what you mean in regards to the problem with my while loop.

Well, here's what happens. Normally, loop() will keep running, repeating the read and validate, but when you get into tagTime(), you loop with a while (validTag == 1), and keep looping until it's 0. Unfortunately, you are stuck in that loop until validTag == 0, which means that you have to read the tag again, then validate it again.

If I understand correctly, the way I had written it, the reader gets enabled, reads a tag, validates it, and then once it gets in the while loop, the other functions stop because they aren't present inside the while loop, and it basically just sits there waiting for the validTag variable to change but it never does because we aren't reading the tag anymore while we are inside the loop? Sounds like a problem.

That explains the anomaly I was experiencing with the status LED on the RFID module. When the module is in 'read mode,' the LED is red, and when the module is in 'idle mode,' the LED is green. During my previous sketches, the LED would be constant red until I passed an RFID tag, when it would turn green permanently. Stuck in the while loop and no longer performing the enableRFID() function. That makes perfect sense, in retrospect.

I've attempted to implement what you said, but I'm still not getting any results sent to serial. Here is what I re-wrote for the tagTime():

void tagTime() {
  if(validTag = true) {
    while (validTag == true) {
      startTime = millis();
      enableRFID();
      readRFIDTag();
      validateTag(); 
      if(validTag == false) {
        duration = millis() - startTime;
        break;
      } 
    }
  }
}

Any further suggestions? I would be willing to compensate you for your time (to the best of my graduate-student ability), as I know these problems require a good deal of brain power to work through. Thanks again.

sellersmd: If I understand correctly, the way I had written it, the reader gets enabled, reads a tag, validates it, and then once it gets in the while loop, the other functions stop because they aren't present inside the while loop, and it basically just sits there waiting for the validTag variable to change but it never does because we aren't reading the tag anymore while we are inside the loop? Sounds like a problem.

Exactly right!. Loop() will keep going as long as whatever other functions you call, return. If a function called from loop() does not return, nothing more in loop() will run.

void tagTime() {
  if(validTag = true) {
    while (validTag == true) {
      startTime = millis();
      enableRFID();
      readRFIDTag();
      validateTag(); 
      if(validTag == false) {
        duration = millis() - startTime;
        break;
      } 
    }
  }
}

There are a few problems in this code. The statement if (validTag = true) says "assign true to validTag", so it isn't really an if. The proper operator is == which is a comparison, as opposed to = which is an assignment. Everyone makes this error many times over.

The if() and while() can be written as

  if(validTag) {
    while (validTag ) {

Any expression that can result in true/false, or non-zero/zero can be written this way.

Another problem is that the location of the startTime = millis(); statement is not right. Consider: the while loop will execute all statements between the curly braces, so startTime will be continually updated. When the RFID tag goes out of range, startTime will be the millis() value when the RFID tag was last validated, and NOT when the first validTag was detected. If you just move that statement up above the while(), and just after the if(), it will do what you want.

Putting a (temporary) Serial.println() just before the break; would help to make sure you are doing it right (just in case there's other problems in the code).

Any further suggestions? I would be willing to compensate you for your time (to the best of my graduate-student ability), as I know these problems require a good deal of brain power to work through. Thanks again.

Not right now... give that a shot and see if it works. I don't know offhand what the range of a reader is, so I am wondering if two tags could be in range, which might be a problem. I'll llook over the rest of your code for anyything else obviously wrong.

Just out of curiosity, where are these going to be located? In a passageway? Watering bowl? Oiler? Salt block? I live on a farm in Saskatchewan, and have a lot of neighbours with cattle and horses. Just wonderingif something like this might be useful for them. I know i was having problems with one of my horses, who kept jumping the fence to get away from the herd boss. I came prretty closse to working out a tracker for her, but ended up getting rid of her instead.

As for compensation, I wouldn't hear of it. I'm here to help and learn, and to keep my mind sharp.

Thanks for another informative reply, lar3ry.

The if (validTag = true) was a rookie typing mistake that I should have caught myself. The prior version of the sketch didn't have that issue.

I see your point about the startTime variable continually being altered every time we loop, and I think I've got it in a better spot.

I've also added some functionality to make sure that, A, not only is a valid tag read in the loop, but also that, B, the unique identification number of the tag read in the while loop continually matches the unique ID of the initial read. if either of these conditions aren't met, the loop breaks, I think. Emphasis on think.

To answer your questions:

I don't know offhand what the range of a reader is, so I am wondering if two tags could be in range, which might be a problem.

To tell the truth, I'm not overly thrilled with the current reader, which has a reading range of around 4 inches. This pretty much negates any opportunity for two tags to be read simultaneously, given the size of Holstein cows. This is just my first prototype for a large-scale project, however, and in the future iteration of the project, I would like a read range of around 8-12 inches.

Just out of curiosity, where are these going to be located? In a passageway? Watering bowl?  Oiler? Salt block? I live on a farm in Saskatchewan, and have a lot of neighbours with cattle and horses. Just wonderingif something like this might be useful for them. I know i was having problems with one of my horses, who kept jumping the fence to get away from the herd boss. I came prretty closse to working out a tracker for her, but ended up getting rid of her instead.

The plan is to have one placed at every headlock in a pen,

with the intent of knowing how long each day any given cow spends at the feed bunk.

Here's the updated code in it's entirety, but the biggest changes are in the tagTime() function and the addition of the initialTag versus currentTag comparison. I also added a clearCache() function that resets all variables to null (or 0) when the tag is no longer present. The code still isn't doing what I think it should be. Please let me know what you think! Thanks again.

#include "SoftwareSerial.h"
#define RFID_READ 0x01   // command byte to put RFID module in 'read' mode
#define txPin 9          // to SIN
#define rxPin 10         // to SOUT

SoftwareSerial mySerial(rxPin, txPin);

int ADDRESS = 3;             // Which line on the RFID tag to read
int readStatus = 0;          // Variable to hold status byte
boolean printAddress = true; // Print address when printing tag data? (1 = Yes; 0 = No)
int tag[4];                  // Integer array to hold 4 bytes of data for each RFID read
int initialTag[2];           // Integer array to hold 2 ID bytes of 'first read' tag
int currentTag[2];           // Integer array to hold 2 ID bytes of 'follow tag reads'
boolean validTag = false;    // Logic indicating whether a valid tag is present (0 = False)
long startTime;              // Variable to store millis() when timer is activated
long duration = 0;           // Variable to store duration of each valid RFID event
int msDelay = 500;           // delay (ms) between tag reads

void setup()
{
  Serial.begin(9600);               // Begin serial communications at 9600 baud
  Serial.println("RFID Read Test"); // Print header
  //Serial.print("ID, ");             // Print column names for .csv output
  //Serial.println("Time(ms)");
  mySerial.begin(9600);             // Begin serial communications for mySerial at 9600 baud
  pinMode(txPin, OUTPUT);           // Declare txPin as OUTPUT
  pinMode(rxPin, INPUT);            // Declare rxPin as INPUT
}



void loop()
{
  enableRFID();        // Put RFID module in active read mode
  readRFIDTag();       // Read RFID tag
  validateTag();       // Ensure that check values on tag are valid
  storeInitialTag();    // Store first-read tag
  tagTime();           // Calculate elapsed time that tag is present
  sendTagTime();       // Send elapsed time and ID to serial
  //printTag();          // Print tag ID and address if valid tag
  //delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  clearCache();
}


// Function to activate RFID reader

void enableRFID() {
   mySerial.print("!RW");            // Send ASCII character "!RW" to begin serial connection with RFID module
   mySerial.write(byte(RFID_READ));  // Send the RFID_READ byte to RFID module
   mySerial.write(byte(ADDRESS));    // Send the address that we want to read from
}

// Function to suppress the "null result" from being printed if no RFID tag is present 
  
void suppressAll()                               
{
    if(mySerial.available() > 0){ 
        mySerial.read();
        suppressAll();
    }
}


// Function to read RFID Tag

void readRFIDTag() {
  
  // supress all tag reads with status code != 1 (status code = 1 means no error)
  if(mySerial.available() > 0) {
     readStatus = mySerial.read();
     if (readStatus != 1){
       suppressAll();
     }
  }
  
  if (readStatus == 1) {
  
  // Extract first byte of data
  if(mySerial.available() > 0) {
     tag[0] = mySerial.read();
     }
     
  // Extract second byte of data
  if(mySerial.available() > 0) {
     tag[1] = mySerial.read();
     }
     
  // Extract third byte of data
  if(mySerial.available() > 0) {
     tag[2] = mySerial.read();
     }
     
  // Extract fourth byte of data
  if(mySerial.available() > 0) {
     tag[3] = mySerial.read();
     }
  }
  
  }

// Function validate tag against check criteria

void validateTag() {
if (tag[0] == 254 && tag[3] == 254) {
  validTag = true;
}
else {
  validTag = false;
}

}

// function to store initial valid tag for comparison

void storeInitialTag() {
  if (validTag == true) {
    initialTag[1] = tag[1];
    initialTag[2] = tag[2];
  }
  else {
    clearCache();
  }
}

    
  
// Function to send RFID code to serial.print()

void printTag() {

  // Check that a tag read had no errors and is a valid tag
  
  if (validTag == true) {

  // Send read address to serial
  if(printAddress == true) {
     Serial.print("Address:");
     Serial.println(ADDRESS);
     }

  // Send byte 1 and byte 2 (2-digit ID) to serial
  Serial.print("TAG:");
  Serial.print(tag[1], DEC);
  Serial.print(tag[2], DEC);
  Serial.println();

  }
}

// Function to begin count when a valid tag is present

void tagTime() {
  if(validTag == true) {
    startTime = millis();
    currentTag[1] = initialTag[1];
    currentTag[2] = initialTag[2];
    while (validTag == true && currentTag[1] == initialTag[1] && currentTag[2] == initialTag[2]) {
      Serial.println("in while loop");
      enableRFID();
      readRFIDTag();
      validateTag();
      if (validTag == true && tag[1] == initialTag[1] && tag[2] == initialTag[2]) {
        currentTag[1] = tag[1];
        currentTag[2] = tag[2];
      }
      delay(msDelay); 
      if(validTag == false || currentTag[1] != initialTag[1] || currentTag[2] != initialTag[2] ) {
        duration = millis() - startTime;
        Serial.println("exited while loop");
        break;
      } 
    }
  }
}

// Function to send Tag and elapsed time to serial

void sendTagTime() {
 if (duration >= 100) {
  Serial.print(initialTag[1]);
  Serial.print(initialTag[2]);
  Serial.print(", ");
  Serial.println(duration);
 } 
}

//Function to clear all stored variables

void clearCache() {
  tag[0] = 0;
  tag[1] = 0;
  tag[2] = 0;
  tag[3] = 0;
  validTag = false;
  duration = 0;
}

I have a global boolean variable I have created. If I serial print the status of the variable directly from the loop(), I get either 0 or 1 as I should depending on the condition being met or not. I have a defined function that is only supposed to run if that boolean variable is true. when I serial print that status of the boolean variable from within the function, I get either 0 (false) or 9 (true) - any one have any sort of explanation?

sellersmd: I've also added some functionality to make sure that, A, not only is a valid tag read in the loop, but also that, B, the unique identification number of the tag read in the while loop continually matches the unique ID of the initial read. if either of these conditions aren't met, the loop breaks, I think. Emphasis on think.

I see several problems, not all of which may be causing problems:

  • int initialTag[2]: creates a 2 element array. Later, you refer to initialTag[2], which is one element beyond the end of that array. Same thing with currentTag[2];
  • Your comment after the statement int tag[4]; says you are declaring an array of 4 bytes,
  • You set initialTag[] before calling timeTag(), but after you enable/read/validate within the while(), you don't set it again.
  • You have an if() and a while() that check initialTag against currentTag, and another if() that checks initialTag[] against tag[]. You have to decide what criteria consitute continuing to monitor, and what constitutes reason to report the time.
  • You have a function that calls itself. Recursion can be useful, but it must be used carefully, lest you run out of memory. When you don't detect a tag, what, exactly is returned from the read?

Here's the updated code in it's entirety, but the biggest changes are in the tagTime() function and the addition of the initialTag versus currentTag comparison. I also added a clearCache() function that resets all variables to null (or 0) when the tag is no longer present. The code still isn't doing what I think it should be. Please let me know what you think! Thanks again.

OK, I'll continue looking it over, but it would be helpful if you could tell me what is happening that you don't expect. That will narrow down the areas to examine.

Please supply us with the code that's doing this. If it's too long, you could write a small sketch that illustrates the problem. If you can't illustrate the problem in a small sketch, I would suspect a memory problem of some sort; perhaps running out; perhaps accessing too many elements in an array, etc.

EDIT: I think this issue was related to mis-referencing values in an array, I think I was calling or writing to some place that I shouldn't have been. Issue resolved.

lar3ry - we meet again. Same RFID cow sketch as before:

#include "SoftwareSerial.h"
#define RFID_READ 0x01   // command byte to put RFID module in 'read' mode
#define txPin 9          // to SIN
#define rxPin 10         // to SOUT

SoftwareSerial mySerial(rxPin, txPin);

int ADDRESS = 3;             // Which line on the RFID tag to read
int readStatus = 0;          // Variable to hold status byte
boolean printAddress = true; // Print address when printing tag data? (1 = Yes; 0 = No)
int tag[4];                  // Integer array to hold 4 bytes of data for each RFID read
int initialTag[2];           // Integer array to hold 2 ID bytes of 'first read' tag
int currentTag[2];           // Integer array to hold 2 ID bytes of 'follow tag reads'
boolean validTag = false;    // Logic indicating whether a valid tag is present (0 = False)
int msDelay = 250;           // delay (ms) between tag reads
boolean tagMatch = false;
long startTime;
long duration = 0;

void setup()
{
  Serial.begin(9600);               // Begin serial communications at 9600 baud
  Serial.println("RFID Read Test"); // Print header
  //Serial.print("ID, ");             // Print column names for .csv output
  //Serial.println("Time(ms)");
  mySerial.begin(9600);             // Begin serial communications for mySerial at 9600 baud
  pinMode(txPin, OUTPUT);           // Declare txPin as OUTPUT
  pinMode(rxPin, INPUT);            // Declare rxPin as INPUT
}



void loop()
{
  enableRFID();        // Put RFID module in active read mode
  readRFIDTag();       // Read RFID tag
  validateTag();       // Ensure that check values on tag are valid
  //storeInitialTag();   // Store first-read tag
  //tagTime();           // Calculate elapsed time that tag is present
  //sendTagTime();       // Send elapsed time and ID to serial
  printTag();          // Print tag ID and address if valid tag
  delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  //clearCache();
}


// Function to activate RFID reader

void enableRFID() {
   mySerial.print("!RW");            // Send ASCII character "!RW" to begin serial connection with RFID module
   mySerial.write(byte(RFID_READ));  // Send the RFID_READ byte to RFID module
   mySerial.write(byte(ADDRESS));    // Send the address that we want to read from
}

// Function to suppress the "null result" from being printed if no RFID tag is present 
  
void suppressAll()                               
{
    if(mySerial.available() > 0){ 
        mySerial.read();
        suppressAll();
    }
}


// Function to read RFID Tag

void readRFIDTag() {
  
  // supress all tag reads with status code != 1 (status code = 1 means no error)
  if(mySerial.available() > 0) {
     readStatus = mySerial.read();
     if (readStatus != 1){
       suppressAll();
     }
  }
  
  if (readStatus == 1) {
  
  // Extract first byte of data
  if(mySerial.available() > 0) {
     tag[0] = mySerial.read();
     }
     
  // Extract second byte of data
  if(mySerial.available() > 0) {
     tag[1] = mySerial.read();
     }
     
  // Extract third byte of data
  if(mySerial.available() > 0) {
     tag[2] = mySerial.read();
     }
     
  // Extract fourth byte of data
  if(mySerial.available() > 0) {
     tag[3] = mySerial.read();
     }
  }
  else {
    clearCache();
  }

  
  }

// Function to validate tag against check criteria

void validateTag() {
if (tag[0] == 254 && tag[3] == 254) {
  validTag = true;
  }
else {
  validTag = false;
  }
}


// function to store initial valid tag for comparison

void storeInitialTag() {
  if (validTag == true) {
    initialTag[1] = tag[1];
    initialTag[2] = tag[2];
  }
  else {
    initialTag[1] = 0;
    initialTag[2] = 0;
  }
}

// Function to send RFID code to serial.print()

void printTag() {

  // Check that a tag read had no errors and is a valid tag
  
  if (validTag == true) {

  // Send read address to serial
  if(printAddress == true) {
     Serial.print("Address:");
     Serial.println(ADDRESS);
     }

  // Send byte 1 and byte 2 (2-digit ID) to serial
  Serial.print("TAG:");
  Serial.print(tag[1]);
  Serial.print(tag[2]);
  Serial.println();

  }
}

// Function to see if currentTag matches initialTag

void tagsMatch() {
  if (tag[1] == initialTag[1] && tag[2] == initialTag[2]) {
    tagMatch = true;
  }
    else {
      tagMatch = false;
    }
  
}

// Function to begin count when a valid tag is present

void tagTime() {
  if(validTag == true) {
    startTime = millis();
    enableRFID();
    readRFIDTag();
    validateTag();
    while (validTag == true && tagMatch == true) {
      enableRFID();
      readRFIDTag();
      validateTag();
      tagsMatch();
      } 
      duration = millis() - startTime;
    }
}

// Function to send Tag and elapsed time to serial

void sendTagTime() {
 if (duration >= 100) {
  Serial.print(initialTag[1]);
  Serial.print(initialTag[2]);
  Serial.print(", ");
  Serial.println(duration);
 } 
}

//Function to clear all stored variables

void clearCache() {
  readStatus = 0;
  tag[0] = 0;
  tag[1] = 0;
  tag[2] = 0;
  tag[3] = 0;
  validTag = false;
  duration = 0;
}

I have a validation function that ensures that the first and last byte (spots 0 and 3 in the array) of the RFID tag == 254 :

void validateTag() {
if (tag[0] == 254 && tag[3] == 254) {
  validTag = true;
  }
else {
  validTag = false;
  }
}

If I run this function and then serial print the status of validTag from inside the loop() as shown below, I get either 0 or 1 depending on whether or not the tag is in the expected location:

void loop()
{
  enableRFID();        // Put RFID module in active read mode
  readRFIDTag();       // Read RFID tag
  validateTag();  // Ensure that check values on tag are valid
  Serial.println(validTag);
  //storeInitialTag();   // Store first-read tag
  //tagTime();           // Calculate elapsed time that tag is present
  //sendTagTime();       // Send elapsed time and ID to serial
  printTag();          // Print tag ID and address if valid tag
  delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  //clearCache();
}

Here's where things get fishy. The first step in the tagTime()function above is verifying that a valid tag is present:

void tagTime() {
  if(validTag == true) {
    startTime = millis();
    enableRFID();
    readRFIDTag();
    validateTag();
    while (validTag == true && tagMatch == true) {
      enableRFID();
      readRFIDTag();
      validateTag();
      tagsMatch();
      } 
      duration = millis() - startTime;
    }
}

I can't get this function to run. My first thought was to place Serial.println(validTag) as the first line inside the function to see if the function was receiving a valid tag or not. When I do this, something is going haywire. The results I get for validTag are now the unique ID of the tag, which are stored in tag[1] and tag[2]. I don't see where in the code this is happening, though.

You're doing a great job of keeping me honest in my code! I appreciate it.

int initialTag[2]: creates a 2 element array. Later, you refer to initialTag[2], which is one element beyond the end of that array. Same thing with currentTag[2]; Your comment after the statement int tag[4]; says you are declaring an array of 4 bytes,

Stupid errors again. Just not paying attention, I suppose. all arrays should be int arrays.

You set initialTag[] before calling timeTag(), but after you enable/read/validate within the while(), you don't set it again.

As I see it, I only want initialTag to be set after the first read, and not be changed until I finish the while loop, record the time, and get back to the top of the loop() to read a new tag.

You have an if() and a while() that check initialTag against currentTag, and another if() that checks initialTag[] against tag[]. You have to decide what criteria consitute continuing to monitor, and what constitutes reason to report the time.

Here's how I want the tagTime() function to operate: 1. Only use the function if validTag is true. 2. Once we know the tag is valid, start the timer. 3. While valid tag is true AND the current tag matches the initial tag, keep reading the tag and seeing if it matches.

SIDE NOTE: Do the conditions of the while loop need to be met to START the while loop?

  1. If the tag is no loner valid OR if the current tag no longer matches the initial tag, exit the while loop and stop the timer.

This logic is what I am having the most trouble with.

You have a function that calls itself. Recursion can be useful, but it must be used carefully, lest you run out of memory. When you don't detect a tag, what, exactly is returned from the read?

I was a bit worried about that recursion myself. I didn't write that code, and don't exactly understand how it works. It came with the bare-bones RFID reader sketch I found online. From my observations, It stops reading the card and suppresses all output to serial if the first received byte from the reader != 1 (if the byte == 1, there were no errors with the read). I would gladly take it out if you think it is causing issues.

it would be helpful if you could tell me what is happening that you don't expect. That will narrow down the areas to examine.

Heres what works and what doesn't:

Working: - Enable RFID reader [via enableRFID()] - Read RFID tag and store result as array [via readRFIDTag()] - Ensure that tag read is valid [via validateTAG()] - Store the unique ID as initialTag [via storeInitialTag()]

Not Working: - Once a valid tag is detected, start timer - Sit in the while loop until either the tag is invalid or the current tag no longer matches the initial tag - stop the timer once the while loop quits - report the time along with the ID (this will be simple once I get a time calculation)



Here's where I stand currently:

If run the loop() as such:

void loop()
{
  enableRFID();        // Put RFID module in active read mode
  readRFIDTag();       // Read RFID tag
  validateTag();  // Ensure that check values on tag are valid
  storeInitialTag();   // Store first-read tag
  tagTime();           // Calculate elapsed time that tag is present
  sendTagTime();       // Send elapsed time and ID to serial
  //printTag();          // Print tag ID and address if valid tag
  delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  clearCache();
}

I can get it to record a start time, but it isn't staying in the loop for any amount of time, because if the tag is continually present, it keeps spitting out startTime values constantly instead of just once like it should if it gets stuck in the while loop properly.

Here is the current tagTime() function, in all its glory misery:

void tagsMatch() {
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    tagMatch = true;
  }
    else {
      tagMatch = false;
    }
  
}

// Function to begin count when a valid tag is present

void tagTime() {
  if(validTag == 1) {
    startTime = millis();
    Serial.print(validTag);
    Serial.print("     ");
    Serial.println(startTime);
    while (validTag == true && tagMatch == true) {
      enableRFID();
      readRFIDTag();
      validateTag();
      tagsMatch();
      } 
      duration = millis() - startTime;
    }
}

Give this a try. Just a few modifications to the latest code. Commented to show what I did.

// Changed the name of the function to differentiate it from the tagMatch variable
// doTagsMatch() assumes:
//  tag[1] and tag[2] are the first and second ID values of the most recently read tag
//  initialTag[0] and initialTag[1] are the corresponding values of the tag you want to time.
bool doTagsMatch() {
  match = false;
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    match = true;
  }
  return match;
}

// Function to begin count when a valid tag is present
// assumes that tagMatch is true on entry to this function (yes, the conditions
//   have to be met to enter the while() loop)
// assumes validTag and tagMatch are declared globally as bool
void tagTime() {
  if( validTag ) {
    startTime = millis();
    Serial.print(validTag);
    Serial.print("     ");
    Serial.println(startTime);
    while ( validTag  && tagMatch) {
      enableRFID();
      readRFIDTag();
      validateTag();
      tagMatch = doTagsMatch();
      if ( (! tagMatch) || (! validTag )) {  
        duration = millis() - startTime;
        tagMatch = false;
        break;
      }
    }
  }
}

If you want help I suggest you post the whole sketch, intact. It's too much like hard work posting snippets together and hoping the result is intact before we can look at the code.

Ahh.. didn't recognize the name. I posted a couple of modified functions on the other thread at http://forum.arduino.cc/index.php?topic=205067.msg1510936#msg1510936 (and I just now modified them because of something you posted here.

You are going to have to deal with the index out of bounds stuff before you do anything else. Storing anything past the end of an array WILL clobber memory that doesn't belong to the array in question, and if it happens to belong to some other variable, ugly, vile things will happen.

This thread should probably be merged with the other one.

Merged.

EDIT: I think this issue was related to mis-referencing values in an array, I think I was calling or writing to some place that I shouldn't have been. Issue resolved.

Are you saying you have fixed the problem of overwriting other variables?

Now would be a good time to post your entire code again, so we can see where it now stands.

Here is the entire code, making use of the two functions you have included:

#include "SoftwareSerial.h"
#define RFID_READ 0x01   // command byte to put RFID module in 'read' mode
#define txPin 9          // to SIN
#define rxPin 10         // to SOUT

SoftwareSerial mySerial(rxPin, txPin);

int ADDRESS = 3;             // Which line on the RFID tag to read
int readStatus = 0;          // Variable to hold status integer
boolean printAddress = true; // Print address when printing tag data? (1 = Yes; 0 = No)
int tag[4];                  // Integer array to hold 4 integers of data for each RFID read
int initialTag[2];           // Integer array to hold 2 ID integers of 'first read' tag
boolean validTag = false;    // Logic indicating whether a valid tag is present (0 = False)
int msDelay = 250;           // delay (ms) between tag reads
boolean tagMatch = false;    // Logic indicating if current tag matches initial tag
long startTime;              // Variable to hold time when timer starts
long duration = 0;           // Variable to hold duration
boolean match = false;

void setup()
{
  Serial.begin(9600);               // Begin serial communications at 9600 baud
  Serial.println("RFID Read Test"); // Print header
  //Serial.print("ID, ");             // Print column names for .csv output
  //Serial.println("Time(ms)");
  mySerial.begin(9600);             // Begin serial communications for mySerial at 9600 baud
  pinMode(txPin, OUTPUT);           // Declare txPin as OUTPUT
  pinMode(rxPin, INPUT);            // Declare rxPin as INPUT
}



void loop()
{
  enableRFID();        // Put RFID module in active read mode
  initialReadRFIDTag();
  secondReadRFIDTag();
  tagTime();
  //tagTime2();           // Calculate elapsed time that tag is present
  sendTagTime();       // Send elapsed time and ID to serial
  //printTag();          // Print tag ID and address if valid tag
  //delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  clearCache();
}


// Function to activate RFID reader

void enableRFID() {
   mySerial.print("!RW");            // Send ASCII character "!RW" to begin serial connection with RFID module
   mySerial.write(byte(RFID_READ));  // Send the RFID_READ byte to RFID module
   mySerial.write(byte(ADDRESS));    // Send the address that we want to read from
}

// Function to suppress the "null result" from being printed if no RFID tag is present 
  
void suppressAll()                               
{
    if(mySerial.available() > 0){ 
        mySerial.read();
        suppressAll();
    }
}

// Initial read  - read the tag once, just make sure it is a read with no errors.

void initialReadRFIDTag() {
  enableRFID();
  readRFIDTag();
  validateTag();
  if (validTag) {
    storeInitialTag();
  }
  else {
    clearCache();
  }
  
}



// Second read - read again and check for match

void secondReadRFIDTag() {
  if (validTag) {
  enableRFID();
  readRFIDTag();
  validateTag();
  if (validTag) {
    doTagsMatch();
  }
  else {
    clearCache();
  }
  
  }
}
  

// Function to read RFID Tag

void readRFIDTag() {
  
  // supress all tag reads with status code != 1 (status code = 1 means no error)
  if(mySerial.available() > 0) {
     readStatus = mySerial.read();
     if (readStatus != 1){
       suppressAll();
     }
  }
  
  if (readStatus == 1) {
  
  // Extract first byte of data
  if(mySerial.available() > 0) {
     tag[0] = mySerial.read();
     }
     
  // Extract second byte of data
  if(mySerial.available() > 0) {
     tag[1] = mySerial.read();
     }
     
  // Extract third byte of data
  if(mySerial.available() > 0) {
     tag[2] = mySerial.read();
     }
     
  // Extract fourth byte of data
  if(mySerial.available() > 0) {
     tag[3] = mySerial.read();
     }
  }
  else {
    clearCache();
  }

  
  }

// Function to validate tag against check criteria

void validateTag() {
if (tag[0] == 254 && tag[3] == 254) {
  validTag = true;
  }
else {
  validTag = false;
  }
}


// function to store initial valid tag for comparison

void storeInitialTag() {
  if (validTag == true) {
    initialTag[0] = tag[1];
    initialTag[1] = tag[2];
  }
  else {
    initialTag[0] = 0;
    initialTag[1] = 0;
  }
}

// Function to send RFID code to serial.print()

void printTag() {

  // Check that a tag read had no errors and is a valid tag
  
  if (validTag == true) {

  // Send read address to serial
  if(printAddress == true) {
     Serial.print("Address:");
     Serial.println(ADDRESS);
     }

  // Send byte 1 and byte 2 (2-digit ID) to serial
  Serial.print("TAG:");
  Serial.print(tag[1]);
  Serial.print(tag[2]);
  Serial.println();

  }
}

// Function to see if currentTag matches initialTag

void tagsMatch() {
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    tagMatch = true;
  }
    else {
      tagMatch = false;
    }
  
}

// Changed the name of the function to differentiate it from the tagMatch variable
// doTagsMatch() assumes:
//  tag[1] and tag[2] are the first and second ID values of the most recently read tag
//  initialTag[0] and initialTag[1] are the corresponding values of the tag you want to time.

bool doTagsMatch() {
  match = false;
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    match = true;
  }
  return match;
}


// Function to begin count when a valid tag is present
// assumes that tagMatch is true on entry to this function (yes, the conditions
//   have to be met to enter the while() loop)
// assumes validTag and match are declared globally as bool

void tagTime() {
  if( validTag && match ) {
    startTime = millis();
    while ( validTag  && match) {
      enableRFID();
      readRFIDTag();
      validateTag();
      match = doTagsMatch();
      if ( (! match) || (! validTag )) { 
        duration = millis() - startTime;
        match = false;
        break;
      }
    }
  }
}

// Function to send Tag and elapsed time to serial

void sendTagTime() {
 if (duration >= 100) {
  Serial.print(initialTag[0]);
  Serial.print(initialTag[1]);
  Serial.print(", ");
  Serial.println(duration);
 } 
}

//Function to clear all stored variables

void clearCache() {
  readStatus = 0;
  tag[0] = 0;
  tag[1] = 0;
  tag[2] = 0;
  tag[3] = 0;
  validTag = false;
  duration = 0;
  match = false;
}

I haven't had time to test it yet, but this is where it stands currently. I will post an update once I try it out.

I see you've made some changes, and it looks like you are not fully understanding functions,

There are two ways to set tagMatch. The first is to change its value in a function, and the second is to assign it the return value of a function. You have two functions that set values of global variables. The first is

void tagsMatch() {
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    tagMatch = true;
  }
    else {
      tagMatch = false;
    }
}

This sets the value of tagsMatch, which is one way to do it.

The function I supplied does something a bit different. It returns a boolean value.

bool doTagsMatch() {
  match = false;
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    match = true;
  }
  return match;
}

This is called by writing something like tagMatch = doTagsMatch();, which returns a boolean value of true or false, and assigns it to the global boolean variable tagMatch. This allows you to then write if (tagMatch)

You have added a boolean global called match, but match is already a local variable in doTagsMatch, which is decidedly not good. Why? Because match is local to doTagsMatch(), and setting it to a value does not affect the global variable of the same name. When doTagsMatch() returns, it returns a value, but since the return value is not being assigned to anything, it is lost. The only reason for the variable match is to hold the calculated value to be returned, and it disappers as soon as you leave the function.

So, your call in this function should be:

void secondReadRFIDTag() {
  if (validTag) {
    enableRFID();
    readRFIDTag();
    validateTag();
    if (validTag) {
      tagMatch = doTagsMatch();  // note the usage for doTagsMatch()
    }
    else {
      clearCache();
    }
  }
}

This also means you can get rid of the function tagsMatch(). Yes, either function will work, but I hope to show you the way a function operates, because sometimes it will save you MANY lines of inline code.

Now you should also get rid of the boolean variable match, and change your tagTime() function as follows:

void tagTime() {
  if( validTag && tagMatch ) {
    startTime = millis();
    while ( validTag  && tagMatch) {
      enableRFID();
      readRFIDTag();
      validateTag();
      tagmatch  = doTagsMatch();
      if ( (! tagMatch) || (! validTag )) {  
        duration = millis() - startTime;
        tagMatch = false;
        break;
      }
    }
  }
}

Let me know if I've just confused you. :~

Lar3ry:

I think I understand where you are coming from. First and foremost, I did leave the tagsMatch() function in the script, but was not referencing it anywhere in the loop, so it was just extraneous code at that point, but I have since taken it out. I also removed the global boolean variable match.

I updated the secondReadRFIDTag() function according to your suggestions:

void secondReadRFIDTag() {
  if (validTag) {
  enableRFID();
  readRFIDTag();
  validateTag();
  if (validTag) {
   match = doTagsMatch();
  }
  else {
    clearCache();
  }
  
  }
}

The current problem, and the reason that I created the global boolean variable earlier, is that the sketch no longer compiles, and says that 'match' is not declared in this scope. The best way I knew how to fix that was to assign a global variable, and if that isn't the right solution, I'm not entirely sure how to fix it.

I've also updated the tagTime() function according to your suggestions. Here is the current version, however I feel like that same issue with variables not being declared in the function may creep up.

void tagTime() {
  if( validTag && match ) {
    startTime = millis();
    while ( validTag  && match) {
      enableRFID();
      readRFIDTag();
      validateTag();
      match = doTagsMatch();
      if ( (! match) || (! validTag )) { 
        duration = millis() - startTime;
        match = false;
        break;
      }
    }
  }
}

And yes, you are entirely correct. I don't feel like I fully understand functions. I don't have any computer science background, so the programming curve has been a bit steep for me. If you have a good reference on some reading material to clarify, I would be grateful. Would this same issue (relating to the boolean variable match) apply to the boolean variable validTag as well? It seems the situation is quite similar, and I have that one declared as a global boolean variable. Thanks again.


Current code in it's entirety, for reference purposes:

#include "SoftwareSerial.h"
#define RFID_READ 0x01   // command byte to put RFID module in 'read' mode
#define txPin 9          // to SIN
#define rxPin 10         // to SOUT

SoftwareSerial mySerial(rxPin, txPin);

int ADDRESS = 3;             // Which line on the RFID tag to read
int readStatus = 0;          // Variable to hold status integer
boolean printAddress = true; // Print address when printing tag data? (1 = Yes; 0 = No)
int tag[4];                  // Integer array to hold 4 integers of data for each RFID read
int initialTag[2];           // Integer array to hold 2 ID integers of 'first read' tag
boolean validTag = false;    // Logic indicating whether a valid tag is present (0 = False)
int msDelay = 250;           // delay (ms) between tag reads
boolean tagMatch = false;    // Logic indicating if current tag matches initial tag
long startTime;              // Variable to hold time when timer starts
long duration = 0;           // Variable to hold duration

void setup()
{
  Serial.begin(9600);               // Begin serial communications at 9600 baud
  Serial.println("RFID Read Test"); // Print header
  //Serial.print("ID, ");             // Print column names for .csv output
  //Serial.println("Time(ms)");
  mySerial.begin(9600);             // Begin serial communications for mySerial at 9600 baud
  pinMode(txPin, OUTPUT);           // Declare txPin as OUTPUT
  pinMode(rxPin, INPUT);            // Declare rxPin as INPUT
}



void loop()
{
  enableRFID();        // Put RFID module in active read mode
  initialReadRFIDTag();
  secondReadRFIDTag();
  tagTime();
  sendTagTime();       // Send elapsed time and ID to serial
  //printTag();          // Print tag ID and address if valid tag
  //delay(msDelay);      // interval delay between RFID reads (for testing purposes)
  clearCache();
}


// Function to activate RFID reader

void enableRFID() {
   mySerial.print("!RW");            // Send ASCII character "!RW" to begin serial connection with RFID module
   mySerial.write(byte(RFID_READ));  // Send the RFID_READ byte to RFID module
   mySerial.write(byte(ADDRESS));    // Send the address that we want to read from
}

// Function to suppress the "null result" from being printed if no RFID tag is present 
  
void suppressAll()                               
{
    if(mySerial.available() > 0){ 
        mySerial.read();
        suppressAll();
    }
}

// Initial read  - read the tag once, just make sure it is a read with no errors.

void initialReadRFIDTag() {
  enableRFID();
  readRFIDTag();
  validateTag();
  if (validTag) {
    storeInitialTag();
  }
  else {
    clearCache();
  }
  
}



// Second read - read again and check for match

void secondReadRFIDTag() {
  if (validTag) {
  enableRFID();
  readRFIDTag();
  validateTag();
  if (validTag) {
   match = doTagsMatch();
  }
  else {
    clearCache();
  }
  
  }
}
  

// Function to read RFID Tag

void readRFIDTag() {
  
  // supress all tag reads with status code != 1 (status code = 1 means no error)
  if(mySerial.available() > 0) {
     readStatus = mySerial.read();
     if (readStatus != 1){
       suppressAll();
     }
  }
  
  if (readStatus == 1) {
  
  // Extract first byte of data
  if(mySerial.available() > 0) {
     tag[0] = mySerial.read();
     }
     
  // Extract second byte of data
  if(mySerial.available() > 0) {
     tag[1] = mySerial.read();
     }
     
  // Extract third byte of data
  if(mySerial.available() > 0) {
     tag[2] = mySerial.read();
     }
     
  // Extract fourth byte of data
  if(mySerial.available() > 0) {
     tag[3] = mySerial.read();
     }
  }
  else {
    clearCache();
  }

  
  }

// Function to validate tag against check criteria

void validateTag() {
if (tag[0] == 254 && tag[3] == 254) {
  validTag = true;
  }
else {
  validTag = false;
  }
}


// function to store initial valid tag for comparison

void storeInitialTag() {
  if (validTag == true) {
    initialTag[0] = tag[1];
    initialTag[1] = tag[2];
  }
  else {
    initialTag[0] = 0;
    initialTag[1] = 0;
  }
}

// Function to send RFID code to serial.print()

void printTag() {

  // Check that a tag read had no errors and is a valid tag
  
  if (validTag == true) {

  // Send read address to serial
  if(printAddress == true) {
     Serial.print("Address:");
     Serial.println(ADDRESS);
     }

  // Send byte 1 and byte 2 (2-digit ID) to serial
  Serial.print("TAG:");
  Serial.print(tag[1]);
  Serial.print(tag[2]);
  Serial.println();

  }
}

// Changed the name of the function to differentiate it from the tagMatch variable
// doTagsMatch() assumes:
//  tag[1] and tag[2] are the first and second ID values of the most recently read tag
//  initialTag[0] and initialTag[1] are the corresponding values of the tag you want to time.

bool doTagsMatch() {
  match = false;
  if (tag[1] == initialTag[0] && tag[2] == initialTag[1]) {
    match = true;
  }
  return match;
}


// Function to begin count when a valid tag is present
// assumes that tagMatch is true on entry to this function (yes, the conditions
//   have to be met to enter the while() loop)
// assumes validTag and match are declared globally as bool

void tagTime() {
  if( validTag && match ) {
    startTime = millis();
    while ( validTag  && match) {
      enableRFID();
      readRFIDTag();
      validateTag();
      match = doTagsMatch();
      if ( (! match) || (! validTag )) { 
        duration = millis() - startTime;
        match = false;
        break;
      }
    }
  }
}

// Function to send Tag and elapsed time to serial

void sendTagTime() {
 if (duration >= 100) {
  Serial.print(initialTag[0]);
  Serial.print(initialTag[1]);
  Serial.print(", ");
  Serial.println(duration);
 } 
}

//Function to clear all stored variables

void clearCache() {
  readStatus = 0;
  tag[0] = 0;
  tag[1] = 0;
  tag[2] = 0;
  tag[3] = 0;
  validTag = false;
  duration = 0;
  match = false;
}