Parts
I picked these up with my last iTeadStudio order to experiment with:
Connections
Connecting to the Arduino is brain-dead simple. Note that I am not connecting the module to the Arduino’s RX/TX pins, because I want to leave that open for the Serial Monitor.
Arduino | RFID |
2 | LED |
6 | TX |
+5V | +5V |
GND | GND |
Reading the ID
My approach in software is to use the SoftwareSerial library. The advantage is that the hardware serial (UART) is free for communication with the host PC. The disadvantage is that the software serial is a lot more finicky.
Fortunately, the module holds the LED pin low while sending data. So what I’ve done is connected that pin to Arduino pin #2, and then I wait for an falling edge on interrupt 0. Once I have that, I know to expect exactly 14 bytes at 9600 baud from the module’s TX pin.
For convenience, I also put this code up as a gist: rfid_simple.pde.
#include <SoftwareSerial.h>
// Pin definitions
const int rfid_irq = 0;
const int rfid_tx_pin = 6;
const int rfid_rx_pin = 7;
// For communication with RFID module
SoftwareSerial rfid(rfid_tx_pin, rfid_rx_pin);
// Indicates that a reading is now ready for processing
volatile bool ready = false;
// Buffer to contain the reading from the module
uint8_t buffer[14];
uint8_t* buffer_at;
uint8_t* buffer_end = buffer + sizeof(buffer);
void rfid_read(void);
void setup(void)
{
// Open serial connection to host PC to view output
Serial.begin(57600);
Serial.println("rfid_simple");
// Open software serial connection to RFID module
pinMode(rfid_tx_pin,INPUT);
rfid.begin(9600);
// Listen for interrupt from RFID module
attachInterrupt(rfid_irq,rfid_read,FALLING);
}
void loop(void)
{
if ( ready )
{
ready = false;
// Print the buffer
Serial.print("Reading: ");
const uint8_t* bp = buffer;
while ( bp < buffer_end )
Serial.print(*bp++);
Serial.println();
}
}
void rfid_read(void)
{
// Read characters into the buffer until it is full
buffer_at = buffer;
while ( buffer_at < buffer_end )
*buffer_at++ = rfid.read();
// Signal that the buffer has data ready
ready = true;
}
Processing the ID
The data from the tag needs to be processed a bit in order to be useful. Running the rfid_simple sketch above, and swiping the key I have, gives this result:
rfid_simple
Reading: �3D009F49608B�
The key says “0010439008” on it, hardly the same. What we have to do is convert the characters to bytes, and take only the middle 4 bytes. That will yield 0x009F4960, which is exactly 10439008. Yay. The first byte appears to be garbage, and the last byte is a checksum.
We can use the checksum to make sure everything came across the wire properly. We can simply XOR each of the 5 bytes together, and compare with the checksum byte, e.g. ( ( ( ( 0x3D ^ 0x00) ^ 0x9F) ^ 0x49) ^ 0x60) == 0x8B.
So the final version of the RFID reader will read in the garbage byte at the start, and read in the checksum, calculate a checksum, and compare the two. I needed to put the chars-to-byte conversion into its own function because it’s used in different places now.
Below are the changes from the above version. The code for this one is also up as a gist: rfid_decimal.pde
void loop(void)
{
if ( ready )
{
// Convert the buffer into a 32-bit value
uint32_t result = 0;
// Skip the preamble
++buffer_at;
// Accumulate the checksum, starting with the first value
uint8_t checksum = rfid_get_next();
// We are looking for 4 more values
int i = 4;
while(i--)
{
// Grab the next value
uint8_t value = rfid_get_next();
// Add it into the result
result <<= 8;
result |= value;
// Xor it into the checksum
checksum ^= value;
}
// Pull out the checksum from the data
uint8_t data_checksum = rfid_get_next();
// Print the result
Serial.print("Reading: ");
Serial.print(result);
if ( checksum == data_checksum )
Serial.println(" OK");
else
Serial.println(" CHECKSUM FAILED");
// We're done processing, so there is no current value
ready = false;
}
}
// Convert the next two chars in the stream into a byte and
// return that
uint8_t rfid_get_next(void)
{
// sscanf needs a 2-byte space to put the result but we
// only need one byte.
uint16_t result;
// Working space to assemble each byte
static char byte_chars[3];
// Pull out one byte from this position in the stream
snprintf(byte_chars,3,"%c%c",buffer_at[0],buffer_at[1]);
sscanf(byte_chars,"%x",&result);
buffer_at += 2;
return static_cast<uint8_t>(result);
}
void rfid_read(void)
{
// Only read in values if there is not already a value waiting to be
// processed
if ( ! ready )
{
// Read characters into the buffer until it is full
buffer_at = buffer;
while ( buffer_at < buffer_end )
*buffer_at++ = rfid.read();
// Reset buffer pointer so it's easy to read out
buffer_at = buffer;
// Signal that the buffer has data ready
ready = true;
}
}
Sweet, you make it look easy.
Hows your range on the antenna?
About 2 inches.
Hi There. I am having trouble making this work. This is great by the way! I have been having the trouble where the reader reads it like 3D009F49608B when it should be a number. I have now found this and am wanting to use it, but I doesn’t seem to work. Could you give me a copy of the final code (is it just like the first part and second combined? It reads RFIDSimple on my serial monitor, but nothing else. Cheers, Tim
As noted in the post, the full code for the decimal translation is at https://gist.github.com/1273970 .
Hi There.
I found that, and I programmed the code in to my Arduino, but it wouldn’t read anything. It prints Reading: but nothing else. I would be really grateful for any help. I have a 125Khz RFID reader, and it has a 12v cable, and Ground, and a White Serial Interface. I connected the white one to pin 6, and the ground to ground, but I couldn’t get it to go (I also had the 12v and ground connected to a 12v power supply. When I use it with a USB to Serial reader, it works. Thanks, Tim
Hi,
I think there is a small problem with your code. When reading a 2nd key it prints out the ID of the previous key. Only the 2nd time the tag is scanned it shows the correct ID. Any idea what might be wrong?
Also, would it be possible to add a delay of 5 secs between 2 tag reads? That should help when you control a door-lock with a pulse for example.
Fascinating! I only have one key, so no way to test it. If you figure it out what causes the 2nd tag to come back wrong, please post it here and I can update the gist.
Ok, I found the issue and it is NOT caused by your code.
I was using NewSoftSerial, but switching to SoftwareSerial the issue went away.
My Apologies.
I AM using SoftwareSerial (latest version, Arduino IDE 1.0) but I’m still experiencing this problem… The program always prints out the ID of the previous key… I have three keys for testing this – it’s always the same behavior….
Any ideas how I could make this work?
The byte you called garbage is most probably the version byte 😉
Hi, I’m attempting to do the exact same thing as you in this project, and I couldn’t help noticing some code that I’d never seen before in Arduino, the ones to do with the buffer (eg.
uint8_t buffer[14];
uint8_t* buffer_at;
uint8_t* buffer_end = buffer + sizeof(buffer);
If you could explain what these are in more detail, it would be awesome. Thanks!
Look for a C introductory reference, and find “arrays” and “pointers” therein. There are some good ones on line, and of course many good books on the topic.
How can i buy this item. I am in Pakistan so kindly do let me know about the payment plan and the shipping charges etc.
Check with iTeadStudio. I’d imagine they ship worldwide.