
EM18 RFID Library for Proteus V1.1 (125 kHz Reader + Arduino)

Hello friends, I hope you all are doing great. Today, I am going to share the new EM18 RFID Library for Proteus V1.1. The EM-18 is a small black 125 kHz RFID reader: hold a card or a keyfob near it, and it sends the tag's number to your Arduino as 12 characters on a serial line. With this EM18 RFID Library for Proteus, you place tags on the reader with a click, at a distance you choose, and your Arduino reads them exactly like a real EM-18.
Version 1.1 replaces the first version of this post. You now get two devices: EM18 Simple, with a tag panel on the schematic, and EM18 Advance, with a pop-up tag wallet, a tag editor and four measured RFID test tools. The new EM18 Arduino Proteus demo is a small access-control system on two Arduino UNOs, shown in the compact Simple interface of our TEP Serial Monitor. Have you read version 1.0? Then jump to "What's New" below.
NOTICE: This library is very special to our team. Our EM-18 model reads EM4100 tags with the real read time and range, sends every tag once like the real module and even speaks Wiegand-26. It took our team a lot of hard work, many test runs and many design changes. Your feedback is the fuel that keeps us going, so please tell us what you think in the comments below or in the EM18 Library board of our forum. And if our free libraries help you, you can buy us a coffee. So, let's get started with the EM18 RFID Library for Proteus:
What is the EM-18 RFID Reader Module?
RFID (radio-frequency identification) means a reader identifies a tag by radio, without contact. The EM-18 reads 125 kHz tags, the low-frequency RFID of many office access cards and keyfobs. Its coil makes a 125 kHz magnetic field; a tag in that field takes its power from it and answers with its number. The tag has no battery.
The EM-18 does the radio work by itself and gives the Arduino only the result: the ID as 12 ASCII characters at 9600 baud on TX, or, with SEL LOW, a Wiegand-26 frame on D0 and D1. A third pin, BEEP, goes LOW on every read. So you need no driver library. The real module is a black potted 32 x 32 mm square with "EM-18 READER MODULE" in white, and the coil is inside it.
The EM-18 at a Glance
| Feature | Value |
|---|---|
| Frequency | 125 kHz (low-frequency RFID) |
| Tags | EM4100 / EM4102 / EM4001 / TK4100 cards and keyfobs (64-bit, read-only) |
| Output | UART on TX: 12 ASCII characters at 9600 8N1 (TTL); or Wiegand-26 on D0 / D1 with SEL LOW |
| BEEP | Active LOW on every read; drives a buzzer and an LED through a PNP transistor |
| Read range | Up to about 10 cm with an ISO card, less with keyfobs and small tags |
| Supply | 4.6 - 5.5 V, about 50 mA (a 5 V module) |
| Pins | 1 VCC, 2 GND, 3 BEEP, 4 - 5 no connection (antenna), 6 SEL, 7 TX, 8 D1, 9 D0 |
EM18, MFRC522 or PN532: Which RFID Library Do You Need?
| Your reader | Tags and interface | Our library |
|---|---|---|
| EM-18 (black 125 kHz module) | 125 kHz EM4100 / EM4102 cards and keyfobs; UART or Wiegand-26 | This article |
| RFID-RC522 (MFRC522) | 13.56 MHz MIFARE Classic, Ultralight, NTAG213; SPI | MFRC522 RFID Library for Proteus |
| PN532 NFC | 13.56 MHz MIFARE Classic and NTAG213; SPI and I2C | PN532 NFC Library for Proteus |
A 125 kHz tag cannot be read by a 13.56 MHz reader, and the other way round, so pick the library that matches your tags.
RFID Terms You Will See in This Article
| Term | Meaning |
|---|---|
| LF, HF | Low frequency (125 kHz, the EM-18) and high frequency (13.56 MHz, MIFARE and NFC) |
| Tag, card, keyfob | Anything the reader can read; a card is the flat ISO card, a keyfob the small plastic drop for a key ring |
| EM4100, EM4102 | The common read-only 125 kHz tag chips; they hold a fixed 40-bit (5-byte) ID |
| Field | The 125 kHz magnetic field of the reader's coil; a tag works only inside it |
| UART, 9600 8N1 | Serial data on one wire: 9600 bits per second, 8 data bits, no parity bit, 1 stop bit |
| ASCII, hex | Characters sent as codes ("5" is 0x35); a hex digit is 0 - 9 or A - F, two digits per byte |
| Checksum, XOR | A check value that reveals damaged data; XOR compares two bits and gives 1 when they differ |
| Wiegand-26 | The access-control output: 26 bits as pulses on two wires, D0 for a 0 and D1 for a 1 |
| Facility code, card number | The two numbers inside a Wiegand-26 frame: 8 bits and 16 bits |
| Parity bit | An extra bit that makes the number of 1s even (even parity) or odd (odd parity) |
| Presentation, tap, hold | One visit of a tag to the reader; a tap is short (0.5 s in our panels), a hold lasts until you remove the tag |
How the EM-18 Reads a Tag: 125 kHz, EM4100 and the 12-Character Frame
Every read, in the simulation and on your desk, takes the same steps:
- Power-up: the tag enters the field and wakes up after about 2 ms.
- EM4100 frames: the tag repeats its 64-bit frame. A bit lasts 64 cycles of 125 kHz (512 us), so a frame takes 32.8 ms.
- Decoding: the reader waits for the next frame start (0 - 32.8 ms) and reads two identical frames (65.5 ms).
- Processing: READ_DELAY, 20 ms by default.
- Output: 12 characters on TX at 9600 baud (12.5 ms); BEEP goes LOW for 100 ms at the first byte.
So a tag close to the reader is decoded 70 - 100 ms after it arrives, and a tag that leaves sooner than about 70 ms is never read. The Read test below measures exactly this.
125 kHz or 13.56 MHz?
Both are passive RFID, but they are two different worlds:
| 125 kHz (EM-18) | 13.56 MHz (MFRC522, PN532) | |
|---|---|---|
| Tags | EM4100 / EM4102 / EM4001 / TK4100 cards and keyfobs | MIFARE Classic, Ultralight, NTAG stickers |
| What the tag holds | A fixed 5-byte ID, read-only | An ID plus memory you can read and write (64 bytes to 4 KB) |
| What the Arduino gets | The finished ID as text (or Wiegand-26) | Card commands over SPI or I2C, handled by a library |
| Protection | None: the ID is sent in the clear | Keys and access bits on MIFARE Classic |
| Range of the usual modules | Up to about 10 cm with a card | A few centimetres |
125 kHz is the simple choice when you only need to know WHICH tag is there; for cards that carry data, see our MFRC522 RFID Library for Proteus.
EM4100 Tags: a 5-Byte ID That Never Changes
An EM4100 tag stores five bytes (40 bits), written at the factory and never changed. Its 64-bit frame holds a header of nine 1s, the 40 ID bits in ten groups of four, each with a parity bit, four column parity bits and a stop bit (9 + 50 + 4 + 1 = 64). The reader checks the parity and hands you the 40 bits as 10 hex digits: our TAG 1 is 5400A1B2C3. Our keyfobs are EM4102 tags with the same format.
The 12-Character Frame and Its XOR Checksum
The EM-18 sends the five ID bytes as text: each byte becomes two hex characters, and two more carry a checksum. For TAG 1, the reader sends 5400A1B2C384. On the wire, "5" is the ASCII code 0x35 and "4" is 0x34, so the 12 bytes are 35 34 30 30 41 31 42 32 43 33 38 34, with no start byte, no end byte and no line ending.
The checksum is the XOR of the five ID bytes. XOR compares two numbers bit by bit and gives 1 where the bits differ:
- 54 XOR 00 = 54
- 54 XOR A1 = F5 (in binary: 0101 0100 XOR 1010 0001 = 1111 0101)
- F5 XOR B2 = 47
- 47 XOR C3 = 84
Your sketch repeats this sum and compares it with the two characters received. A checksum only detects errors, though: TAG 2 and TAG 4 both have 93.
UART or Wiegand-26: the SEL Pin
The SEL pin chooses the output. SEL HIGH gives UART, the 12 characters on TX. SEL LOW gives Wiegand-26, the standard of access-control panels: 26 short LOW pulses on two wires, on D0 for a 0 and on D1 for a 1, 100 us long and 1 ms apart in our model.
The 26 bits are an even parity bit, an 8-bit facility code, a 16-bit card number and an odd parity bit, so only the last three ID bytes travel: for 5400A1B2C3, facility A1 = 161 and card B2C3 = 45763. Many 125 kHz cards have this pair printed on them. In the simulation, SEL may stay open; then the OUTPUT property decides (UART by default).
One Read per Tap, and the Read Range
A real EM-18 sends a tag once per presentation, then waits until it leaves the field; to read it again, take it away and bring it back. Our v1.1 model does the same. (The RDM6300, a similar module, repeats its frame every 65 ms; the MODE property switches to that format.)
The field is weak, so a tag must be close: a card is read up to the RANGE property, 10 cm by default (the data sheet says "up to 100 mm, depending on tag"), and a keyfob up to half of that. Near the edge, the reader needs 3 or 4 frames instead of 2.
What's New in EM18 RFID Library for Proteus V1.1
If you used version 1.0, here is what has changed:
- Two devices in
TEPEM18.LIB: EM18 Simple (EM18TEP, the v1.0 device, so old designs keep working) and EM18 Advance (EM18ADVTEP) with a pop-up window. - A redrawn board: the black EM-18 square instead of v1.0's blue "RFID" board, with a glowing coil, waves, the tag drawn on it, and PWR / BEEP LEDs and a buzzer (a TEP addition).
- New pins SEL, D0 and D1; VCC, GND, BEEP and TX keep their v1.0 order and places.
- Real reader behaviour: the EM4100 read time (first byte 88 - 120 ms after the tap; v1.0: 20 ms after the click), the read range, one read per presentation and Wiegand-26.
- EM4100 cards and EM4102 keyfobs (TYPE1 - TYPE4), and test tags with a damaged checksum.
- Close and reopen: a red X and PANEL on the Simple, OPEN PANEL on the Advance.
- Tag wallet, tag editor and four measured test tools on the Advance.
- A two-UNO demo with the TEP Serial Monitor instead of the Virtual Terminal: AltSoftSerial on D8 (v1.0: a polled receiver on A4), access LEDs, ADD / DEL / STATUS / HELP and no "[status]" line every 10 s.
- Lighter package: about 1.4 MB, without the C++ source code (v1.0: about 7.4 MB).
EM18 RFID Library for Proteus: Simple vs Advance
Both devices run the same model with the same properties; only the panel differs:
| Feature | Simple | Advance |
|---|---|---|
| Full EM-18 model (125 kHz field, EM4100 read time, range, one read per tap, UART, Wiegand-26, BEEP, SEL) | ✔ | ✔ |
| Black EM-18 board with the glowing coil, the tag drawn on it, PWR / BEEP LEDs and buzzer | ✔ | ✔ |
| Tag panel on the schematic (TAG 1 - 4, REMOVE TAG, last frames) | ✔ | ✘ |
| Tag wallet in a pop-up window you can move, resize and minimise | ✘ | ✔ |
| Tap (0.5 s) and Hold at 1 - 12 cm | ✘ | ✔ |
| Tag editor: card / keyfob, ID keypad, checksum OK / Bad, what the reader sends | ✘ | ✔ |
| Read test, Range, Frame check and Output check | ✘ | ✔ |
| TEP Dark / Light theme, text size, Help page with Copy diagnostics | ✘ | ✔ |
| Same device name as v1.0 (old designs keep working) | ✔ | ✘ |
Choose Simple to keep the tags beside your circuit, and Advance when your sheet is full or you want hard numbers. The demo has one of each.
Download EM18 RFID Library for Proteus
Click the button below to download EM18-RFID-Library-for-Proteus-v1.1.zip (about 1.4 MB, without the C++ source code):
EM18 RFID Library for Proteus V1.1- README.txt: a detailed guide to the files, the wiring, the tags, the test tools and real hardware.
- Proteus Library Files:
TEPEM18.LIB(both devices),TEPSERIALMON.LIBand our Arduino UNO libraryArduinoV3TEP.LIB/ArduinoV3TEP.IDX. - Proteus Model Files:
TEPEM18.DLLandTEPSERIALMON.DLL. - Proteus Simulation:
EM18-ArduinoUnoV3.pdsprj,EM18_Demo.hexand copies of both DLLs. - Arduino Code:
EM18_Demo.inoand AltSoftSerial 1.4 by Paul Stoffregen (PJRC), unmodified, under the MIT licence with its LICENSE.txt.
No Proteus yet? Read How to Download and Install Proteus 7 and 8. New to libraries? Follow How to Install a New Library in Proteus.
How to Install EM18 RFID Library for Proteus
- Close Proteus and extract the whole zip file.
- Copy the four files from Proteus Library Files into the LIBRARY folder, usually
C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Professional\LIBRARY(on some PCsC:\ProgramData\Labcenter Electronics\Proteus 8 Professional\LIBRARY). - Copy
TEPEM18.DLLandTEPSERIALMON.DLLinto the MODELS folder. - Start Proteus, press P and search for EM18 (or RFID). You get the Simple and the Advance device (category Sensors > RFID).
Updating from v1.0? Replace TEPEM18.LIB and TEPEM18.DLL, and delete TEPEM18.IDX if there is one in LIBRARY. A v1.0 design keeps its v1.0 symbol: it runs with the new model (with the v1.1 read time) and shows the v1.0 panel, without the new board parts and the red X; re-pick the part to get the v1.1 board. Tested in Proteus 8.5; Proteus 7 is not supported.
The EM-18 Board in Proteus
We drew the reader as a clean TEP board in the shape and colour of the real module. Its hidden coil is an x-ray ring of three copper turns, and the tag on the reader is drawn in the middle. Below sit the panel button, the PWR and BEEP LEDs, a buzzer and the SIMPLE or ADVANCE badge. Here is U1, the Simple device, a moment after I clicked TAG 1:
The coil and the waves are green: the ID has just been sent. The card shows TAG 1 and 5400A1B2C3, with "2 cm", "READ" and "TAP 0.2 s", the time left of the 0.5 s tap. The PWR and BEEP LEDs are lit, and the buzzer's arcs glow orange.
Pinout
Proteus shows seven pins: VCC, GND, BEEP and TX in their v1.0 places, then SEL, D0 and D1. The real module has nine pins in another order, so always wire by the names:
| Pin | Function | Real module | Demo connection |
|---|---|---|---|
| VCC | Power, 5 V | Pin 1 | Supply terminal |
| GND | Ground | Pin 2 | GND |
| BEEP | LOW for BEEP_MS (100 ms) on every read | Pin 3 (BUZZ) | Arduino D12 |
| TX | UART output, 9600 8N1: the 12 characters | Pin 7 | Arduino D8 and Serial Monitor RXD2 |
| SEL | Output select: HIGH = UART, LOW = Wiegand-26, open = the OUTPUT property | Pin 6 | Not connected |
| D0 | Wiegand data 0: a LOW pulse for every 0 bit | Pin 9 | Not connected |
| D1 | Wiegand data 1: a LOW pulse for every 1 bit | Pin 8 | Not connected |
Coil, LEDs and Buzzer
| Indicator | What it shows |
|---|---|
| Coil (three turns) | Copper = no power, cyan = the 125 kHz field is on, amber = the reader is reading a tag, green = the tag was just sent; one brighter turn ripples round the ring |
| Waves above the module | Follow the coil's colour |
| Tag on the module | A card (orange band) or a blue keyfob with TAG n, its ID, the distance and its state (READING, READ, OUT OF RANGE drawn dimmed), then the tap time left or HELD; "PLACE A TAG HERE · 125 kHz · EM4100 / EM4102" when empty |
| PWR LED (red) | Lit while VCC and GND are powered |
| BEEP LED (green) and buzzer arcs | Lit while the BEEP pin is LOW, at least 0.35 s, so every read is a visible blink |
| PANEL / OPEN PANEL, SIMPLE / ADVANCE | The panel button and the device badge |
The LEDs and the buzzer are a TEP addition: the real EM-18 has none. They show what the buzzer and LED of its data sheet circuit would do.
Component Properties
| Property | Meaning | Default |
|---|---|---|
| TAG1 - TAG4 | The tag IDs: 10 hex characters, or 12 = the ID plus the checksum to send (a wrong one makes a damaged-checksum tag) | 5400A1B2C3, 5400D4E5F6, 1A0077B8C9, 1A00ABCDEF |
| TYPE1 - TYPE4 | CARD (EM4100 card, read up to RANGE) or KEYFOB (EM4102 keyfob, up to RANGE / 2) | CARD, CARD, KEYFOB, KEYFOB |
| MODE | EM18 (12 characters, once per presentation) or RDM6300 (0x02 + 12 characters + 0x03, every 65 ms while the tag stays) | EM18 |
| OUTPUT | UART or WIEGAND while the SEL pin is open (a wired SEL decides) | UART |
| BAUD | UART baud rate (300 - 115200) | 9600 |
| READ_DELAY | The module's processing time after it has decoded the tag, ms | 20 |
| BEEP_MS | How long BEEP stays LOW on a read, ms | 100 |
| RANGE | Read range with a card, cm (1 - 30) | 10 |
| DISTANCE | Where the Simple panel taps a tag, cm | 2 |
Changes made in the Advance tag editor last while the simulation runs; every run starts from these properties.
EM18 Simple: The Tag Panel on the Sheet
Beside the Simple board sits the EM-18 RFID TAGS panel (on the right of the image above):
| Part | What it shows |
|---|---|
| Header, red X | EM-18 RFID TAGS; the X closes the panel |
| State bar | FIELD ON - NO TAG, then for example TAG 1 AT 2 CM: READING and READ - REMOVE TO READ AGAIN; OUT OF RANGE; NO POWER - CHECK VCC / GND |
| Info line | READS 1, LAST 5400A1B2C3 84 OK, UART 9600: the reads, the last ID with its checksum, and the output |
| TAG 1 - TAG 4 | Click one to tap it on the reader for 0.5 s at the DISTANCE property's distance; each row shows the kind (EM4100 CARD or EM4102 KEYFOB) and the checksum |
| REMOVE TAG | Takes the tag away |
| LAST FRAMES ON TX / D0 D1 | The frames the reader sent, newest at the top, for example T1 5400A1B2C384 SUM OK; a missed tap shows as LEFT TOO SOON - NOT READ |
Tapping TAG 1: ACCESS GRANTED
Click TAG 1. The coil turns amber while the reader decodes the card, then green as the 12 characters leave TX, and the BEEP LED blinks. U3 prints "Read #1 Tag: 5400A1B2C3 -> ACCESS GRANTED", and the access LED D1 lights for 3 s. The panel logs T1 5400A1B2C384 SUM OK. A click is a 0.5 s tap, so click again to read the tag again.
TAG 3: A Keyfob Is Denied
TAG 3 is an EM4102 keyfob, drawn as a blue drop:
The panel shows READS 2 and logs T3 1A0077B8C91C SUM OK. The checksum is fine, but 1A0077B8C9 is not in the sketch's list, so U3 prints ACCESS DENIED; TAG 4 is denied too. Tip: set DISTANCE to 6, and the cards are still read, but the keyfobs are OUT OF RANGE, because a keyfob reaches only 5 cm.
Closing the Panel
Need room on the sheet? Click the red X: the board button says PANEL: CLOSED with a grey dot, and the reader keeps running. PANEL brings it back.
With no tag on it, the coil is cyan: the 125 kHz field is on, and the reader waits.
EM18 Advance: The Pop-Up Tag Wallet
The Advance device keeps only the board on the schematic. At Run, the "TEP EM18 Advance" pop-up opens with the look of our Serial Monitor and no Windows title bar: move, resize or minimise it, and reopen it with OPEN PANEL. Its header shows the state (for example U2 · TAG READ), the Tags and Test tabs and the theme, Settings and Help icons.
A Held Tag Is Read Once
On the Tags page, click Hold next to TAG 2. The card stays on the reader until you remove it. The reader sends it, and U2's board lights up:
A moment later, the card is still HELD, but the coil is cyan again, BEEP is dark and TX stays silent:
That is one read per presentation. While TAG 2 is held, click 12 cm: the tag moves with the distance, is drawn dimmed as OUT OF RANGE, and nothing is read. Click 2 cm, and it is read again, because for the reader it is a new presentation.
The Tags Page
The READER card shows the field, the output ("UART 9600 8N1, EM-18 ASCII"), the tag and the reads. Below are the distance buttons (1 - 12 cm) and the four tags with their range: Tap puts a tag on the reader for 0.5 s, Hold keeps it there until you click Remove the tag. On the right, WHAT THE READER SENDS FOR IT works out TAG 2:
- UART: 5400D4E5F6 93, 12 characters in 12.5 ms.
- Checksum: 54 ^ 00 ^ D4 ^ E5 ^ F6 = 93 (^ is XOR in C).
- Bytes: 35 34 30 30 44 34 45 35 46 36 39 33, the ASCII codes.
- Wiegand-26: 1 11010100 1110010111110110 1, facility 212, card 58870.
LAST FRAMES lists one frame, "78.743 s T2 5400D4E5F693 106 ms", although the card is still held.
The Tag Editor: Testing a Bad Checksum
Does your sketch really check the checksum? Click TAG 4: the editor offers Card or Keyfob, the ID with a hex keypad (or Random) and Sum: OK or Bad. I chose Bad, clicked Apply and tapped TAG 4:
The reader sent "1A00ABCDEF 6C": the model inverts every bit of the checksum (6C instead of 93), and the Wiegand parity is damaged too. The frame is marked BAD, and U4 printed "Read #2 Tag: 1A00ABCDEF -> CHECKSUM ERROR". Real errors come from a wrong baud rate; this is how you test your code for them.
The Test Page: Four Measured RFID Test Tools
The tools place tags in the field and read the reader's own records (the frames sent, the reads missed and every level on TX, D0, D1 and BEEP), so every number is measured with the simulation clock while your sketch runs. Each tool ends with a "Good for:" line.
1. Read Test: How Long Must a Tag Stay on the Reader?
Choose the tag, the tap length (0.08 - 0.5 s) and 3, 5 or 10 runs; the tool taps at 2 cm and times each read. TAG 1, five taps of 0.5 s:
All 5 / 5 taps were read, one frame each. Take tap 1: decoded after 88.2 ms, the first byte 20 ms later (the READ_DELAY) at 108.2 ms, and the last byte 12.5 ms after that, at 120.7 ms; now the ID is in your Arduino. "Decoded" varies from 70.4 to 98.0 ms, because the reader waits 0 - 32.8 ms for the next frame header. On average: 84.6 ms to decode, 117.1 ms to the Arduino. With 0.08 s taps, some taps are missed. Good for: seeing how long a tag must stay on the reader and when your sketch gets its ID.
2. Range: How Far Away Is a Tag Still Read?
One 0.5 s tap at each distance from 1 to 12 cm. TAG 1, a card:
| Distance | 1 - 7 cm | 8 cm | 9 cm | 10 cm | 11 and 12 cm |
|---|---|---|---|---|---|
| Decode time | 71 - 98 ms | 120 ms | 129 ms | 148 ms | not read |
| Frames | 2 | 3 | 3 | 4 | - |
Up to 7 cm, two frames are enough. At 8 - 10 cm, the bars turn amber: the weak signal needs 3 or 4 frames. Past the red "range 10.0 cm" line, nothing is read. A keyfob (tag 3 or 4) is read up to 5 cm. Good for: finding how far from the reader a card or a keyfob is still read.
3. Frame Check: The 12 Characters on the TX Pin
One tap, and the TX pin is decoded like a UART receiver: every bit sampled in its middle, the start and stop bits checked, the checksum worked out again. TAG 1:
The table lists the 12 bytes of 5400A1B2C384, from 35 = "5" at 0.000 ms to 34 = "4" at 11.458 ms, and the checksum matches: "84 sent, 84 calc". In the waveform, each byte is a LOW start bit (S), 8 data bits with the least significant bit first and a HIGH stop bit. The measured bit time is 104.17 us = 9600 bd (1 / 9600 s), so a 10-bit byte takes 1.042 ms and the frame 12.50 ms. Good for: checking the 12 characters your sketch must parse.
4. Output Check: Wiegand-26 and the BEEP Pulse
One tap with UART or Wiegand-26; while SEL is open, the tool chooses. TAG 1 with Wiegand-26:
D0 pulsed 15 times and D1 11: 26 bits of 100 us, 1.00 ms apart. The bits read 0, 10100001 (facility A1 = 161), 1011001011000011 (card B2C3 = 45763), 0. Bits 2 - 13 hold six 1s (already even) and bits 14 - 25 five (already odd), so both parity bits are 0, and both checks say OK. BEEP went LOW 103.6 ms after the tap, for 100 ms. The wiring card shows Wiegand on D2 / D3 with SEL to GND. Good for: seeing what a Wiegand-26 controller gets from a tag, and the BEEP pulse.
Settings and Help
The gear opens Settings: theme, text size, open the panel at Run and window size, saved for your Windows user.
The ? icon opens Help & Support: eight cards (the EM18 board of our forum, this article, donate, website, forum) and Copy diagnostics for a bug report. A links.ini next to the DLL can change the links.
EM-18 Access Control with Arduino in Proteus
Open EM18-ArduinoUnoV3.pdsprj from the Proteus Simulation folder, with the .hex file and both DLLs beside it. Its two Arduino UNOs from our Arduino Library for Proteus V3.0 both run EM18_Demo.hex (the first image shows the whole circuit):
- NODE 1 - EM18 SIMPLE: UNO 1 (ARD1) with the EM18 Simple (U1), the access LED D1 on A0 and Serial Monitor U3.
- NODE 2 - EM18 ADVANCE: UNO 2 (ARD2) with the EM18 Advance (U2), the access LED D2 on A0 and Serial Monitor U4.
Wiring
| From | To | Why |
|---|---|---|
| EM-18 VCC / GND | Supply (+5 V) / ground | Power |
| EM-18 TX | Arduino D8 | AltSoftSerial RX, 9600 8N1 |
| EM-18 BEEP | Arduino D12 | The sketch counts the beeps (INPUT_PULLUP) |
| EM-18 SEL, D0, D1 | Not connected | SEL open = UART (the OUTPUT property) |
| LED + 220 Ω | A0 to GND | The access LED, 3 s on ACCESS GRANTED |
| Serial Monitor RXD / TXD / GND | Arduino D1 / D0 / ground | Shows what the Arduino prints, sends what you type |
| Serial Monitor RXD2 | The EM-18 TX line (a junction on the TX wire) | Shows the reader's raw frames as RX2 |
See our Introduction to Arduino UNO for the pins. VCC goes to +5 V, like on the real module.
Why AltSoftSerial on D8?
D0 / D1, the UNO's hardware serial port, belongs to the Serial Monitor, so the reader needs a second serial input. SoftwareSerial cannot receive in Proteus 8.5: it relies on pin-change interrupts, which Proteus 8.5 never runs. AltSoftSerial uses Timer1's input capture on D8 instead, which works in Proteus and on a real UNO. It also takes D9 (its TX, unused here) and stops PWM on D10. Our HC-12 Library for Proteus uses the same trick.
The Arduino Code
The sketch needs only AltSoftSerial by Paul Stoffregen, included in the package:
#include <AltSoftSerial.h>
AltSoftSerial rfid; // RX = D8 (the EM-18's TX), TX = D9 (not used)
const byte BEEP_PIN = 12; // the EM-18's BEEP output (LOW while it beeps)
const byte LED_PIN = A0; // the access LED
Tags 1 and 2 are allowed from the start; ADD can grow the list to 8:
const byte MAX_ALLOWED = 8;
char allowed[MAX_ALLOWED][11] = { "5400A1B2C3", "5400D4E5F6" }; // v1.0: cards 1 and 2
In setup(), both ports run at 9600 baud, and BEEP (active LOW) gets a pull-up:
Serial.begin(9600);
rfid.begin(9600);
pinMode(BEEP_PIN, INPUT_PULLUP);
The loop() feeds every byte from D8 to receive(); a frame that stops for 50 ms starts again:
// the reader on D8 (AltSoftSerial)
while (rfid.available()) receive((char)rfid.read());
if (length && millis() - lastByteAt > FRAME_GAP_MS) length = 0; // a broken frame: start again
The EM-18 sends no line ending, so receive() counts 12 hex characters. It skips the RDM6300 start and end bytes, so both formats work:
void receive(char c) {
byteCount++;
lastByteAt = millis();
if (c == 0x02) { length = 0; return; } // RDM6300 start byte
if (c == 0x03) return; // RDM6300 end byte
if (hexValue(c) < 0) { length = 0; return; }
frame[length++] = c;
if (length == 12) {
frame[12] = 0;
frameCount++;
handleFrame();
length = 0;
}
}
handleFrame() repeats our XOR sum; hexByte() turns "A" and "1" into 0xA1:
byte hexByte(const char* p) { return (hexValue(p[0]) << 4) | hexValue(p[1]); }
Then the five ID bytes are XORed and compared with the last two characters:
byte checksum = 0;
for (byte i = 0; i < 10; i += 2) checksum ^= hexByte(frame + i);
const byte received = hexByte(frame + 10);
A wrong checksum ends the read before any access decision:
if (checksum != received) {
sumErrors++;
Serial.println(F(" -> CHECKSUM ERROR"));
return;
}
A granted ID lights the LED on A0; the loop switches it off after 3 s:
const bool granted = findAllowed(id) >= 0;
Serial.println(granted ? F(" -> ACCESS GRANTED") : F(" -> ACCESS DENIED"));
if (granted) {
digitalWrite(LED_PIN, HIGH);
ledOn = true;
ledOnAt = millis();
}
The RDM6300 format repeats a held tag every 65 ms, so the same tag within 0.3 s is ignored:
// RDM6300 repeats the tag every 65 ms while it stays: the same tag within 0.3 s is not a new read
if (strcmp(id, lastTag) == 0 && millis() - lastReadAt < REPEAT_MS) {
lastReadAt = millis();
repeats++;
return;
}
And the loop counts the BEEP pulses on D12 for STATUS:
const bool beepLow = digitalRead(BEEP_PIN) == LOW;
if (beepLow && !beepWasLow) beepCount++;
beepWasLow = beepLow;
The list lives in RAM, so a reset brings back the two default tags. If D8 stays LOW for 50 ms, the sketch prints one wiring warning; nothing is printed periodically. To change the sketch, export a new HEX file and load it into both UNOs; see How to get the HEX file from Arduino. New to Arduino? Start with our Arduino Tutorial for Beginners.
Serial Monitor Commands
| Command | What it does |
|---|---|
| HELP | The command list |
| STATUS | Reads and checksum errors, allowed tags, beeps, the LED, the last tag, the D8 line check and the list |
| ADD [id] | Allows the last tag read, or a 10-digit hex ID (spaces allowed); up to 8 tags |
| DEL [id] | Removes it from the list |
How to Run the Demo
- Press Run. Both Serial Monitors (9600 baud) and U2's pop-up open, and both coils turn cyan.
- On U1's panel, click TAG 1 (granted, D1 lights), then TAG 3 (denied).
- Type ADD in U3's send box, click TAG 3 again (granted) and type STATUS.
- In U2's pop-up, Hold TAG 2, try 12 cm and 2 cm, then set TAG 4 to Sum = Bad and Tap it.
- Run the four tools on U2's Test tab.
EM18 Proteus Simulation Results
The Serial Monitor in Its Simple Interface
Both monitors run in the Simple interface of our TEP Serial Monitor, as in every monitor screenshot here: only the log, the send box and one slim toolbar row (baud rate, follow, pause, search, clear) stay visible, so the window stays small next to your schematic.
- Switch to it: right-click the log and choose Simple interface, or press Ctrl+Shift+U.
- Back to the full view: click the corner button (the expand arrows at the top right), press Esc or Ctrl+Shift+U, or right-click and choose Full interface.
- Your choice is remembered.
Type commands such as STATUS or ADD in the send box and press Enter; the quick buttons return with the full view. Read all about the monitor in TEP Serial Monitor Advance for Proteus.
RX and RX2: The Sketch and the Raw Frames
The monitor's second input, RXD2, watches the EM-18's TX line. Green RX lines are what the sketch prints, amber RX2 lines are the raw frames, and lines you type carry a blue TX tag. The EM-18 sends no line ending, so the first frame gets the RX2 tag, and later frames appear as continuation rows with a small hook symbol instead of a tag (indented in the listings below). That is exactly what the reader sends.
Start-Up
After Run, U3 prints the banner, the allowed tags and the commands, then stays quiet until a tag is read:
TEP EM-18 RFID Reader Demo v1.1
Authorised: 5400A1B2C3, 5400D4E5F6
Click a card on the reader panel...
Serial Monitor: HELP, STATUS, ADD [id], DEL [id]
TAG 1, TAG 3 and ADD
Now the best part of the new sketch. On U1, I clicked TAG 1 and TAG 3, typed ADD in U3's send box, clicked TAG 3 again and typed STATUS:
Read #1 Tag: 5400A1B2C3 -> ACCESS GRANTED
1A0077B8C91C
Read #2 Tag: 1A0077B8C9 -> ACCESS DENIED
ADD
Added 1A0077B8C9 (3 allowed)
1A0077B8C91C
Read #3 Tag: 1A0077B8C9 -> ACCESS GRANTED
STATUS
Status: 3 reads (0 checksum errors), 3 allowed, 3 beeps, LED on, last 1A0077B8C9
D8 (AltSoftSerial RX): idle HIGH ok, 36 bytes, 3 frames
allowed: 5400A1B2C3
allowed: 5400D4E5F6
allowed: 1A0077B8C9
Line 5, just above this view, holds the first raw frame with its RX2 tag. ADD took the last tag read, and Read #3 grants the same keyfob; in v1.0, that meant a new HEX file. STATUS counts 3 reads, 3 beeps on D12 and 36 bytes in 3 frames (3 x 12): not one character was lost. DEL removes the keyfob again.
CHECKSUM ERROR on U4
And here is U4, after TAG 2 was held and TAG 4 was tapped with Sum = Bad:
TEP EM-18 RFID Reader Demo v1.1
Authorised: 5400A1B2C3, 5400D4E5F6
Click a card on the reader panel...
Serial Monitor: HELP, STATUS, ADD [id], DEL [id]
5400D4E5F693
Read #1 Tag: 5400D4E5F6 -> ACCESS GRANTED
1A00ABCDEF6C
Read #2 Tag: 1A00ABCDEF -> CHECKSUM ERROR
TAG 2 (RX2: 5400D4E5F693) is granted. Then the damaged frame 1A00ABCDEF6C arrives, and the sketch prints CHECKSUM ERROR: it worked out 93, received 6C and made no access decision. Your own code should do the same: never open a door for a damaged ID.
Troubleshooting
- Nothing on the monitor: check TX -> D8, VCC / GND (PWR LED lit) and that your sketch uses AltSoftSerial; RX2 shows whether the reader sent anything.
- A held tag is read only once: correct; remove it, or tap it again.
- A tap is not read: too short (under about 70 ms) or out of range; the Simulation Log says which.
- CHECKSUM ERROR: Sum = Bad, or a 12-digit TAGn with a wrong checksum; on a real module, check the baud rate.
- The BEEP LED blinks, but nothing is printed: SEL is LOW or OUTPUT = WIEGAND, so the UART is silent.
- No pop-up, panel or monitor: a DLL is missing from MODELS and the project folder; click OPEN PANEL or OPEN MONITOR.
Things to Know Before Using a Real EM-18
The demo sketch runs on a real UNO and EM-18, too. Keep in mind:
- 5 V module: 4.6 - 5.5 V, about 50 mA; feed it from the Arduino's 5 V.
- TTL output: TX is a 5 V serial output (9600 8N1); wire it straight to D8 or RX of a 5 V Arduino. A 3.3 V board needs a 5 V tolerant input or a divider.
- Tie SEL: to 5 V for the UART on TX, to GND for Wiegand on D0 / D1; only the simulation accepts it open.
- BEEP is active LOW: drive a buzzer and an LED through a PNP transistor (a BC557 with 2.2 k in the data sheet), never a buzzer directly.
- Range: up to about 10 cm with an ISO card, less with keyfobs and small tags; metal near the module and an unsteady supply shorten it.
- Tags: 125 kHz EM4100, EM4102, EM4001 and TK4100 (64-bit, read-only). 13.56 MHz MIFARE and NFC cards are NOT read; use the MFRC522 for them.
- One read per tap: many cheap modules sold as EM-18 behave the same way.
- Security: an EM4100 ID is not a secret, and tags with a copied ID exist; an ID list is fine for learning, but not for a real door.
Limitations of the Simulation
- Not modelled: several tags at once, the EM4100 data on the air, tag orientation, metal and supply effects on the range, the supply current, the magnetic-stripe output of some EM-18 variants, read / write tags (T5577) and 13.56 MHz cards.
- The model is our own implementation, written from the EM-18 data sheet, the EM4100 tag format and the Wiegand-26 format; it contains no third-party firmware or code.
- Tested in Proteus 8.5 on 7 Oct 2026 with the final build (the demo, the four tools and every screenshot here) and with 1,244 automatic PC checks, all passed, 33 of them with the real demo sketch. Proteus 7 is not supported.
For 13.56 MHz cards, see our MFRC522 RFID Library for Proteus; for NFC over SPI or I2C, our PN532 NFC Library for Proteus. To send each ID to another Arduino by radio, add our HC-12 Library for Proteus.
So, that was all about the EM18 RFID Library for Proteus V1.1. I hope the glowing coil, the tag wallet, the four test tools and the CHECKSUM ERROR experiment make 125 kHz RFID much easier to understand, so your access-control project works the first time you wire a real EM-18. If you use the EM18 RFID Library for Proteus in a project, please share your feedback in the comments or in our forum, and if you have any questions, ask in the comments and I will help you out. Till the next tutorial, take care and have fun!
























Comments
0