The RDM6300 is a ₹150 reader for 125 kHz RFID cards and key fobs (EM4100 type). It suits attendance registers, door locks and “tap to start” machines where cheap fobs are already in use.
It is one of the simplest RFID readers to connect to an Uno. It runs from 5V and sends each card’s ID as serial data on its TX pin. The Uno’s hardware serial is busy with USB, so TX goes to SoftwareSerial on D2. The reader needs no commands, so nothing goes back to it.
The sketch collects each 14-byte frame, checks its checksum, and prints both the full tag code and the card number usually printed on the fob. Holding a card in place doesn’t flood the output: repeats of the same tag are ignored for 1.5 s.
Wiring
| Arduino Uno R3 | RDM6300 125 kHz RFID reader (EM4100) | Wire | Notes |
|---|---|---|---|
| — | ANT1 | — | To Coil antenna wire 1 (not drawn) |
| — | ANT2 | — | To Coil antenna wire 2 (not drawn) |
| D2 | TX | yellow | 5 V serial at 9600 baud → Uno SoftwareSerial RX. |
| 5V | +5V | red | About 50 mA. |
| GND | GND | black |
5 V (4.5–5.5 V) part, 5 V board. The module needs 5 V and its TX outputs 5 V. On ESP32 and Pico put a 1 kΩ / 2 kΩ divider between RDM6300 TX and the board’s RX. Uno connects directly. RX on the module is unused.
Board quirks
- The RDM6300 reads 125 kHz EM4100 cards — the thick white cards and grey key fobs used in many Indian offices and hostels. It can’t read 13.56 MHz cards (Mifare, most metro and ID cards); those need an RC522.
- Everything is 5 V, so TX connects straight to the Uno. Only TX is used; the module’s RX pin stays unconnected.
- D0/D1 belong to USB, so the reader goes on SoftwareSerial. The sketch parses the 14-byte frame itself and checks its XOR checksum — no extra library needed (the rdm6300 library isn’t in the Arduino Library Manager index we compile against).
- Keep the coil away from the Uno, metal and switching supplies; noise from them shortens the read range (normally 3–5 cm).
Code
// RDM6300 125 kHz RFID reader on an Arduino Uno R3, read with SoftwareSerial.
// TX → D2 (Uno RX), +5V → 5V, GND → GND, ANT1/ANT2 → the coil antenna. RX unused.
// Each tag sends a 14-byte frame: 0x02, 10 hex chars of data, 2 hex chars of checksum, 0x03.
#include <SoftwareSerial.h>
SoftwareSerial rfid(2, 3); // RX on D2; D3 is unused (the reader never listens)
char frame[14];
uint8_t pos = 0;
unsigned long lastTag = 0, lastTime = 0;
uint8_t hexVal(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0;
}
uint8_t hexByte(const char* p) { return hexVal(p[0]) << 4 | hexVal(p[1]); }
void handleFrame() {
uint8_t sum = 0;
for (uint8_t i = 0; i < 5; i++) sum ^= hexByte(frame + 1 + i * 2); // XOR of the 5 data bytes
if (sum != hexByte(frame + 11)) {
Serial.println(F("Checksum error - ignored"));
return;
}
// The last 4 data bytes are the number printed on most cards and fobs.
unsigned long id = 0;
for (uint8_t i = 1; i < 5; i++) id = id << 8 | hexByte(frame + 1 + i * 2);
if (id == lastTag && millis() - lastTime < 1500) { // the reader repeats while a tag is held
lastTime = millis();
return;
}
lastTag = id;
lastTime = millis();
Serial.print(F("Tag "));
Serial.write((const uint8_t*)frame + 1, 10);
Serial.print(F(" card number "));
Serial.println(id);
}
void setup() {
Serial.begin(9600);
rfid.begin(9600);
Serial.println(F("RDM6300 on D2 - hold a 125 kHz card near the coil"));
}
void loop() {
while (rfid.available()) {
char c = rfid.read();
if (c == 0x02) pos = 0; // start of a frame
if (pos < sizeof(frame)) frame[pos++] = c;
if (c == 0x03 && pos == sizeof(frame)) handleFrame();
}
}// RDM6300 125 kHz RFID reader on an Arduino Uno R3, read with SoftwareSerial.
// TX → D2 (Uno RX), +5V → 5V, GND → GND, ANT1/ANT2 → the coil antenna. RX unused.
// Each tag sends a 14-byte frame: 0x02, 10 hex chars of data, 2 hex chars of checksum, 0x03.
#include <SoftwareSerial.h>
SoftwareSerial rfid(2, 3); // RX on D2; D3 is unused (the reader never listens)
char frame[14];
uint8_t pos = 0;
unsigned long lastTag = 0, lastTime = 0;
uint8_t hexVal(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0;
}
uint8_t hexByte(const char* p) { return hexVal(p[0]) << 4 | hexVal(p[1]); }
void handleFrame() {
uint8_t sum = 0;
for (uint8_t i = 0; i < 5; i++) sum ^= hexByte(frame + 1 + i * 2); // XOR of the 5 data bytes
if (sum != hexByte(frame + 11)) {
Serial.println(F("Checksum error - ignored"));
return;
}
// The last 4 data bytes are the number printed on most cards and fobs.
unsigned long id = 0;
for (uint8_t i = 1; i < 5; i++) id = id << 8 | hexByte(frame + 1 + i * 2);
if (id == lastTag && millis() - lastTime < 1500) { // the reader repeats while a tag is held
lastTime = millis();
return;
}
lastTag = id;
lastTime = millis();
Serial.print(F("Tag "));
Serial.write((const uint8_t*)frame + 1, 10);
Serial.print(F(" card number "));
Serial.println(id);
}
void setup() {
Serial.begin(9600);
rfid.begin(9600);
Serial.println(F("RDM6300 on D2 - hold a 125 kHz card near the coil"));
}
void loop() {
while (rfid.available()) {
char c = rfid.read();
if (c == 0x02) pos = 0; // start of a frame
if (pos < sizeof(frame)) frame[pos++] = c;
if (c == 0x03 && pos == sizeof(frame)) handleFrame();
}
}Expected serial output
RDM6300 on D2 - hold a 125 kHz card near the coil
Tag 1A0049E3B2 card number 4842418
Tag 0F00A13C55 card number 10566741RDM6300 on D2 - hold a 125 kHz card near the coil Tag 1A0049E3B2 card number 4842418 Tag 0F00A13C55 card number 10566741
Common errors
Nothing prints when a card is near
Wrong card type (13.56 MHz), the coil not plugged into ANT1/ANT2, or TX not on D2. The module’s LED (if fitted) blinks on a read.
“Checksum error” often
Noise from a nearby supply or long wires on TX. Move the coil away from the Uno and keep the TX wire short.
The number differs from the one printed on the card
Cards print the last 3 bytes in two parts (e.g. 073,58290) or in decimal. The full 10-character tag code is the unique ID — use that.