The RFID Access control system with two factor authentication (2FA) project is a security system project which uses RFID cards and a random 4 digit code to unlock a door and grant access to a user. The process is initiated by first placing an RFID card over the integrated RFID module in the project. The project, through the RFID module, detects this card and reads the UID (Universal Identifier) data of the card. The project then tries to identify this card by comparing its UID with previously stored UIDs in the project microcontroller EEPROM. If a match is found, the alias given to the card when it is stored is read together with an 11 digit mobile phone number stored with the UID data of the card in the microcontroller EEPROM memory. If a match is not found in EEPROM, the user has the option of storing this card UID, an alias and an 11 digit mobile phone number in the EEPROM of the project microcontroller. When a card is detected and identified, the system generates a 4-digit random code and sends it via SMS using an integrated GSM module (SIM800l) to the 11-digit mobile phone number associated with the stored card data. The SMS bearing the code is received on the phone associated with the 11-digit phone number. The user is required to enter the code in the system to complete the process. If the user enters the correct code, the door is unlocked else the door remains locked.
The projects boasts of a simple user interface and is capable of storing 15 RFID card UID together with an alias and a phone number. A security code is required to access the settings menu of the project and also to store card information in EEPROM.
Let’s take a look at how the project works in detail. Since the project is comprised by hardware and software components, we will be looking into both in detail. First let’s analyze the hardware.
The Hardware
The project hardware is made up of the following key components:
- PIC16F876 Microcontroller with 28pin DIL socket
- RC-522 RFID Module with RFID Card and Keychain
- 16X2 LCD Module
- 4X4 keypad
- SIM800L GSM Module
- Buzzer
- Two 4V 150mAH Rechargeable sealed lead acid batteries
- LM7805 (5V Regulator)
- LM317 Adjustable regulator
The image below shows some of the components

RFID access control system project key components
The circuit diagram below shows how these components are interconnected. We will be using the circuit diagram as a guide in explaining the operation of the project hardware.

Circuit diagram of the RFID access control system with two-factor authentication project
From the circuit diagram, the circuit is powered through mains and rechargeable lead acid batteries. When the circuit is plugged into mains, step down transformer TR1 steps down the mains voltage to 12Volts AC. TR1 is a center tapped transformer so full-wave rectification is achieved using two diodes D1 and D2. This rectified voltage is used to power the circuit and also charge the series connected rechargeable batteries through resistor R4. The rechargeable batteries each have a voltage of 4V and a capacity of 150mAH. This gives a series voltage of 8V 150mAH. The value of R4 has been chosen such that the charging current never overcharges the batteries. Diode D3 connected across R4 allows the batteries to power to the circuit when the mains voltage is low or absent (circuit unplugged). The batteries also help supply extra current required by the SIM800L module when sending SMS.
Switch S1 is used to turn the circuit ON and OFF. When Switch S1 is ON, voltage appears across the fixed linear voltage regulator LM7805 and the adjustable linear voltage regulator LM317. The LM7805 outputs a regulated 5V while the LM317 has been configured with resistors R2 an RV2 to produce a regulated output voltage of about 3.4V.
The 3.4V output of the LM317 powers the RC522 RFID module and the SIM800L GSM module; while the 5V output of the LM7805 powers the PIC16F876 microcontroller and the LCD module. The PIC16F876 microcontroller is the heart of this project. It coordinates the operation of each of the modules interfaced with it. Piezoelectric Crystal X1, capacitors C1 and C2 set the PIC16F876 microcontroller operating frequency at a stable 20MHz. This is the frequency of the internal clock of the microcontroller which allows it execute instructions of the software the microcontroller has been programmed with.
Microcontrollers usually have I/O (Input / output) ports. Each port comprises of a certain number of pins through which devices can be connected and controlled by the microcontroller. The PIC16F876 microcontroller has three ports – PORTA, PORTB and PORTC. PORTA has six I/O pins while PORTB and PORTC have eight I/O pins. This gives a total of 22 port pins. Each of these port pins can be configured through software to function as either input or output. It is common for one to run out of port pins needed to completely interface every module or component required in a project to a microcontroller. The solution is always either to go for a microcontroller with even more I/O port pins or to multiplex some port pins. Multiplexing is a method where a port pin can be made to drive multiple devices one at a time. In this project, it wouldn’t have been possible to connect all components on each port of the microcontroller as the number of port pins weren’t enough. Through multiplexing, I was able to drive the LCD module and the 4X4 keypad on PORTB of the microcontroller. This is possible because writing to the LCD and reading the 4X4 keypad is never done at the same time but in sequence. Any time we want to display some information on the LCD, the keypad is disabled. When we want to read input from the keypad, we suspend writing to the LCD.
The 4X4 keypad comprises of 16 switches connected in such a way as to form a 4X4 grid pattern. This can be seen in the image below.

Diagram of 4X4 keypad showing buttons layout and connections
The buttons in the 4X4 keypad are arranged in a row and column arrangement. This reduces the connections to 8. Each of the 16 switches on the keypad can be addressed to determine if it is pressed or not. Using the image above, let’s say we want to check for button press of button ‘1’ on the keypad, we place a logic HIGH on the first row R1. When button ‘1’ is pressed, the button conducts and a logic HIGH appears on column C1. Since buttons 2, 3, and A are all connected to R1, pressing any of these buttons with R1 HIGH sends are HIGH to the corresponding Column line. To check for button press on buttons 4, 5, 6 and B, we remove the logic HIGH earlier placed on R1 and place the logic HIGH on R2 while checking the column lines. At any point in time only one row line is HIGH at a time. The microcontroller keeps track of the row line that is currently HIGH while checking the column lines. This scanning process is done quite fast by the microcontroller that no button press is missed. The software in the microcontroller has been written to enable the microcontroller scan each button on the keypad, detect when it is pressed and process the key press.
The PIC16F876 microcontroller comes with a host of hardware peripheral such as SPI (Serial Peripheral Interface), Timers, USART (Universal Synchronous Asynchronous Receiver and Transmitter) etc. The project makes use of some of these peripherals. The hardware SPI on the microcontroller is used to interface the RC522 RFID module while the USART is used to interface the SIM800L GSM module. These modules are powered from 3.3V while the microcontroller is powered from 5V. It is risky connecting these modules directly to the microcontroller since the voltage levels are different. To solve this problem, a voltage level shift is required. This is achieved using voltage dividers.
Output pins on the microcontroller connecting to input pins of these modules goes through a voltage divider while output pins on the modules connecting to input pins on the microcontroller goes direct. This can be seen in the circuit diagram. The RC522 RFID module SCK and MOSI input pins are connected to the output pins of the microcontroller through voltage divider formed by R6, R3 and R6, R5. This is also true for the SIM800L GSM module RXD pin. The values of the resistors of the voltage dividers are chosen such that the 5V logic HIGH output of the microcontroller is dropped to around 3.4V; within the input voltage range of the modules.
Other components connected to the microcontroller include the buzzer and the L293D motor driver. The buzzer is connected directly to a port pin on the microcontroller configured as output. The microcontroller logic HIGH can output up to 25mA of current which can sufficiently drive the buzzer. Unfortunately 25mA is not sufficient to drive a motor hence a motor driver L293D IC is used to drive the door lock motor. The decision to use a motor was just for demonstration purposes. I got a faulty CD-ROM drive, took out everything in it leaving only the CD tray and drive motor. This was to enable me simulate a door opening and closing. In practice, the CD_ROM drive assembly can be removed and replaced with a solenoid lock.
The Software
The software programmed into the microcontroller breathes life into the project. Through software we are able to coordinate the operation of the modules as well as the operation logic required for the entire access control function of the project.
The PIC16F876 microcontroller software was developed using the Microchip MPLAB IDE. There is support for Assembly language programming for this microcontroller under MPLAB IDE by default but for ANSI C programming language, support is provided through an external plug-in.
Due to the complexity of the project and limited development time; I decided to use ANSI C programming language. For that, the HITECH C ANSI C programming plug-in for PIC 10/12/16 series microcontroller was installed and configured in MPLAB.
At the start of the project software development process, I had to break down the project software into smaller parts and tackled each one at a time. The key parts of the software include:
- Setting up the RC522 RFID module to detect RFID cards and also read the UID of the cards.
- Sending SMS with the SIM800L module.
- Scanning the keypad for button press and assigning the appropriate ASCII character to each button press.
- Writing to the LCD module.
- Structuring and Storing appropriate card data to EEPROM.
Setting up the RC522 RFID Module:
Setting up the RFID module required downloading the datasheet. The operation of the module is explained in detail in the datasheet. It guided me in correctly connecting the module to the microcontroller as well as understanding the various commands of the RFID module and their functions. With this knowledge, I worked through developing the RC522 RFID module software stack. The software stack works well and supports detecting, reading and writing RFID cards. It can be used with any PIC microcontroller that has an integrated hardware SPI module. The PIC hardware SPI is configured with the following parameters:
- 312,500Hz clock frequency (FOSC (20MHz)/64)
- Master mode operation
- Data sampled at middle
- Clock idle low
- Data transmitted at rising edge of clock
At one point during testing, the module failed to function. I went through the software stack severally, tried different things but it still won’t work. I realized that I had neglected connecting the SDA pin to the microcontroller but instead grounded it. The SDA pin must be connected and controlled by the microcontroller as the RC522 RFID module uses this pin to automatically detect the SPI communication interface type used since it supports other communication interfaces such as USART and I2C.
Sending SMS with the SIM800L module
The SIM800L GSM module enables us add GSM functionality to our projects. It has a SIM card interface and supports making and receiving calls, sending and receiving SMS as well as connecting to the internet through GPRS. The module is interfaced to the microcontroller through hardware USART (Universal Synchronous Asynchronous Receiver and Transmitter). The PIC16F876 microcontroller has an integrated hardware USART. This USART is configured for asynchronous 8-bit serial communication, no parity and a BAUD rate of 9600. A SIM card and a suitable antenna must be connected to the module to enable operation. The module can draw up to 2 Amperes of current when communicating with the GSM network; thus the power supply must be able to meet this requirement. The rechargeable batteries used in the project buffer the power supply to meet this requirement.
A red LED on the module is used to indicate the network connection status of the module. When not connected to a GSM network, the LED flashes at a fast rate. When connected to a network, the LED flashes at a slower rate.
The module is used in the project to send SMS. The SMS message is of the format: OTP:XXXX. Where XXXX is a randomly generated 4 digit code required to deactivate the lock and grant access to a user after his RFID card has been detected.
Communication with the module is through ‘AT’ commands. AT commands are a set of commands used to programmatically control a telephony device through a terminal or serial port.
To send an SMS message ‘OTP:4512’ to destination phone number “08035631219” with the module, the following sequence of commands is sent to the module by the microcontroller through the USART interface:
- Send string “AT” (enables SIM800L to auto detect our baud rate)
- Send 0x0D (hex code for ENTER)
- Delay 500ms (wait for 500ms for module to process commands)
- Send string “AT0” (AT command to disable command echoing)
- Send 0x0D (hex code for ENTER)
- Delay 500ms (wait for 500ms for module to process commands)
- Send string “AT+CMGF=1” (AT command to enable SMS sending in TEXT mode)
- Send 0x0D (hex code for ENTER)
- Delay 500ms (wait for 500ms for module to process commands)
- Send string “AT+CMGS= “08035631219”” (AT command to for SMS destination phone number)
- Send 0x0D (hex code for ENTER)
- Delay 500ms (wait for 500ms for module to process commands)
- Send message string “OTP:4512”
- Send 0x1A (hex code for CTRL+Z. Terminates message input)
- Send 0x0D (hex code for ENTER)
- Delay 500ms (wait for 500ms for module to process commands)
The implementation of the communication between the microcontroller and the SIM800L is one way. This means that whatever response the SIM800L returns, it is ignored. As a result, for any command sent to the SIM800L we wait for 500ms for the SIM800L to process the command. Assuming a two way communication between the microcontroller and the SIM800L is implemented there will be no need for the 500ms delay, thus speeding up the process. Since the SIM800L always returns a string “OK” after processing a command successfully, we can read the response from the SIM800L and proceed with the next command after receiving an “OK” response. Nevertheless, the method used in the project works quite well.
Scanning the Keypad
The 4X4 keypad provides a means of getting user input. The microcontroller PORTB I/O port is an 8-bit port and is used to interface the keypad. This port is also used to connect the data bus of the LCD module to the microcontroller. Because the keypad and the LCD module share a single port, they are said to be multiplexed. This saves port pin usage. The limitation to multiplexing is that the keypad and the LCD can only be accessed one at a time and not at the same time since this will corrupt the data on the port lines.
As already explained, the buttons on a 4X4 keypad are arranged in a row / column pattern. The four rows are connected to the lower nibble of PORTB while the columns are connected to the upper nibble. The lower nibble of PORTB is configured as outputs while the lower nibble is configured as inputs.
The microcontroller, starting with the first row, asserts a HIGH on each row one at a time while reading the columns data for button press. After the last row is asserted, the cycle repeats. Each button on the keypad is assigned a key code. The key code is from 1 to 16. A function keyToAscii() is called on each button press to convert the key code of the button pressed to an ASCII character. This is to enable display of the character on the LCD module and also for storing user phone numbers to be used in sending OTP codes. The keypad scanning code is put in an interrupt service routine which runs every 10ms. Thus, all buttons of the keypad are checked every 10ms.
Debouncing is handled in software. Switch bounce is a term used to describe the oscillation that occurs when a mechanical switch is enabled. The contacts of the switch, when enabled, bounce for a short time before settling. Without debouncing, switch bounce can appear to the microcontroller as multiple button presses. In the software, debouncing is handled by introducing a delay on detection of a state change on the column line of the microcontroller. During this delay, the keypad scanning is suspended. Once the delay has elapsed, the microcontroller continues scanning the keypad.
Writing to the LCD Module
The LCD module is used to provide a visual output in the project. The LCD module used is a 16 Character by 2 lines LCD. The LCD module is configured to work in 4-bit mode. The 4-bit data bus of the LCD is connected to the lower nibble of PORTB while the two control pins of the LCD are connected to PORTA. The software required to operate (read / write) the LCD was developed using information on the LCD datasheet as a guide.
Due to multiplexing between the LCD and Keypad on PORTB, accessing the LCD disables the keypad. As a result, all LCD operations had to be done as fast as possible in order to free the keypad. Once the LCD is update with information to be displayed, no further writing to the LCD is performed except new information is available to be displayed on the LCD. This way, the keypad remains responsive.
Storing card data to EEPROM
The project relies on stored card data in EEPROM to identify valid cards and send OTP SMS messages to phone numbers associated with the card. A card is valid if the UID data has been stored previously in the microcontroller EEPROM. Bringing such card close to the RFID module triggers the system to read the card UID and compare it with data in the EEPROM. If the card UID was found in EEPROM, the text “VERIFIED CARD” is shown on the LCD, followed by the name / alias given to the card. If the card UID is not found in the EEPROM, the text “INVALID CARD” is displayed on the LCD. The user can decide to store this card for future validation. Pressing the [F3] button on the keypad initiates the card storing sequence. First, a pass key is requested by the system (Default passkey is 12345). Once a passkey is entered, pressing [F4] validates the passkey and the system proceeds to request for a name or alias for the card. The user must enter a three digit number; this number is appended to a word “ID”. Thus card names are of the format IDXXX where XXX is the number entered by the user as the card name / alias. On pressing [F4], the system proceeds to request for the destination phone number where OTP message code will be sent. Entering an 11 digit phone number and pressing the [F4] button completes the card storing process. The card data is now available in EEPROM. On bringing the card to the RFID module, the system will always validate the card.
To effectively store the card data to allow for quick binary search, the data must be structured appropriately. Each card data requires 17 bytes of EEPROM space. The data structure is as follows:

RFID access control system with two-factor authentication project card data structure
- 1 byte = Card data block start delimiter 0xF0: Denotes the beginning of a valid card data block
- 5 bytes = holds card UID
- 5 bytes = holds card name / alias example “ID123”
- 6 bytes = holds 11 digit Phone number to send card OTP example “08035631219” + “0”. Each byte holds 2 digits. Last digit of stored phone number is always zero.
The PIC16F876 microcontroller has a 256 byte EEPROM. This allows for storage of a maximum of 15 cards data. The EEPROM memory addresses range for each card data block is as follows:
- 1st data block 0x00 – 0x10
- 2nd data block 0x11 – 0x21
- 3rd data block 0x22 – 0x32
- 15th data block 0xEE – 0xFF
At the beginning of each data block is the start delimiter. The start delimiter is used to identify a valid card data block. The system begins writing a new card data by writing 0xF3 (Hex), followed by 5 bytes of the card UID, 5 bytes for the card name / alias and finally six bytes for the phone number. The phone number is broken up and stored in nibbles. Each digit takes 4 bits to store.
With this arrangement, it becomes easy to search the EEPROM and retrieve card data. Deleting card data becomes easy too. We just change the delimiter to some other value that isn’t 0XF0. The data block available for storing a new card data.
Software operation flow
Let’s take a look at the complete picture on the operation of the project software. We will be using a flow diagram to explain the operation flow.

RFID access control system with two-factor authentication project flow diagram
When the project is powered on, the microcontroller starts executing the instructions of the software in its flash memory. First it initializes the SPI hardware module, USART hardware module, RFID module, sets up timer interrupt to run at 10ms interval, puts the door lock in a locked state, and then enters a standby mode.
In standby mode, the RFID module is in auto detect mode and the key pad is continually scanned for [F1] button press.
Pressing the [F1] button calls up the settings menu. User must enter a valid pass key to enter the settings menu. The default passkey is “12345”. Once entered, the user can access the settings menu. The settings menu has the following options:
- Manage Cards
- Manual Override
- Exit
Use the [F2] and [F3] buttons to scroll through the menu. Select a menu item by pressing [F4]. Selecting the “Manage Cards” menu item will display the “Delete Card” menu. The delete card menu allows the user browse through the stored card data on EEPROM. Use [F2] and [F3] buttons to scroll through the cards data. Pressing [F4] on the currently displayed card data will prompt a message asking if the card should be deleted. Pressing [F4] will delete the card; pressing [F1] dismisses the prompt.
The Manual Override menu option allows the user to manually open the door lock.
Selecting the “EXIT” menu item takes the system back to standby mode. The system must be in standby mode for RFID cards to be detected. When in standby mode and an RFID card is brought close to the RFID module, the RFID card is detected instantly and the UID of the card read. The UID is searched in the EEPROM. If found the system displays the message “VERIFIED CARD” as well as the name / alias of the card. Pressing [F1] returns the system back to standby mode. Pressing [F4] at this point will cause the system to generate and 4-digit OTP and send via SMS to the assigned phone number stored with the card. The screen displays the message “ENTER OTP:”. The user is required to enter the exact OTP sent through SMS. Entering a valid OTP unlocks the lock. When an invalid OTP is entered, the system displays the message “WRONG OTP” followed by the “ENTER OTP” message. Pressing [F1] returns the system back to standby mode.
If an RFID card not stored is brought close to the RFID module, the system displays the message “INVALID CARD”. Pressing [F1] takes the system back to standby mode. Pressing [F3] allows the user to save this card. Once [F3] is pressed, the system requests for a passkey. Entering “12345” and pressing [F4] proceeds to the next step. First the user enters a name for the card and presses [F4]. A phone number is requested. User enters an 11 digit phone number. Pressing [F4] saves the card UID together with the name and phone number provided. Subsequently, when this card is brought close to the RFID module, it will be detected as a verified card.