RDM630 125KHz RFID reading with the Arduino Mega 2560 R3

This howto is for the RDM630 125Khz RFID module – UART board. Seeedstudio and Spec Sheet.

There are a few chunks of code on the internet that will get the RDM630 up and running on an Uno, but those don’t seem to work on the Mega. There are also a few examples of code that sort-of works, but not reliably, and does not check the checksum etc. I stated with these and then kept on hacking until I got it to work 100%.

RDM630ArduinoMega

So, firstly, a few things that you should know before we start:

  • Many of the code examples work fine with an Uno (using Software Serial) but I’m starting to learn that the Mega doesn’t like Software Serial. I’ve found a few instances of people saying (anecdotally) that Software Serial is “not supported” on the Mega, and even though it works, it’s buggy, and there are patches blah blah. Luckily we have 4 hardware serial ports, so lets use those.
  • You only need to use +5V, GND and one pin (TX) to connect the board to your Mega.
  • You will notice the delay(20); in my code. That gives the board time to bring up the serial connection before trying to read data for it. Without that you’ll get garbage 90% of the time.
  • There are various methods for reading. I’m using a hybrid of various approaches from the internets that uses Serial1.available() as a signal that a tag has been swiped and explicitly reads 14 bytes.
  • I am also explicitly closing and restarting the the Serial1 connection after reading a tag. I do this because the code was working until I left a tag in range for longer than about 5 seconds, at which point Serial1 would get confused and the counter would overrun. This approach does slow things down, but since you can still scan about 4 tags a second (way more than you’ll need to in real life) you’ll be fine.
  • This approach uses pointers, buffers and some confusing snprintf and sscanf functions to extract and convert the 14 bytes from the tag into the various bits and pieces (RFID Tags have checksums, and the unique number itself is stored in HEX). That stuff is hard to grok, but luckily you can chose to either make an effort to understand it or just use the code as-is.

Right. Wiring.

Look at the spec sheet. On pin-set one, pins 4 and 5 go to GND and +5V respectively, with  pin 1 going to Pin 19 on your Arduino Mega (RX for Serial1). That’s all.

Now the code:

uint8_t buffer[14];
uint8_t* buffer_at;
uint8_t* buffer_end = buffer + sizeof(buffer);

String checksum;
boolean tagfound = false;

void setup()
{
    Serial.begin(9600);
    Serial.println("Serial Ready");

    Serial1.begin(9600);
    Serial.println("RFID Ready");
}

void loop()
{
    if (Serial1.available()){
        delay(20);
        buffer_at = buffer;

        while ( buffer_at < buffer_end )
        {
            *buffer_at++ = Serial1.read();
        }
        tagfound = true;
        Serial1.end();
        Serial1.begin(9600);
    }

    if (tagfound){
        buffer_at = buffer;
        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("Tag: ");
        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

        tagfound = false;
    }

}

uint8_t rfid_get_next(void)
{
    // sscanf needs a 2-byte space to put the result but we
    // only need one byte.
    uint16_t hexresult;
    // 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",&hexresult);
    buffer_at += 2;
    return static_cast<uint8_t>(hexresult);
}

Now connect it up, open your Serial Monitor and swipe a tag. You should see the tags being read, with their decimal value (often the number that’s printed on them) printed out.

My three tags look like so:

Serial Ready
RFID Ready
Reading: 695592 OK
Reading: 721129 OK
Reading: 1430936 OK

Credits:
I stole a large chunk of code from ManicBug’s blog post, and got a lot of help from the great people in #arduino on Freenode.  Thanks!

Advertisements

Seeed Studio GPRS Shield 1.4 and Arduino Mega 2560

Recently I battled to get the Seeed Studio GPRS Shield 1.4 and Arduino Mega 2560 to talk to each other. I eventually discovered that they are not actually compatible when stacked (without some ugly pin jumping, and even then, not really compatible because the Software Serial can’t seem to really handle 19200 baud rates).

So here’s how to treat it as a breakout board. (my notes in blue):Image

This only requires 5 connections. The blue labels represent the Arduino pins to connect to.

  1. 5v and GND – These should be pretty obvious.
  2. Pin 9 – This pin is used to turn the SIM900 on and off.
  3. Pin 18 and 19 – These are the HW serial pins

Finally note the position of the jumpers (HW Serial) and the position of the Power Switch (Internal).

Which, when connected up should look something like this:Image

Then finally you can load up the following sketch to get serial access to the GPRS modem via the Arduino’s serial monitor.

#include <SoftwareSerial.h> 
#define terminator 10 // DEC value for a LF(line feed) to skip while loop

/*
SETUP
 
 See https://arbitraryuser.com/2013/04/07/seeed-studio-gprs-shield-and-arduino-mega-2560/
 
 This code is partially "borrowed" from idS2001 at http://www.seeedstudio.com/forum/viewtopic.php?p=12939#p12939
 */

String IncDataSerial = "";

void setup()
{
  delay(1000);
  Serial.begin(19200);
  Serial1.begin(19200);

  // Automatically power up the SIM900.
  pinMode(9, OUTPUT);
  digitalWrite(9,LOW);
  delay(1000);
  digitalWrite(9,HIGH);
  delay(2500);
  digitalWrite(9,LOW);
  delay(3500);
  // End of SIM900 power up.
}

void loop()
{
  if (Serial1.available()>0)  // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    boolean getLF = false;
    while(Serial1.available()>0 && !getLF)  // reading data into string if activity is on port and getLF is false ==> no LF have been send
    {
      char buffer=Serial1.read();  // writing data into char
      IncDataSerial += buffer;
      if (buffer == terminator) {
        getLF = true;
      }
    }

    Serial.print(IncDataSerial);  // send string ( char array ) to hardware serial
    Serial.print("\r");   // send a CR because it is missing
    IncDataSerial = "";
  }
  if (Serial.available()>0) // if data is available on hardwareserial port ==> data is comming from PC or notebook
    Serial1.write(Serial.read());  // write it to the GPRS shield
}

In Serial Monitor (or similar app) you will then see it start to talk to you after the initial ~5 second startup delay.

RDY

+CFUN: 1

+CPIN: READY

Call Ready

AT
OK

AT+CSQ
+CSQ:18,0
OK