Hi there! I'm running my Arduino Uno with the SparkFun Simultaneous UHF RFID Reader. What I'm trying to have it do is read a tag ID, send it to the Arduino, then have the Arduino look up the ID in an array of structs and print a name. It's looking up the tags okay, but it'll print the name and wrong tag ID (usually 32) a dozen or so times on the same line in the Serial Monitor. How do I get it to only print the name and RFID tag ID once?
Here's the Array of Structs:
struct Athlete {
String tagID;
String name;
};
Athlete athletes[] = {
{" Chip 04 ", "Runner Lastname"},
{" Chip 05. ", "Runner1 Lastname"},
// Add more athletes and their tag IDs here
};
const int maxAthletes = sizeof(athletes) / sizeof(athletes[0]);
And here's the code that does the reading and printing:
if (nano.check() == true) {
byte responseType = nano.parseResponse();
if (responseType == RESPONSE_IS_TAGFOUND) {
// it is already in the list
if (DeDub()) return;
playTone();
Serial.print(place);
Serial.print(" ");
byte tagEPCBytes = nano.getTagEPCBytes();
for (byte x = 0; x < tagEPCBytes; x++) {
if (nano.msg[31 + x] < 0x10) Serial.print("0");
for (int b = 0; i < maxAthletes; i++){
String tagID = String(nano.msg[31+x]);
Serial.print("Athlete: " + athletes[b].name + " - Tag ID: " + tagID);
Serial.print((""));
}
}
Serial.print(" ");
Serial.print(minutes);
Serial.print(':');
if ((personTime + 0.0005) < 10)
Serial.print('0');
Serial.println(personTime, 2);
place++;
}
}
}
I'm pretty new to arrays of structs, so any help is appreciated. Thank you!
Here's the complete code (Sorry, it's super long):
#include <toneAC.h>
#include <SoftwareSerial.h>
SoftwareSerial softSerial(2, 3);
#include "SparkFun_UHF_RFID_Reader.h"
RFID nano;
//place variables - data placement
int place = 1;
float seconds;
float personTime;
unsigned long currentMillis = 0;
unsigned long prevMillis = millis;
unsigned long minutes = 0;
int heat = 1;
bool gunReady = false;
bool panelReady = false;
int rfidcounter = 1;
#define piezo 10
bool data = true;
int note = 2637;
#define buzzgnd 9
//Array of Structs
struct Athlete {
String tagID;
String name;
};
Athlete athletes[] = {
{" Chip 04 ", "John McKellar"},
{"TAG_ID_2", "Athlete 2"},
// Add more athletes and their tag IDs here
};
//Various more Variables
const int maxAthletes = sizeof(athletes) / sizeof(athletes[0]);
bool tagRead[maxAthletes] = {false};
//switches and such
const int buttonPin = 6;
int buttonPushCounter = 1;
int buttonState = 0;
int lastButtonState = 0;
int rfidbtn = 8;
int gun = 13;
int gunCounter = 1;
int gunState = 0;
int lastGunState = 0;
int lapno = 1;
unsigned long nowMillis = 0;
unsigned long lastMillis = 0;
int mic = A5;
bool rfidon;
int lapbtn = 4;
int raceonbtn = 11;
int lapbtnstate;
int raceonbtnstate;
// create structure to filter
struct DubFilter {
uint8_t EPC[12];
//unsigned long LastTime;
// maximum number of unique EPC
#define MaxEPC 40
struct DubFilter dub[MaxEPC];
void (*resetFunc)(void) = 0;
void setup() {
gunState = digitalRead(gun);
buttonState = digitalRead(buttonPin);
pinMode(lapbtn, INPUT);
pinMode(raceonbtn, INPUT);
//RFID
pinMode(gun, INPUT);
pinMode(rfidbtn, INPUT);
//Piezo out
pinMode(piezo, OUTPUT);
pinMode(12, OUTPUT);
digitalWrite(buzzgnd, LOW);
//Serial Stuff
Serial.begin(115200);
while (!Serial);
if (setupNano(38400) == false) {
Serial.println("Module failed to respond");
while (1);
}
nano.setRegion(REGION_NORTHAMERICA);
nano.setReadPower(2700);
// init de-dub
for (uint8_t i = 0; i < MaxEPC; i++)
dub[i].EPC[0] = 0;
Serial.println("Horseshoe Creek Timing");
delay(500);
Serial.println("Time Trial Pro Controller");
delay(500);
Serial.println("Software V3.2.4");
Serial.println("");
delay(1000);
Serial.println("System Ready");
delay(500);
Serial.println("Ready to begin first race");
pinMode(buttonPin, INPUT);
pinMode(piezo, OUTPUT);
pinMode(buzzgnd, OUTPUT);
}
//For when the race starts
void startRace() {
lapno = 1;
Serial.print("Race ");
Serial.print(heat);
Serial.println(" started");
digitalWrite(5, HIGH);
heat++;
lap();
}
//For setting a Lap split
void lap() {
Serial.print("Lap ");
Serial.println(lapno);
place = 1;
for (uint8_t i = 0; i < MaxEPC; i++)
dub[i].EPC[0] = 0;
lapno++;
}
//Where all the stuff goes on
void runTimer() {
//Millis checker
currentMillis = millis();
seconds = currentMillis - prevMillis;
float personTime = seconds / 1000;
unsigned minutes = (personTime + .0005) / 60;
personTime -= minutes * 60;
gunState = digitalRead(gun);
if(buttonState == HIGH){
if(lapbtnstate == LOW && raceonbtnstate == LOW){
if(gunState == HIGH){
Serial.print("-");
Serial.print(" Manual Entry ");
Serial.print(" ");
Serial.print(minutes);
Serial.print(':');
if ((personTime + 0.0005) < 10)
Serial.print('0');
Serial.println(personTime, 2);
delay(250);
}
}
if (lapbtnstate == HIGH){
if (gunState == HIGH) {
lap();
playTone();
nowMillis = lastMillis;
delay(175);
}
}
}
// I had to declare this variable
int b;
//Where the data gets read
if (nano.check() == true) {
byte responseType = nano.parseResponse();
if (responseType == RESPONSE_IS_TAGFOUND) {
// it is already in the list
if (DeDub()) return;
playTone();
Serial.print(place);
Serial.print(" ");
byte tagEPCBytes = nano.getTagEPCBytes();
for (byte x = 0; x < tagEPCBytes; x++) {
if (nano.msg[31 + x] < 0x10) Serial.print("0");
for (int b = 0; i < maxAthletes; i++){
String tagID = String(nano.msg[31+x]);
Serial.print("Athlete: " + athletes[b].name + " - Tag ID: " + tagID); //Print the name and chip
Serial.print((""));
}
}
//Print the time
Serial.print(" ");
Serial.print(minutes);
Serial.print(':');
if ((personTime + 0.0005) < 10)
Serial.print('0');
Serial.println(personTime, 2);
place++;
}
}
}
// The function that plays a beep
void playTone() {
lastMillis = nowMillis;
digitalWrite(12, HIGH);
toneAC(note, 10);
}
/**
* This routine will check against the table
* If EPC is already in the table true will be returned.
* if NOT EPC will be added to the list and false is turned
*/
bool DeDub() {
uint8_t i, x;
bool MissMatch = false;
// get the num EPC bytes
uint8_t tagEPCBytes = 12;
// check each entry in the table
for (i = 0; i < MaxEPC; i++) {
// if empty entry
if (dub[i].EPC[0] == 0) break;
MissMatch = false;
for (x = 0; x < tagEPCBytes; x++) {
// check for miss match
if (nano.msg[31 + x] != dub[i].EPC[x]) {
MissMatch = true;
break;
}
}
// A this point we check for MisMatch (false means we have a Match)
if (!MissMatch) return true;
}
// EPC was not in the list already
if (i == MaxEPC) {
Serial.println("Table is full\nCan NOT add more");
} else {
// add to the list
for (x = 0; x < tagEPCBytes; x++) {
// Add to the list
dub[i].EPC[x] = nano.msg[31 + x];
}
}
return (false);
}
void flash() {
}
void stopTimer() {
seconds = 0;
place = 1;
minutes = 0;
prevMillis = millis();
digitalWrite(5, LOW);
}
//LOOP---------LOOP STARTS HERE ---- LOOP STARTS HERE --- LOOP STARTS HERE -----
void loop() {
gunState = digitalRead(gun);
if (nowMillis - lastMillis >= 1000) {
noToneAC();
digitalWrite(12, LOW);
lastMillis = millis();
}
// Serial.println(nowMillis);
nowMillis = millis();
//inputs from the multi-select switch
lapbtnstate = digitalRead(lapbtn);
raceonbtnstate = digitalRead(raceonbtn);
buttonState = digitalRead(buttonPin);
//Check to start a race
if (buttonState == HIGH) {
if(raceonbtnstate == HIGH){
if (gunState == HIGH) {
if (gunCounter % 2 != 0) {
startRace();
gunCounter++;
playTone();
delay(150);
}
else if (gunCounter % 2 == 0) {
gunCounter++;
Serial.print("Race ");
Serial.print(heat - 1);
Serial.println(" Ended");
Serial.println("Ready to begin next race");
playTone();
delay(150);
}
}
}
//Rfid stuff
int rfidbtnstate = digitalRead(rfidbtn);
if (rfidbtnstate == HIGH) {
rfidcounter++;
if (rfidcounter % 2 == 0) {
rfidon = true;
nano.startReading();
digitalWrite(7, HIGH);
digitalWrite(5, LOW);
Serial.println("RFID ON");
//Serial.println("RFID reader activated");
} else if (rfidcounter % 2 != 0) {
rfidon = false;
nano.stopReading();
digitalWrite(5, HIGH);
digitalWrite(7, LOW);
Serial.println("RFID OFF");
//Serial.println("RFID Reader deactivated");
}
delay(200);
}
}
if (gunCounter % 2 == 0) {
runTimer();
}
if (gunCounter % 2 != 0) {
stopTimer();
for (uint8_t i = 0; i < MaxEPC; i++)
dub[i].EPC[0] = 0;
}
if (rfidon == true) {
digitalWrite(7, HIGH);
digitalWrite(5, LOW);
}
//Serial Comm
if (Serial.available() > 0) {
char code = Serial.read();
if (code == 'r') {
resetFunc();
}
if (code == '1') {
nano.startReading();
digitalWrite(5, HIGH);
digitalWrite(7, LOW);
Serial.println("RFID ON");
rfidcounter = 2;
rfidon = true;
}
if (code == '2') {
nano.stopReading();
digitalWrite(7, LOW);
digitalWrite(5, HIGH);
Serial.println("RFID OFF");
rfidon = false;
rfidcounter = 1;
}
}
//end loop
}
//SparkFun RFID setup things
boolean setupNano(long baudRate) {
nano.begin(softSerial); //Tell the library to communicate over software serial port
//Test to see if we are already connected to a module
//This would be the case if the Arduino has been reprogrammed and the module has stayed powered
softSerial.begin(baudRate); //For this test, assume module is already at our desired baud rate
while (softSerial.isListening() == false)
; //Wait for port to open
//About 200ms from power on the module will send its firmware version at 115200. We need to ignore this.
while (softSerial.available()) softSerial.read();
nano.getVersion();
if (nano.msg[0] == ERROR_WRONG_OPCODE_RESPONSE) {
//This happens if the baud rate is correct but the module is doing a continuous read
nano.stopReading();
Serial.println(F("Module continuously reading. Asking it to stop..."));
delay(1500);
} else {
//The module did not respond so assume it's just been powered on and communicating at 115200bps
softSerial.begin(115200); //Start software serial at 115200
nano.setBaud(baudRate); //Tell the module to go to the chosen baud rate. Ignore the response msg
softSerial.begin(baudRate); //Start the software serial port, this time at user's chosen baud rate
delay(250);
}
//Test the connection
nano.getVersion();
if (nano.msg[0] != ALL_GOOD) return (false); //Something is not right
//The M6E has these settings no matter what
nano.setTagProtocol(); //Set protocol to GEN2
nano.setAntennaPort(); //Set TX/RX antenna ports to 1
return (true); //We are ready to rock
}
You should do something like this
(1) assemble a tag ID from the characters in nano.msg, and then
(2) search for the tag ID in your athletes array.
The search can be successful or un successful (comm errors, mistyping, ...).
(3) Print a message accordingly
(3a) "Tag ID found. Athlete name: " + name
(3b) "Tag ID " + tagID + "not found"
Ok, so I changed the code to write the entire tag to the string first, then check it against the array. Right now, it's just printing the whole array of structs however.
Here's the updated for loop:
if (nano.check() == true) {
byte responseType = nano.parseResponse();
if (responseType == RESPONSE_IS_TAGFOUND) {
String tagID = "";
if (DeDub()) return;
playTone();
Serial.print(place);
Serial.print(" ");
byte tagEPCBytes = nano.getTagEPCBytes();
for (byte x = 0; x < tagEPCBytes; x++) {
if(nano.msg[31 + x] < 0x10){
tagID += 0;
}
tagID += String(char(nano.msg[31 + x]));
}
for (int i = 0; i < maxAthletes; i++){
Serial.print(athletes[i].name + " - Tag ID: " + tagID);
Serial.print((""));
}
Serial.print(" ");
Serial.print(minutes);
Serial.print(':');
if ((personTime + 0.0005) < 10)
Serial.print('0');
Serial.println(personTime, 2);
place++;
}
}
}
bool found = false;
if (tagID == athletes[i].tagID) {
Serial.print(athletes[i].name + " - Tag ID: " + tagID);
Serial.print((""));
found = true;
}
if (!found) {
Serial.println(tagID + " not found");
}
This will still scan all the array, but it will print only the one(s) that have the searched tagID.
(edited)
If you leave the number empty as in your first post, the compiler will take care of the size, which you are anyway calculating in the following instruction.
If you do put a number there, the number of array elements declared must not exceed this number.