125Khz RFID Module RDM630

RFID Test Photo


I picked these up with my last iTeadStudio order to experiment with:


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
6 TX
+5V +5V

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
  // Open software serial connection to RFID module
  // Listen for interrupt from RFID module
void loop(void)
  if ( ready )
    ready = false;
    // Print the buffer
    Serial.print("Reading: ");
    const uint8_t* bp = buffer;
    while ( bp < buffer_end )
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:

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
    // Accumulate the checksum, starting with the first value
    uint8_t checksum = rfid_get_next();
    // We are looking for 4 more values
    int i = 4;
      // 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: ");
    if ( checksum == data_checksum )
      Serial.println(" OK");
      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
  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;


Filed under Arduino

16 responses to “125Khz RFID Module RDM630

  1. Justin

    Sweet, you make it look easy.

  2. Collin

    Hows your range on the antenna?

  3. Tim

    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 .

      • Tim

        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

  4. Eric VDB

    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?

    • Eric VDB

      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.

  5. 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.

    • Eric VDB

      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.

      • Flocko Motion

        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?

  6. jrx

    The byte you called garbage is most probably the version byte 😉

  7. Koop

    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!

  8. Fahad

    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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s