I have managed to get it hooked up to the Arduino uno and displaying the EID number on an LCD.
My problem is the EID number is not the same as the visual number on the tag.
The EID number looks like this: 982_000175197588, and the visual number on the tag is like this:
UK9 371177 0800 5.
How do I make it display the visual number on the lcd if the tag number is read?
I only have around 70 animals. I'm thinking some sort of table with the tag numbers along with matching visual numbers, but I have no idea how to go about this.
I used this code with a few changes from user crumpy10
// include the library code:
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
#define WHITE 0x7 //set the backlight colour
SoftwareSerial RFID(2, 3); //pin2 Rx, pin3 Tx
int CMD[64];
int comlen = 0;
int out_flag = 0;
void setup()
{
Serial.begin(9600);
lcd.begin(16, 2); // set up the LCD's number of columns and rows:
RFID.listen();
Serial.println("Tag number will be displayed here if detected by the module:\n");
lcd.print("Your tag No is:");
lcd.setCursor(0, 1); //place cursor on 2nd row for tag number
RFID.begin(9600); // set the data rate for the RFID reader
delay(10);
}
void loop()
{
while (Serial.available())
{
int a = SerialReadHexDigit();
if (a >= 0) {
CMD[comlen] = a;
comlen++;
}
delay(10);
}
for (int i = 0; i < comlen; i += 2) {
int c = RFID.write( CMD[i] * 16 + CMD[i + 1]);
}
comlen = 0;
while (RFID.available()) {
byte C = RFID.read();
//if (C<16) Serial.print("0"); //Future use for tags with less numbers
Serial.write(C); //Display tag number on serial bus in human form
lcd.write(C); //Display tag number on LCD
//Serial.print(" "); //Puts space between each digit on Serial Monitor
out_flag = 1;
}
if (out_flag > 0) {
Serial.println();
out_flag = 0;
lcd.setCursor(0, 1);
}
}
int SerialReadHexDigit()
{
byte c = (byte) Serial.read();
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
} else {
return -1; // getting here is bad: it means the character was invalid
}
}
982_000175197588 is the number format that I get.
Even if I use this simple code:
char val = 0; // variable to store the data from the serial port
void setup() {
Serial.begin(9600); // connect to the serial port
}
void loop () {
// read the serial port
if(Serial.available() > 0) {
val = Serial.read();
Serial.write(val);
}
}
I get the exact same number and format on the serial monitor.
Is this not correct, what should I be getting?
You may also be running into some sort of encryption. Some time ago when researching microchips for pets, I discovered that one of the chip manufacturers does some sort of encryption to the tag in their reader so it does not match what it says on the registration information. I don't remember exactly what it was, and if you read their microchip, you would get the same number each time - it just didn't match what your paperwork said. I don't remember right off hand which one it was, but it was one of the common ones out there.
I don't think I explained myself properly. When I say exact same format and number, I mean the 3 digits followed by an underscore, followed by another 12 digits. If I use another tag its in the same format but with a different number.
The first three digits are always the same, which is apparently the country code. Me being the UK.
The output format for a read of an FDX-B protocol transponder is a simple string of decimal characters
indicating the 3 digit country code, and 12 digit National ID followed by the ASCII code $0D (carriage
return) as a string end marker.
When a FDX-B programmed transponder enters the field of the reader it will be scanned and a string as
shown in the example below is transmitted:
999_000000001008, where is serial ASCII code $0D, and "_" is a data separator
In this example 999 is the country code defined inside the transponder, while 000000001008 is the unique
12 digit decimal code used to identify an animal.
FDX-B protocol transponders may contain additional data which can be accessed using specific commands.
See RAT and WAT commands as shown in Table 3. Active Tag Commands Summary further on.
If I use crumpy10's original code I get the tag number including underscore in hex format.
39 38 32 5F 30 30 30 31 37 35 31 39 37 35 38 38 D
These numbers translate into the tag number I originally posted.
My understanding is that the rfid tag number and the visual number printed on the front of the tag do not match, and I somehow have to make them match. Meaning if an rfid tag number is scanned, that it prints the visual number it has been paired with onto the lcd, rather than its own internal number. I have no idea how to do this though.
The visual tag number printed on the tag is a mixture of my heard number and animal number, which is why the internal rfid number does not match, but our business works on the visual numbers.
My understanding is that the rfid tag number and the visual number printed on the front of the tag do not match, and I somehow have to make them match.
Why? If you scan a tag that says "Purple with pink polka dots" on it, and get the string "654_4412", why is it necessary to construct "Purple with pink polka dots" from "654_4412"?
If, for some reason, it IS necessary, keep two lists in PROGMEM. One would contain "Purple with pink polka dots". The other would contain "654_4412". When you scan a tag, and get "654_4412", look for that in the second list. Use the index to get the corresponding data ("Purple with pink polka dots") from the other list.
Or use an SD card with a file containing entries like "654_4412 = Purple with pink polka dots". Find the record with the right name and use the corresponding value.
Well, then you have to find the magic decoder ring that translates the RFID tag number to the printed one, we cannot help you with that. It is possible there is no connection.
Seedler:
The visual tag number printed on the tag is a mixture of my heard number and animal number, which is why the internal rfid number does not match
You will probably need to create a table, possibly in EEPROM, that relates the RFID number to the number you want. You probably need just the last few digits of the RFID number - just enough to get a unique number for each cow.
PaulS:
Why? If you scan a tag that says "Purple with pink polka dots" on it, and get the string "654_4412", why is it necessary to construct "Purple with pink polka dots" from "654_4412"?
If, for some reason, it IS necessary, keep two lists in PROGMEM. One would contain "Purple with pink polka dots". The other would contain "654_4412". When you scan a tag, and get "654_4412", look for that in the second list. Use the index to get the corresponding data ("Purple with pink polka dots") from the other list.
Or use an SD card with a file containing entries like "654_4412 = Purple with pink polka dots". Find the record with the right name and use the corresponding value.
KeithRB:
You will probably need to create a table, possibly in EEPROM, that relates the RFID number to the number you want. You probably need just the last few digits of the RFID number - just enough to get a unique number for each cow.
Yes this is what I am after. A table that will match the internal tag number to the number I want it to display. How do I go about doing this. Like sd idea because it would be easily updated.
The heard number is my farm business number. The animal number is the unique identifier number within the heard.
I downloaded Priority 1's Reader/Writer application program to see if I could write the number I wanted to the tag, but it doesn't seem to be re-writable.
Then, use a for loop to iterate over the values, comparing the value just read to each of the N tagValues. When you find a match, the tagNames[thatIndex] value will be the name printed on the tag. Break out of the for loop at that point.
Then, use a for loop to iterate over the values, comparing the value just read to each of the N tagValues. When you find a match, the tagNames[thatIndex] value will be the name printed on the tag. Break out of the for loop at that point.
PaulS I think this is what I need. I'm still very green a programming. This is what I have put together at the minute, with your suggested code.
#include <Wire.h>
#include <LCD.h> // Standard lcd library
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
SoftwareSerial RFID(2, 3); //pin2 Rx, pin3 Tx
#define I2C_ADDR 0x27 // address found from I2C scanner
#define RS_pin 0 // pin configuration for LCM1602 interface module
#define RW_pin 1
#define EN_pin 2
#define BACK_pin 3
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, EN_pin, RW_pin, RS_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACK_pin, POSITIVE);
//Pins for the LCD are SCL A5, SDA A4
int out_flag = 0;
const int TagCount = 0;
char *tagValues[] = { "982_000175197588" };
char *tagNames[] = { "0800 5" };
void setup()
{
Serial.begin(9600);
lcd.begin(20, 4); // set up the LCD's number of columns and rows:
RFID.listen();
Serial.println("Tag number will be displayed here if detected by the module:\n");
lcd.print("Your tag No is:");
lcd.setCursor(0, 1); //place cursor on 2nd row for tag number
RFID.begin(9600); // set the data rate for the RFID reader
delay(10);
}
void loop()
{
while (RFID.available()) {
byte C = RFID.read();
Serial.write(C); //Display tag number on serial bus in human form
lcd.write(C); //Display tag number on LCD
out_flag = 1;
}
if (out_flag > 0) {
Serial.println();
out_flag = 0;
lcd.setCursor(0, 1);
}
}
Do I need a veriable that will store the whole tag number? I'm guessing the byte C in my code is just reading and printing one digit at a time through the while loop.
Do I need a veriable that will store the whole tag number?
I thought you already had that. I see that you don't. Yes, you need one (an array of chars, NULL terminated each time you add a character to it). You need an index variable to, to keep track of where to add data to the array.
Your while statement seems to operate on the principal that all the RFID data will arrive at once. That is not the case.
I'm guessing the byte C in my code is just reading and printing one digit at a time through the while loop.
Yes.
How do I write the for loop?
Assuming that you have rfidData as a char array,
for(byte t=0; t<TagCount; t++)
{
if(strcmp(rfidData, tagValues[t]) == 0) // If there is a match
{
// Do something with tagNames[t]
break; // No need to test the other values after finding a match
}
}
#include <Wire.h>
#include <LCD.h> // Standard lcd library
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
SoftwareSerial RFID(2, 3); //pin2 Rx, pin3 Tx
#define I2C_ADDR 0x27 // address found from I2C scanner
#define RS_pin 0 // pin configuration for LCM1602 interface module
#define RW_pin 1
#define EN_pin 2
#define BACK_pin 3
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, EN_pin, RW_pin, RS_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACK_pin, POSITIVE);
//Pins for the LCD are SCL A5, SDA A4
int out_flag = 0;
const int TagCount = 1;
char *tagValues[] = { "982_000175197588" };
char *tagNames[] = { "0800 5" };
char rfidData[16];
int readCount = 0;
void setup()
{
Serial.begin(9600);
lcd.begin(20, 4); // set up the LCD's number of columns and rows:
RFID.listen();
Serial.println("Tag number will be displayed here if detected by the module:\n");
lcd.print("Your tag No is:");
lcd.setCursor(0, 1); //place cursor on 2nd row for tag number
RFID.begin(9600); // set the data rate for the RFID reader
delay(10);
}
void loop()
{
while (RFID.available()) {
byte C = RFID.read();
rfidData[readCount] = C;
readCount++;
out_flag = 1;
}
if (out_flag > 0) {
Serial.println();
out_flag = 0;
lcd.setCursor(0, 1);
}
for(byte t=0; t<TagCount; t++)
{
if(strcmp(rfidData, tagValues[t]) == 0) // If there is a match
{
Serial.print(tagNames[t]);
lcd.write(tagNames[t]);
break; // No need to test the other values after finding a match
}
}
readCount = 0;
}
after the end of the while loop. We need to see if all the data arrives "at the same time". If not, we need to see whether there is anything that indicates when the record is complete.
PaulS thank you so much, its starting to come together. I now know what you mean about data arriving at the same time. When I put the Serial.print code in after the while loop, sometimes I got the whole number and sometimes only part of it. I added a 5 millisecond delay in the while loop which seems to have fixed that. Is this ok?
I left rfidData as:
char rfidData[16];
or should it be, with the added NULL values:
char rfidData[32];
This is the code now with two tags.
#include <Wire.h>
#include <LCD.h> // Standard lcd library
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
SoftwareSerial RFID(2, 3); //pin2 Rx, pin3 Tx
#define I2C_ADDR 0x27 // address found from I2C scanner
#define RS_pin 0 // pin configuration for LCM1602 interface module
#define RW_pin 1
#define EN_pin 2
#define BACK_pin 3
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, EN_pin, RW_pin, RS_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACK_pin, POSITIVE);
//Pins for the LCD are SCL A5, SDA A4
int out_flag = 0;
const int TagCount = 2;
char *tagValues[] = { "982_000175197588","982_000175197671" };
char *tagNames[] = { "0800 5","0801 6" };
char rfidData[16];
int readCount = 0;
void setup()
{
Serial.begin(9600);
lcd.begin(20, 4); // set up the LCD's number of columns and rows:
RFID.listen();
Serial.println("Tag number will be displayed here if detected by the module:\n");
lcd.print("Your tag No is:");
lcd.setCursor(0, 1); //place cursor on 2nd row for tag number
RFID.begin(9600); // set the data rate for the RFID reader
delay(10);
}
void loop()
{
while (RFID.available()) {
byte C = RFID.read();
rfidData[readCount] = C;
readCount++;
rfidData[readCount] = '\0';
out_flag = 1;
delay(5);
}
if (out_flag > 0) {
Serial.println();
out_flag = 0;
lcd.setCursor(0, 1);
}
for(byte t=0; t<TagCount; t++)
{
if(strcmp(rfidData, tagValues[t]) == 0) // If there is a match
{
lcd.setCursor(0, 1); //place cursor on 2nd row for tag number
Serial.print(tagNames[t]);
lcd.write(tagNames[t]);
break; // No need to test the other values after finding a match
}
}
readCount = 0;
}
Does it look ok now?
How hard would it be to do the same thing as tagValues, and tagNames is doing, but in two colums in a text file on an sd? It would make it easier to add and remove records.
It's not the best solution, but if it works, you can leave it for now.
or should it be, with the added NULL values:
You only add one NULL. Notice that readCount is not incremented after adding the NULL. The array size should be 17, to hold the 16 character and the NULL. Personally, I like even numbers, so I'd make the array size 20.
I'd also make sure that readCount was less than 20 before writing to the array.
How hard would it be to do the same thing as tagValues, and tagNames is doing, but in two colums in a text file on an sd? It would make it easier to add and remove records.
Reading the data from the SD card is not that hard. There is an example, DumpFile, in the SD library that shows how to read a file.
It does not deal with saving the data in an array, but you know how to do that (it's the same as saving serial data in an array). It also does not deal with individual records in a file, but that's simply a matter of checking the character before adding it to the array. If it is a carriage return or line feed ('\n' or '\r'), parse the saved data (strtok()) to get the name and value. Otherwise, add the character, increment the index, and add the NULL.
When you have a name and value, you can compare that to the tag value you have. If they match, use the name, close the file, and break out of the while loop that is reading the file.
I left the array size at 16. It seems to work ok. If I changed it to 17 or 20, I lost the display of the visual tag on the lcd. It might not be pretty but it works.
Cheers for all your help. I'll rest my brain for a bit before having a look at the sd card stuff