Control a Servo Motor Using Arduino Uno R4 WiFi and RC522 RFID Module

In this blog, you are going to learn how to control a servo motor’s angle with the Arduino Uno R4 WiFi using the RC522 RFID module.

I will walk you through all the necessary components used in this project and show you how to connect them to the Arduino Uno R4 WiFi microcontroller.

Before we get started, make sure you have the Arduino IDE installed on your computer, and ensure that the Arduino Uno R4 Boards package is installed in the Boards Manager.

Components Used:

  • Arduino Uno R4 WiFi
  • RC522 RFID Module
  • Passive Buzzer
  • SG90 Servo Motor

Components used

RFID RC522 Module

The RFID RC522 is a popular module built around the MFRC522 controller. It operates at a frequency of 13.56 MHz, which is the radio frequency used to communicate with RFID cards and tags.

 In simple terms, the module sends and receives electromagnetic signals at 13.56 million cycles per second, allowing it to detect and read RFID cards efficiently.

RC522 Pin Configuration

The module has 8 pins, but for simple projects you may not need to use all of them. Here’s the typical pinout:

  • SDA / SS – Slave Select for SPI
  • SCK – Clock
  • MOSI – Master Out, Slave In
  • MISO – Master In, Slave Out
  • IRQ – Interrupt (optional)
  • GND – Ground
  • RST – Reset
  • 3.3V – Power Supply

For most Arduino projects, you only need to use SDA, SCK, MOSI, MISO, RST, GND, and 3.3V.If you want to learn more about using the RC522 RFID module, check out the detailed tutorial below:

Interface Arduino Uno R4 WIFI with RFID RC522 Module

SG90 Servo Motor Pinout

The servo motor used in this project is the SG90, a small and commonly used micro servo. It has three pins:

  • Signal/Data (yellow)
  • VCC (red)
  • GND (brown)

The servo motor should be powered from the 5V pin of the Arduino Uno R4 WiFi, and its signal pin must be connected to a digital pin on the Arduino that is capable of generating PWM signals.

Circuit Diagram

Arduino Code

For this project, we need to install two libraries: MFRC522.h and Servo.h.

#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>

Servo myservo;

#define SS_PIN 10
#define RST_PIN 9


#define Alarm 7
#define SERVO_PIN 5

MFRC522 mfrc522(SS_PIN, RST_PIN);

void setup() {
  myservo.attach(SERVO_PIN);

  Serial.begin(9600);

  SPI.begin();
  mfrc522.PCD_Init();


  pinMode(Alarm, OUTPUT);
}

void loop() {
  // RFID section
  if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
    return; // No new card, exit RFID part
  }

  // Read UID
  Serial.print("UID tag: ");
  String content = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);

    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  Serial.println();

  content.toUpperCase();

  // Authorized card
  if (content.substring(1) == "0B 23 9B 15") {
    Serial.println("Access Granted - Correct Card");

    myservo.write(0);
    delay(2000);
    myservo.write(180);
  }

  // Unauthorized card
  else if (content.substring(1) == "52 EF E9 1C") {
    Serial.println("Access Denied - Wrong Card");
    digitalWrite(Alarm, HIGH);
    delay(2500);
    digitalWrite(Alarm, LOW);

    myservo.write(180);

  }

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

Line-by-line explanation

Includes the SPI library which handles the Serial Peripheral Interface bus — required because the RC522 RFID module communicates with the Arduino over SPI.

#include <SPI.h>

Includes the MFRC522 library which provides functions to control the RC522 RFID reader (detect cards, read UID, etc.).

#include <MFRC522.h>

Includes the Servo library so you can control hobby servos (set angles, attach to pins, etc.).

#include <Servo.h>

Creates a Servo object named myservo. You use this object to attach the servo to a pin and command angles (e.g., myservo.write(90)).

Servo myservo;

Defines two constants: SS_PIN (slave/select pin for SPI to the RC522) and RST_PIN (reset pin for the RC522). Using #define gives them readable names used later in the code.

#define SS_PIN 10
#define RST_PIN 9

Defines the Arduino pins used in the project:

  • Alarm is the digital pin driving the passive buzzer.
  • SERVO_PIN is the digital pin that carries the servo signal (PWM).
#define Alarm 7
#define SERVO_PIN 5

Creates an MFRC522 object called mfrc522 and tells it which pins are used for SPI Slave Select and Reset. This initializes the library instance for your specific wiring.

MFRC522 mfrc522(SS_PIN, RST_PIN);

setup() runs once at startup. myservo.attach(SERVO_PIN); connects the myservo object to the servo signal pin so you can control its position.

void setup() {
  myservo.attach(SERVO_PIN);

Starts serial communication at 9600 baud so the Arduino can print messages to the Serial Monitor for debugging (UIDs, access granted/denied messages, etc.).

  Serial.begin(9600);

SPI.begin(); initializes the SPI hardware on the Arduino.

mfrc522.PCD_Init(); initializes the RC522 module (PCD = Proximity Coupling Device). This wakes up the reader and prepares it for card detection and communication.

  SPI.begin();
  mfrc522.PCD_Init();

Sets the buzzer pin as an OUTPUT so you can turn the alarm on/off with digitalWrite(). End of setup().

  pinMode(Alarm, OUTPUT);
}

Start of loop() which repeats forever:

  • mfrc522.PICC_IsNewCardPresent() checks if a new card/tag is near the reader.
  • mfrc522.PICC_ReadCardSerial() attempts to read the card’s serial (UID).
  • If either function returns false (no card or failed read), the if triggers and return; exits the loop() function early — effectively skipping the rest of the code until the next iteration (next scan).
void loop() {
  // RFID section
  if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
    return; // No new card, exit RFID part
  }

Prints a label to Serial: "UID tag: ".

Declares an empty String variable content which will be used to build a textual representation of the UID bytes.

  // Read UID
  Serial.print("UID tag: ");
  String content = "";

This loop iterates over each byte of the UID and does two things per byte:

  1. Serial printing:
    • If the byte is less than 0x10 (a single hex digit), it prints a leading space and 0 to make two hex digits (" 0"), otherwise it prints just a space.
    • Then prints the byte in HEX format (e.g., 0B).
      This produces a human-readable UID like: 0B 23 9B 15.
  2. Build content string:
    • The same two parts are appended to the content String, so the full UID text becomes stored in content.

Using concat() and the conditional ensures each byte appears as two hex characters with a leading space for formatting.

  for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);

content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}

Prints two newline lines to Serial for spacing — makes the output easier to read.

  Serial.println();
  Serial.println();

Converts content to uppercase letters. (So 0b becomes 0B.) This makes UID comparisons case-insensitive and consistent.

  content.toUpperCase();

content.substring(1) takes the content string starting from index 1. This is used because content starts with a leading space produced earlier; substring(1) removes that first leading space and produces 0B 23 9B 15.

If the UID matches "0B 23 9B 15", the sketch recognizes the card as authorized:

  • Prints "Access Granted - Correct Card" to Serial.
  • myservo.write(0); moves the servo to 0° (e.g., open the lock).
  • delay(2000); waits 2 seconds with the servo at 0°.
  • myservo.write(180); returns the servo to 180° (e.g., close/lock again).
  // Authorized card
  if (content.substring(1) == "0B 23 9B 15") {
    Serial.println("Access Granted - Correct Card");

    myservo.write(0);
    delay(2000);
    myservo.write(180);
  }

Else-if checks a different UID for a specific unauthorized card:

  • Prints "Access Denied - Wrong Card".
  • digitalWrite(Alarm, HIGH); turns the buzzer on.
  • delay(2500); keeps the buzzer on for 2.5 seconds.
  • digitalWrite(Alarm, LOW); turns the buzzer off.
  • myservo.write(180); ensures the servo stays at 180° (locked).
  // Unauthorized card
  else if (content.substring(1) == "52 EF E9 1C") {
    Serial.println("Access Denied - Wrong Card");
    digitalWrite(Alarm, HIGH);
    delay(2500);
    digitalWrite(Alarm, LOW);

    myservo.write(180);
  }

mfrc522.PICC_HaltA(); tells the PICC (the card) to halt. This puts the card into an idle state so the reader can move on to the next card cleanly.

mfrc522.PCD_StopCrypto1(); stops the cryptographic communication that the library might have started with certain card types — it’s a cleanup step recommended by the MFRC522 library to finish the transaction.

End of loop() — code returns to the top and repeats.

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

How the Project Works

Once everything is connected, the Arduino continuously checks if a new RFID card is detected. When a card is scanned:

  • The Arduino reads the UID (Unique Identifier) of the card.
  • It compares the UID to predefined values stored in the code.
  • If the UID matches the authorized card, the servo rotates to , waits 2 seconds, then returns to 180°.
  • If an unauthorized card is scanned, the buzzer (alarm) turns on for 2.5 seconds and the servo remains locked.
  • The RFID module is then reset and ready for the next scan.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *