EM-18 running Proteus simulation, RFID reader with Arduino Uno, tag IDs on Virtual Terminal, ACCESS GRANTED and ACCESS DENIED results

EM-18 RFID Proteus Library | Arduino Simulation with Code

2.5K Views
40
700
60
25
60
PCBWay

Hello friends, I hope you are doing well. In today's tutorial, I am going to share our EM-18 RFID Proteus Library. With this library, we can connect an EM-18 RFID reader to an Arduino Uno and tap a virtual card on the reader with a single click. The Arduino receives the tag number through a serial line, checks it and prints whether access is granted or denied.

We will start with the basics of the reader, install the library files and wire the circuit. After that, we will run the supplied simulation, understand the Arduino code and calculate the checksum that protects every tag number. The download includes the wired project, compiled HEX and editable sketch, so you can run the example before compiling anything yourself.

This tutorial uses our V1.0 package, the TEP Arduino UNO V3 and a 16 MHz clock. The package targets Proteus 8.5 with AVR simulation support. In the running screenshot below, the four cards have been tapped several times. Cards 1 and 2 are granted, while cards 3 and 4 are denied.

EM-18 running Proteus simulation, RFID reader with Arduino Uno, tag IDs on Virtual Terminal, ACCESS GRANTED and ACCESS DENIED results
Figure: The four cards have been tapped nine times. Tags 5400A1B2C3 and 5400D4E5F6 are granted, while 1A0077B8C9 and 1A00ABCDEF are denied.

What Is the EM-18 RFID Reader?

The EM-18 is a reader module for low-frequency RFID cards that work at 125 kHz. It reads the identification number stored in a card and sends that number to a microcontroller as plain text. We do not need a driver library for it. Any serial receiver at 9600 baud can read its output.

How the Reader Works

  1. A card comes near the reader.
  2. The reader gets the card's identification number, which has five bytes.
  3. The reader pulls its BEEP pin low for a short time.
  4. The reader sends the number on its TX pin as 12 text characters.
  5. The microcontroller receives the characters and checks them.

Important Terms

  • Tag ID: the identification number of the card. Its five bytes are sent as 10 hexadecimal characters.
  • Checksum: one extra byte that the receiver uses to detect a damaged message. It is sent as two characters.
  • Frame: the complete message for one card read.
  • UART: the serial format used by the TX pin. Our example uses 9600 baud, eight data bits, no parity and one stop bit.

Features of Our Proteus Model

  • The component is named EM18TEP and has four pins: VCC, GND, BEEP and TX.
  • Four virtual cards are available on a control panel beside the reader.
  • Each card's tag ID can be changed in the component properties.
  • The output can follow the EM-18 format or the RDM6300 format.
  • The baud rate, read delay and beep length are adjustable.

Keep one distinction in mind. This is a functional model of the reader's serial output. A click on the panel replaces the physical action of bringing a card near the reader. The radio field, reading distance and antenna are not simulated.

Download the EM-18 RFID Library for Proteus

First of all, download the V1.0 package using the button below. Extract the complete ZIP into a normal folder before opening the project, and keep the files of the simulation folder together.

Download EM-18 RFID Proteus Library V1.0 and Arduino Simulation
Contents of the EM-18 RFID Proteus package
Folder or fileContents and purpose
Proteus Library FilesTEPEM18.LIB for the reader, and the TEP Arduino UNO V3 LIB/IDX files.
Proteus Model FilesTEPEM18.DLL, which provides the reader's simulated behavior.
Proteus SimulationEM18-ArduinoUnoV3.pdsprj, EM18_Demo.hex and a local copy of the DLL.
Arduino CodeThe demo sketch, the AVR core archive and a firmware rebuild script.
Model SourceThe source code of the reader model and its rebuild script.
DocumentationModel notes, third-party notices and a preview of the board artwork.
README.txt and SHA256SUMS.txtQuick-start instructions and checksums of the packaged files.

This package does not contain an Arduino driver library, because the sketch does not need one. The LIB file defines the component that we place on the schematic, and the DLL gives it its behavior.

How to Install the EM-18 Library in Proteus

Copy the Library and Model Files

Save your work and close Proteus before copying the files. Then follow these steps:

  1. Open the extracted Proteus Library Files folder.
  2. Copy TEPEM18.LIB into the library directory configured for your Proteus installation.
  3. Copy ArduinoV3TEP.LIB and ArduinoV3TEP.IDX from the same folder if our TEP Arduino UNO V3 library is not installed already.
  4. Open Proteus Model Files and copy TEPEM18.DLL into your configured Proteus MODELS directory.
  5. Restart Proteus, open Pick Devices and search for EM18TEP.
  6. Place the reader on the schematic, or open the supplied project to use the completed circuit.

Points to Remember

  • Use the library and model folders that your installation actually searches. Their locations differ between installations.
  • The reader is supplied as a LIB file without a separate IDX. The included IDX belongs to the Arduino board.
  • Keep the extra DLL beside the project in the Proteus Simulation folder.
  • EM18_Demo.hex belongs to the Arduino's Program File property. The reader does not need a HEX file.
  • Compatibility with Proteus 7 has not been established. The supplied project uses the Proteus 8 project format.

The Arduino board in this project comes from our Arduino Library for Proteus V3.0. Start with the supplied project, so that the board, wiring and firmware match the demonstration.

EM-18 Pinout and Arduino Uno Wiring

The TEP reader has four pins along its lower edge. From left to right, they are VCC, GND, BEEP and TX. Start each wire at the exposed pin endpoint below the board artwork.

Connections used by the supplied simulation
Reader pinConnectionPurpose
VCCPositive supply terminalPowers the digital model.
GNDGroundProvides the shared reference.
BEEPArduino Uno A5Goes low for 100 ms on every read. It is active low.
TXArduino Uno A4Sends the tag frame as serial data.
EM-18 Proteus wiring, RFID reader TX on Arduino Uno A4, BEEP on A5, RFID card control panel, Virtual Terminal connections
Figure: The stopped circuit connects TX to A4 and BEEP to A5. The panel lists the four cards with their tag IDs.

The reader has a TX pin but no RX pin. Data travels in one direction only, from the reader to the Arduino. The pins A4 and A5 are used as digital inputs here, although they are labeled as analog inputs on the board.

Virtual Terminal Connections

  • Connect Arduino D1/TX to RXD on the Virtual Terminal.
  • Set the terminal to 9600 baud, eight data bits, no parity and one stop bit.
  • The return connection to D0/RX is shown in the circuit, but you do not need to type anything.

Why TX Goes to A4 and Not to D0

The Arduino Uno has one hardware serial port on D0 and D1, and our example uses it for the Virtual Terminal. The reader therefore needs a different pin. The sketch reads the reader's data on A4 by its own code. The reader may also be wired to D0/RX, because the sketch reads the hardware serial port too.

Notes for Physical Hardware

  • The model treats the reader as unpowered when VCC is low or GND is high. It does not check the supply voltage or the current.
  • A real EM-18 module has more pins than our component. Follow the labels and the documentation of your module.
  • The real module also offers a Wiegand output, which is selected by its SEL pin. Our model provides the serial output only.

Run the EM-18 Simulation

Start the Simulation

  1. Open Proteus Simulation/EM18-ArduinoUnoV3.pdsprj from the extracted package.
  2. Keep EM18_Demo.hex and TEPEM18.DLL in that folder.
  3. Double-click the Arduino and confirm that its Program File is EM18_Demo.hex.
  4. Confirm the 16 MHz clock and the 9600 baud terminal.
  5. Press Run and open the Virtual Terminal window if it is hidden.

The terminal prints three lines at the start. The first line is TEP EM-18 RFID Reader Demo v1.1. The second line lists the two authorised tags, and the third line asks you to click a card.

Tap a Card on the Reader

  1. Click CARD 1 on the control panel. The row turns blue.
  2. Read the new line on the terminal.
  3. Click CARD 3 and compare the result.
  4. Click the same card again to tap it once more.
  5. Click REMOVE CARD to take the card off the reader. Nothing is sent for this button.

The running screenshot at the top shows nine reads. Read #1 is tag 5400A1B2C3 with ACCESS GRANTED, and Read #3 is tag 1A0077B8C9 with ACCESS DENIED. The panel shows CARD 3 in blue, and its last line reads LAST READ: 1A0077B8C9 (EM-18). This agrees with Read #9 on the terminal.

Default Cards of the Library

Default cards and the results of the supplied sketch
CardTag IDChecksumFrame sent on TXResult
CARD 15400A1B2C3845400A1B2C384ACCESS GRANTED
CARD 25400D4E5F6935400D4E5F693ACCESS GRANTED
CARD 31A0077B8C91C1A0077B8C91CACCESS DENIED
CARD 41A00ABCDEF931A00ABCDEF93ACCESS DENIED

Understand the Status Line

The screenshot also contains this line: [status] A4 idle=HIGH ok bytes=84 cards=7. The sketch prints it every 10 seconds, so that we can check the wiring from the terminal.

  • A4 idle=HIGH ok means the TX line rests at a high level, which is correct for a serial line.
  • bytes=84 is the number of characters received so far.
  • cards=7 is the number of complete frames.

The two numbers agree with each other. Seven frames of 12 characters give 7 × 12 = 84 characters. If the line shows LOW instead, check the TX wire and the reader's power.

Understand the EM-18 Control Panel

  • REMOVE CARD takes the card off the reader.
  • CARD 1 to CARD 4 tap that card on the reader. Each button shows the card's tag ID.
  • The last line shows the tag that was read most recently, and the output format in brackets.

Every click on a card sends the tag once. If you click a second card while a frame is still being sent, the model keeps that tap and sends it after the present frame. The Simulation Log records each read and the number of bytes sent.

Arduino Code for the EM-18 Simulation

The following is the exact sketch included in the download. It uses no external library. The supplied HEX file was built from this sketch.

/*
  EM-18 / RDM6300 RFID Reader - Arduino UNO demo for the TEP Proteus library
  The Engineering Projects - www.TheEngineeringProjects.com

  Wiring (as in EM18-ArduinoUnoV3.pdsprj):
    RFID VCC  -> 5V          RFID GND -> GND
    RFID TX   -> A4          (9600 baud, 8N1 - read by a polled UART receiver)
    RFID BEEP -> A5          (goes LOW for 100 ms on every read)
    Arduino D1/TX -> Virtual Terminal RXD (9600 8N1)

  The reader may also be wired to D0/RX instead of A4; hardware Serial is read too.

  In the simulation, click CARD 1..4 on the reader's control panel.
  Cards 1 and 2 are authorised; cards 3 and 4 are denied.
  Works with both output formats (MODE property EM18 or RDM6300).

  The receiver on A4 is a simple polled UART (no SoftwareSerial, no interrupts):
  it waits for the start bit, then samples each bit in the middle. Frames
  are only 12-14 bytes and the reader is idle between cards, so polling is
  enough and it behaves identically in Proteus and on real hardware.
*/
#include <Arduino.h>

const byte RFID_PIN = A4;      // reader TX  (PC4 - read directly for speed)
#define RFID_LINE_LOW() ((PINC & _BV(PC4)) == 0)
const byte BEEP_PIN = A5;      // reader BEEP (active low)
const unsigned int BIT_US = 104;   // 1 / 9600 baud

const char* const authorised[] = { "5400A1B2C3", "5400D4E5F6" };
const byte AUTH_COUNT = sizeof(authorised) / sizeof(authorised[0]);

char frame[13];     // 10 ID characters + 2 checksum characters + NUL
byte length = 0;
unsigned long readCount = 0, byteCount = 0, lastStatus = 0;

int hexValue(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 -1;
}

byte hexByte(const char* p) { return (hexValue(p[0]) << 4) | hexValue(p[1]); }

void handleFrame() {
  char id[11];
  memcpy(id, frame, 10);
  id[10] = 0;

  byte checksum = 0;
  for (byte i = 0; i < 10; i += 2) checksum ^= hexByte(frame + i);
  const byte received = hexByte(frame + 10);

  readCount++;
  Serial.print(F("Read #"));
  Serial.print(readCount);
  Serial.print(F("  Tag: "));
  Serial.print(id);

  if (checksum != received) {
    Serial.println(F("  -> CHECKSUM ERROR"));
    return;
  }

  bool granted = false;
  for (byte i = 0; i < AUTH_COUNT; i++)
    if (strcmp(id, authorised[i]) == 0) granted = true;

  Serial.println(granted ? F("  -> ACCESS GRANTED") : F("  -> ACCESS DENIED"));
}

void receive(char c) {
  byteCount++;
  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;
    handleFrame();
    length = 0;
  }
}

// Polled 8N1 receiver. Call when the line has just gone LOW (start bit).
// Returns -1 on a false start or framing error.
int readPolledByte() {
  delayMicroseconds(BIT_US / 2);                 // middle of the start bit
  if (!RFID_LINE_LOW()) return -1;               // glitch, not a start bit
  byte value = 0;
  for (byte bit = 0; bit < 8; bit++) {
    delayMicroseconds(BIT_US);
    if (!RFID_LINE_LOW()) value |= (1 << bit);   // LSB first
  }
  delayMicroseconds(BIT_US);
  if (RFID_LINE_LOW()) return -1;                // stop bit must be HIGH
  return value;
}

void setup() {
  Serial.begin(9600);
  pinMode(RFID_PIN, INPUT);
  pinMode(BEEP_PIN, INPUT);
  Serial.println(F("TEP EM-18 RFID Reader Demo v1.1"));
  Serial.println(F("Authorised: 5400A1B2C3, 5400D4E5F6"));
  Serial.println(F("Click a card on the reader panel..."));
}

void loop() {
  // Reader wired to A4: poll for a start bit and read the whole frame.
  if (RFID_LINE_LOW()) {
    const int value = readPolledByte();
    if (value >= 0) receive((char)value);
    return;                                      // stay responsive for the next byte
  }
  // Reader wired to D0/RX instead: hardware UART.
  while (Serial.available()) receive((char)Serial.read());

  // Short status line every 10 s so the wiring can be checked from the terminal.
  if (millis() - lastStatus >= 10000) {
    lastStatus = millis();
    Serial.print(F("[status] A4 idle="));
    Serial.print(RFID_LINE_LOW() ? F("LOW (check TX/VCC)") : F("HIGH ok"));
    Serial.print(F(" bytes="));
    Serial.print(byteCount);
    Serial.print(F(" cards="));
    Serial.println(readCount);
  }
}

Set the Pins and the Authorised List

  • RFID_PIN is A4, where the reader's TX pin is connected.
  • RFID_LINE_LOW() reads pin PC4 of the microcontroller directly. PC4 is the same pin as A4. A direct read is faster than digitalRead().
  • BIT_US is 104. It is the length of one bit in microseconds at 9600 baud.
  • The array authorised holds the two tag IDs that are allowed.
  • The array frame has 13 elements: 10 for the ID, 2 for the checksum and 1 for the ending zero.

Receive One Byte by Polling

A serial byte starts with a start bit, which is low. Eight data bits follow, and a stop bit, which is high, ends the byte. The function readPolledByte() reads these bits one after the other:

  1. The loop notices that the line has gone low.
  2. The function waits for half a bit and checks the line again. If the line is high now, it was only a glitch.
  3. It waits for one bit and reads the first data bit in its middle.
  4. It repeats this for all eight data bits. The least significant bit arrives first.
  5. It waits for one more bit and checks that the stop bit is high.

The function returns the byte, or -1 when the start bit or the stop bit was wrong. After each byte, the loop returns at once, so that it is ready for the start bit of the next byte.

Build the Frame

The function receive() handles every byte. It counts the byte and then applies these rules:

  • The value 0x02 is the start byte of the RDM6300 format. It begins a new frame.
  • The value 0x03 is the end byte of the RDM6300 format. It is ignored.
  • A character that is not a hexadecimal digit begins a new frame.
  • Every other character is stored. When 12 characters are complete, the frame is processed.

With these rules, the same sketch accepts the EM-18 format and the RDM6300 format.

Check the Frame and Decide Access

The function handleFrame() copies the first 10 characters as the tag ID. It calculates the checksum from the five ID bytes and compares it with the received checksum. When the two values differ, it prints CHECKSUM ERROR and makes no access decision. Otherwise it compares the ID with the authorised list and prints the result.

The helper hexByte() converts two text characters into one byte. For example, the characters A and 1 become the value 0xA1.

What the Sketch Does with BEEP

The sketch sets A5 as an input, but it does not read the pin. The BEEP connection is ready for your own experiments, such as switching an LED or a buzzer on every read.

Calculate the Frame and Its Timing

Calculate the Checksum

The checksum is the exclusive OR of the five ID bytes. For CARD 1, the ID 5400A1B2C3 is divided into the bytes 54, 00, A1, B2 and C3:

  1. 54 XOR 00 = 54
  2. 54 XOR A1 = F5
  3. F5 XOR B2 = 47
  4. 47 XOR C3 = 84

The checksum is 0x84, so the reader sends 5400A1B2C384. For CARD 3, the same steps give 1A, 6D, D5 and finally 1C. Note that CARD 2 and CARD 4 have the same checksum of 93, although their IDs are different. A checksum detects most transmission errors, but it does not identify a card.

Compare the Two Output Formats

Output formats of the model
MODE propertyFrame contentsLength
EM1810 ID characters and 2 checksum characters12 bytes
RDM6300Start byte 0x02, 10 ID characters, 2 checksum characters and end byte 0x0314 bytes

Calculate the Bit Time

At 9600 baud, one bit lasts 1 / 9600 = 104.17 microseconds. The sketch uses 104 microseconds, because the delay function accepts whole numbers. Does this small difference matter?

The last sample of a byte is the stop bit, which is taken 9.5 bits after the start. The ideal time is 9.5 × 104.17 = 989.6 microseconds, and the sketch's time is 9.5 × 104 = 988 microseconds. The difference is less than 2 microseconds, which is very small compared with one bit. The timing starts again with every start bit, so the error does not grow from byte to byte. The program's own instructions add a little time as well.

Calculate the Frame Time

Each byte needs 10 bits on the line: one start bit, eight data bits and one stop bit.

  • EM-18 format: 12 bytes × 10 bits = 120 bits, which take 120 / 9600 = 12.5 ms.
  • RDM6300 format: 14 bytes × 10 bits = 140 bits, which take about 14.6 ms.

With the default read delay of 20 ms, the first bit leaves the reader 20 ms after your click. The complete EM-18 frame has arrived about 32.5 ms after the click. The BEEP pulse lasts 100 ms, so it is still low when the frame ends.

Change the Cards and Settings

Edit the Component Properties

Stop the simulation and double-click the reader to open its properties.

Properties of the EM18TEP component
PropertyMeaningDefault
TAG1 to TAG4Tag IDs of the four cards, exactly 10 hexadecimal charactersSee the card table
MODEOutput format, EM18 or RDM6300EM18
BAUDBaud rate of the TX pin9600
READ_DELAYTime from the click to the first bit20 ms
BEEP_MSLength of the low pulse on BEEP100 ms

An invalid tag ID is replaced by the default ID of that card. The NAME, VERSION and Designed by fields identify the library and are read-only.

Experiments to Try

Change one thing at a time and predict the result before you press Run. The results below follow from the sketch and the model's rules.

Suggested experiments and their expected results
ChangeExpected result
Add 1A0077B8C9 to the authorised array and rebuild.CARD 3 is granted.
Set TAG1 to 0123456789.CARD 1 is denied, because its new ID is not in the list.
Set MODE to RDM6300.The panel shows RDM6300 and each frame has 14 bytes.
Set BAUD to 4800 without changing the sketch.The sketch cannot read the frames correctly.
Connect the VCC pin to ground.No tag is sent, and the Simulation Log reports that the card was ignored.
Add an LED to D13 and switch it from the level of A5.The LED follows the BEEP pulse on every read.

If you change the baud rate, change BIT_US in the sketch as well. For 4800 baud, one bit lasts 1 / 4800 = 208 microseconds.

Compile and Load Your Own Arduino Changes

  1. Open Arduino Code/EM18_Demo/EM18_Demo.ino in Arduino IDE.
  2. Select Arduino Uno as the board. No additional library is required.
  3. Compile the sketch and use the Export Compiled Binary command.
  4. Select the new application HEX in the Arduino's Program File property.
  5. Restart the simulation.

The package also contains a rebuild script and the AVR core source archive. Its README explains the compiler folders required for that route. Editing the INO file alone does not change the firmware that Proteus has loaded.

Common Problems and Their Solutions

Troubleshooting the EM-18 Proteus simulation
ProblemWhat to check
EM18TEP is missing from Pick Devices.Check that TEPEM18.LIB is in the active library folder and restart Proteus.
The reader is placed, but its model cannot load.Check TEPEM18.DLL in MODELS and beside the project.
Nothing happens on a card click.Click inside a card row while the simulation runs. Check VCC, GND and the TX wire to A4.
The status line shows LOW.The TX line is not resting high. Check the TX wire and the reader's power.
The terminal prints CHECKSUM ERROR.Check that the BAUD property and the sketch use the same rate, then tap the card again.
The terminal is blank or unreadable.Check the Program File, the 16 MHz clock, D1/TX to RXD and 9600 baud.
Code changes have no effect.Compile a new HEX and select it in the Arduino before restarting.

If a problem remains, return to the unmodified project and change one thing at a time. When you ask for help, mention which card you clicked and include the terminal output.

Practical Review and Model Limitations

This library is useful for learning how a serial RFID reader sends its data and how a program should check it. The frame is short and readable, so every step can be followed on the terminal. According to the package notes, the model's frame timing, both output formats, the checksums and the BEEP pulse were tested on a PC before the project was run in Proteus.

What the Model Supports

  • Serial output in the EM-18 and RDM6300 formats with the correct checksum.
  • An adjustable baud rate, read delay and beep length.
  • Four cards with editable tag IDs, and repeated taps of the same card.
  • Power detection through VCC and GND.

What the Model Does Not Simulate

  • The radio field, the antenna and the reading distance.
  • Two cards near the reader at the same time.
  • The data coding between the card and the reader.
  • The Wiegand output of the real module.
  • The supply current of the module.

There is also a security point for real projects. A tag ID of this kind is not a secret, and cards with a copied ID exist. An ID list is suitable for a demonstration, but a real access system needs stronger protection.

More Proteus Libraries of This Series

This library belongs to a series of wireless and RFID libraries for Proteus. Every library has its own control panel and its own tutorial:

Frequently Asked Questions

Do I Need an Arduino Library for the EM-18?

No. The reader sends plain text through a serial line. The supplied sketch receives and checks it without any external library.

What Is the Difference Between EM-18 and RDM6300?

Both are 125 kHz readers with a serial output. In our model, the difference is the frame. The RDM6300 format adds a start byte and an end byte around the same 12 characters.

How Is the EM-18 Different from the MFRC522?

The EM-18 works at 125 kHz and only reports the card's ID through a serial line. The MFRC522 works at 13.56 MHz, uses SPI and can also read and write the memory of its cards. We have explained it in our MFRC522 RFID Proteus Library tutorial.

Can I Add My Own Tag ID?

Yes. Enter 10 hexadecimal characters in one of the properties TAG1 to TAG4. To grant access to it, add the same ID to the authorised array, rebuild the sketch and load the new HEX.

Can I Connect the Reader to D0 Instead of A4?

Yes, the sketch reads the hardware serial port as well. In the supplied circuit, however, D0 is connected to the Virtual Terminal, so remove that wire first.

Do I Need Arduino IDE to Run the Supplied Circuit?

No. The compiled HEX file is included. You need Arduino IDE, or the documented build tools, only when you change the sketch.

That completes our EM-18 RFID Proteus Library tutorial. Start with the supplied project, tap the four cards and compare each result with the table. Once the readings make sense, change a tag ID or the authorised list and build your own access control project. Share your questions and simulation results in the comments below.


Comments

0

Join the conversation