Wiegand is one of the simplest line protocols in existence, and at worst, is a nightmare to code for on Linux because it takes work to detect very brief pulses on a multitasking OS. Arduino wonât have that problem. Hereâs code you can flash right now to a $5 Arduino Nano from Amazon that will turn it into a USB Wiegand-to-Serial converter for your Linux box, which you can then open directly as a serial port. Flash this code to your board with the free Arduino IDE at arduino.cc. Connect D0 and D1 (from your Wiegand RFID reader) to pins 2 and 3 (respectively). (Arduino GND must also go to readerâs GND)
(*The Chinese knockoffs of Arduino Nano work just as well as the original)
(Pins 2 and 3 are labeled âD2â and âD3â on the Nano board.)
// Define the Wiegand pins.
#define D0_PIN 2
#define D1_PIN 3
// Variables to store incoming data
volatile unsigned long wiegandData = 0;
volatile int bitCount = 0;
// Timeout to reset bitCount if no bits received for a while
unsigned long lastWiegand = 0;
#define WIEGAND_WAIT_TIME 25 // milliseconds
void readD0() {
// Shift wiegand data to left and add 0
wiegandData <<= 1;
bitCount++;
lastWiegand = millis();
}
void readD1() {
// Shift wiegand data to left and add 1
wiegandData <<= 1;
wiegandData |= 1;
bitCount++;
lastWiegand = millis();
}
void setup() {
// Begin serial communication at 9600 baud rate
Serial.begin(9600);
// Set digital pins as inputs
pinMode(D0_PIN, INPUT);
pinMode(D1_PIN, INPUT);
// Attach interrupts
attachInterrupt(digitalPinToInterrupt(D0_PIN), readD0, FALLING);
attachInterrupt(digitalPinToInterrupt(D1_PIN), readD1, FALLING);
}
void loop() {
if (bitCount > 0 && (millis() - lastWiegand > WIEGAND_WAIT_TIME)) {
if (bitCount >= 4) Serial.println(wiegandData);
// Reset variables
bitCount = 0;
wiegandData = 0;
lastWiegand = millis();
}
}
Hereâs a python script you can run on Raspberry Pi / your Linux box / that will pipe the successful card reads from the Arduino to the terminal (first, run pip install pyserial
to install python serial support)
# first, pip install pyserial
import serial
import time
port = '/dev/ttyUSB0' # Change this to your serial port name
serial_port = serial.Serial(9600, baudrate, timeout=1)
while True:
if serial_port.in_waiting > 0:
data = serial_port.readline().decode().strip()
if data: # Only print non-empty lines
print(data)
time.sleep(0.1)
The pins are being used as inputs not outputs (since Wiegand is output from the RFID reader to the Arduino). The voltages must be respected.
Most Arduinos run their I/O at 3.3 volts (as do Raspberry Piâs) and will fry rather quickly by putting 5 volts here. Wiegand D0 and D1 lines are held at 5 volts full time by the RFID reader, and drop to 0 only during a card read. Pretty much all of the non-8-bit Arduinos use 3.3 volt I/O (with the only notable exception being Arduinoâs recent 32-bit Uno based on R4 chipset). Rumor on the Internet is that the ESP32 chips will unofficially tolerate 5 volts on their inputs, and this code will also work on ESP32 so youâre welcome to try it if you have one handy.
This code requires only 2.4 kilobytes of the Arduino Nanoâs available 32 kilobytes of flash⊠this 5 dollar 8 bit processor is a great fit for the job.
The Arduino Nanoâs USB can only do Serial, it canât emulate a USB keyboard so you either need an Arduino Leonardo, or something to convert the 5 volts to 3.3 to safely use the wide range of 32-bit Arduinos that support USB HID.