Practical case: Arduino UNO RFID Clock-In to SD Card

Practical case: Arduino UNO RFID Clock-In to SD Card — hero

Objective and use case

What you’ll build: A standalone hardware prototype that reads passive RFID tags, retrieves the current time from a precision real-time clock (RTC), and logs the event (UID and timestamp) to a CSV file on a microSD card.

Why it matters / Use cases

  • Student Attendance Tracking: Automates classroom check-ins via ID card taps, eliminating manual roll calls.
  • Lab Equipment Access Logging: Provides an offline audit trail of exactly who used a specific piece of machinery and at what time.
  • Employee Time Clock: Acts as a basic punch-in/punch-out system for small workshops where network connectivity is unavailable.
  • Security Auditing: Demonstrates the foundational principles of physical access control systems by logging entry attempts at a door or gate.

Expected outcome

  • Successful initialization of shared SPI bus components (microSD and RFID) and I2C components (RTC).
  • Serial monitor output displaying detected card UIDs and timestamps in real-time (< 100ms read latency).
  • Creation of an ATTEND.CSV file on the microSD card containing properly formatted, comma-separated log entries.

Audience: Embedded systems developers and makers; Level: Intermediate

Architecture/flow: RFID Tag Tap → SPI RFID Reader → Microcontroller → I2C RTC Timestamp Fetch → SPI microSD CSV Append

Educational validation note

Before publication, this case passed the Prometeo automated validation gate with status PASS. The validator checked the code blocks, article structure, copy/paste-safe commands and consistency with the supported device catalog.

Published validation evidence

  • Automatic result: PASS.
  • Parsed structure: 3 sections, 5 tables and 2 code blocks detected before publication.
  • Checked code: 2 Arduino/arduino-cli compile.
  • Supported catalog: the article text was checked against Prometeo’s validation-capable device profiles, and unsupported stacks block publication.
  • Report findings: no blocking findings.

This validation confirms syntax and tool compatibility for the published material, but it does not replace physical testing on your exact hardware, wiring and runtime environment.

Educational safety note

This project builds an educational prototype intended for learning hardware integration, SPI bus sharing, and data logging. It is not a secure access control system. The MIFARE Classic tags commonly used with the MFRC522 have well-documented cryptographic vulnerabilities and

Conceptual block diagram

High-level view: what enters the system, what each block processes, and what comes out.

Functional architecture

RFID Tag Tap

SPI RFID Reader

Microcontroller

I2C RTC Timestamp Fetch

SPI microSD CSV Append

Conceptual signal and responsibility flow between device blocks.

Validation path

Sketch

arduino-cli compile

Upload

Functional test

Conceptual summary of the tools used to check the published material.

Prerequisites

To successfully complete this tutorial, you need:
* Basic understanding of C++ programming and Arduino sketch structure (setup() and loop()).
* Familiarity with serial communication and reading serial monitor outputs.
* A computer with the arduino-cli (Arduino Command Line Interface) installed and added to your system path.
* A microSD card (32GB or smaller) formatted to FAT32.
* A USB Type-A to Type-B cable for programming and powering the Arduino UNO.

Materials

  • Arduino UNO R3 (ATmega328P) + MFRC522 RFID module + microSD SPI module + DS3231 RTC (Exact target hardware).
  • Passive RFID Tags or Cards (13.56 MHz, compatible with MFRC522, typically MIFARE Classic).
  • Breadboard and premium male-to-male and male-to-female jumper wires.
  • MicroSD card (formatted to FAT32).

Setup/Connection

This project requires careful wiring because two different modules (the MFRC522 and the microSD module) must share the Arduino’s single hardware SPI bus. The SPI bus uses shared lines for data (MOSI, MISO) and clock (SCK), but requires unique Chip Select (CS) pins for each device. The DS3231 RTC uses the I2C bus, which operates on separate pins.

Power Distribution Warning

  • MFRC522: Must be powered by 3.3V. Applying 5V to the VCC pin of the MFRC522 will damage it.
  • MicroSD Module: Most standard Arduino microSD modules have an onboard voltage regulator and level shifter. These should be powered by 5V.
  • DS3231: Can safely operate at 5V.

Wiring Tables

1. MFRC522 RFID Module (SPI Bus 1 – 3.3V Logic)

MFRC522 PinArduino UNO R3 PinFunction / Note
3.3V3.3VCRITICAL: Do not connect to 5V
RSTPin 9Reset control
GNDGNDCommon Ground
IRQUnconnectedNot used in this polling implementation
MISOPin 12Master In Slave Out (Shared SPI)
MOSIPin 11Master Out Slave In (Shared SPI)
SCKPin 13Serial Clock (Shared SPI)
SDA (CS)Pin 10Chip Select for RFID

2. MicroSD Card Module (SPI Bus 2 – 5V Logic)

MicroSD PinArduino UNO R3 PinFunction / Note
VCC5VPower for onboard regulator
GNDGNDCommon Ground
MISOPin 12Master In Slave Out (Shared SPI)
MOSIPin 11Master Out Slave In (Shared SPI)
SCKPin 13Serial Clock (Shared SPI)
CSPin 4Chip Select for SD Card

3. DS3231 RTC Module (I2C Bus)

DS3231 PinArduino UNO R3 PinFunction / Note
VCC5VPower
GNDGNDCommon Ground
SDAPin A4I2C Data
SCLPin A5I2C Clock

Validated Code

The project uses two separate code files. The first is a utility sketch to set the current date and time on your DS3231 RTC. The second is the main attendance logger application.

Utility Sketch: set_rtc_time.ino

Run this sketch once to program the RTC with your computer’s current compile time.

/*
 * Utility: Set DS3231 RTC Time
 * This sketch sets the RTC to the date & time the sketch was compiled.
 */

#include <Wire.h>
#include <RTClib.h>

RTC_DS3231 rtc;

void setup() {
  Serial.begin(9600);
  while (!Serial) { delay(10); } // Wait for serial console

  Serial.println("Initializing RTC...");

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC. Check wiring.");
    while (1) { delay(10); } // Halt
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, let's set the time!");
  }

  // Set the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  Serial.println("RTC time has been successfully updated!");
  Serial.print("Current time set to: ");

  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.println(now.second(), DEC);

  Serial.println("You can now flash the main attendance logger sketch.");
}

void loop() {
  // Nothing to do here
}

Main Application: attendance_logger.ino

This is the primary firmware for the prototype. It initializes the shared SPI bus, manages the Chip Select pins, polls for RFID cards, and appends records to the SD card.

Public preview of the validated file. The complete source is shown to members and in PDF/Print.

/*
 * Project: RFID Attendance SD Logger
 * Target: Arduino UNO R3 + MFRC522 + MicroSD + DS3231
 * Description: Reads RFID tag UIDs, fetches timestamp from RTC, 
 *              and logs the data to ATTEND.CSV on the SD card.
 */

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

// --- Pin Definitions ---
#define SD_CS_PIN    4
#define RFID_CS_PIN  10
#define RFID_RST_PIN 9

// --- Object Instantiation ---
MFRC522 mfrc522(RFID_CS_PIN, RFID_RST_PIN);
RTC_DS3231 rtc;

// --- Global Variables ---
const char* logFileName = "ATTEND.CSV";

void setup() {
  // Initialize serial communications
  Serial.begin(9600);
  while (!Serial) { delay(10); } // Wait for serial port to connect

  Serial.println(F("--- RFID Attendance Logger Initialization ---"));

  // 1. Initialize SPI Bus
  SPI.begin();

  // 2. Initialize DS3231 RTC (I2C)
  if (!rtc.begin()) {
    Serial.println(F("ERROR: Couldn't find RTC."));
    while (1) { delay(10); }
  }
  if (rtc.lostPower()) {
    Serial.println(F("WARNING: RTC lost power. Time may be inaccurate."));
  } else {
    Serial.println(F("RTC initialized successfully."));
  }

  // 3. Initialize MicroSD Card (SPI)
  // Disable RFID SPI temporarily to ensure clean SD init
  pinMode(RFID_CS_PIN, OUTPUT);
  digitalWrite(RFID_CS_PIN, HIGH); 

  Serial.print(F("Initializing SD card..."));
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println(F("ERROR: SD card initialization failed!"));
    Serial.println(F("Check formatting (FAT32), wiring, and CS pin."));
    while (1) { delay(10); } // Halt if SD fails
  }
  Serial.println(F("SD card initialized."));

  // Write CSV Header if file doesn't exist
  if (!SD.exists(logFileName)) {
    File dataFile = SD.open(logFileName, FILE_WRITE);
    if (dataFile) {
      dataFile.println(F("Timestamp,UID"));
      dataFile.close();
      Serial.println(F("Created new ATTEND.CSV with headers."));
    } else {
      Serial.println(F("ERROR: Could not create file on SD card."));
    }
// ...

🔒 This content is premium. With the monthly subscription (7-day free trial) you can unlock the full didactic material and the print-ready PDF pack.🔓 Unlock it — 7-day free trial
/*
 * Project: RFID Attendance SD Logger
 * Target: Arduino UNO R3 + MFRC522 + MicroSD + DS3231
 * Description: Reads RFID tag UIDs, fetches timestamp from RTC, 
 *              and logs the data to ATTEND.CSV on the SD card.
 */

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

// --- Pin Definitions ---
#define SD_CS_PIN    4
#define RFID_CS_PIN  10
#define RFID_RST_PIN 9

// --- Object Instantiation ---
MFRC522 mfrc522(RFID_CS_PIN, RFID_RST_PIN);
RTC_DS3231 rtc;

// --- Global Variables ---
const char* logFileName = "ATTEND.CSV";

void setup() {
  // Initialize serial communications
  Serial.begin(9600);
  while (!Serial) { delay(10); } // Wait for serial port to connect

  Serial.println(F("--- RFID Attendance Logger Initialization ---"));

  // 1. Initialize SPI Bus
  SPI.begin();

  // 2. Initialize DS3231 RTC (I2C)
  if (!rtc.begin()) {
    Serial.println(F("ERROR: Couldn't find RTC."));
    while (1) { delay(10); }
  }
  if (rtc.lostPower()) {
    Serial.println(F("WARNING: RTC lost power. Time may be inaccurate."));
  } else {
    Serial.println(F("RTC initialized successfully."));
  }

  // 3. Initialize MicroSD Card (SPI)
  // Disable RFID SPI temporarily to ensure clean SD init
  pinMode(RFID_CS_PIN, OUTPUT);
  digitalWrite(RFID_CS_PIN, HIGH); 

  Serial.print(F("Initializing SD card..."));
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println(F("ERROR: SD card initialization failed!"));
    Serial.println(F("Check formatting (FAT32), wiring, and CS pin."));
    while (1) { delay(10); } // Halt if SD fails
  }
  Serial.println(F("SD card initialized."));

  // Write CSV Header if file doesn't exist
  if (!SD.exists(logFileName)) {
    File dataFile = SD.open(logFileName, FILE_WRITE);
    if (dataFile) {
      dataFile.println(F("Timestamp,UID"));
      dataFile.close();
      Serial.println(F("Created new ATTEND.CSV with headers."));
    } else {
      Serial.println(F("ERROR: Could not create file on SD card."));
    }
  }

  // 4. Initialize MFRC522 RFID (SPI)
  mfrc522.PCD_Init();
  // Optional: Increase antenna gain if tags are hard to read
  // mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
  Serial.println(F("MFRC522 initialized successfully."));

  Serial.println(F("--- System Ready. Waiting for RFID tags ---"));
}

void loop() {
  // Look for new RFID cards
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  // Get Current Time from RTC
  DateTime now = rtc.now();

  // Format Timestamp: YYYY-MM-DD HH:MM:SS
  char timeBuffer[20];
  snprintf(timeBuffer, sizeof(timeBuffer), "%04d-%02d-%02d %02d:%02d:%02d",
           now.year(), now.month(), now.day(),
           now.hour(), now.minute(), now.second());

  // Format UID to Hex String
  String uidString = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    if (mfrc522.uid.uidByte[i] < 0x10) {
      uidString += "0";
    }
    uidString += String(mfrc522.uid.uidByte[i], HEX);
  }
  uidString.toUpperCase();

  // Print to Serial Monitor
  Serial.print(F("Scanned: "));
  Serial.print(timeBuffer);
  Serial.print(F(" | UID: "));
  Serial.println(uidString);

  // Log to SD Card
  File dataFile = SD.open(logFileName, FILE_WRITE);
  if (dataFile) {
    dataFile.print(timeBuffer);
    dataFile.print(F(","));
    dataFile.println(uidString);
    dataFile.close();
    Serial.println(F(" -> Logged to SD card successfully."));
  } else {
    Serial.println(F(" -> ERROR: Failed to open ATTEND.CSV for writing."));
  }

  // Halt PICC to prevent reading the same card repeatedly in a single tap
  mfrc522.PICC_HaltA();
  // Stop encryption on PCD
  mfrc522.PCD_StopCrypto1();

  // Brief delay to prevent rapid-fire multiple reads
  delay(1000); 
}

Build/Flash/Run commands

Use the arduino-cli to compile and upload your code.

Command Reference Table

TaskCommand
Update core indexarduino-cli core update-index
Install AVR corearduino-cli core install arduino:avr
Install dependenciesarduino-cli lib install "MFRC522" "RTClib" "SD"
Compile sketcharduino-cli compile --fqbn arduino:avr:uno <Sketch_Folder>
Upload to UNOarduino-cli upload --fqbn arduino:avr:uno --port <PORT> <Sketch_Folder>
Serial Monitorarduino-cli monitor --port <PORT> --config baudrate=9600

Numbered Workflow

  1. Find your port: Connect the Arduino UNO to your computer. Run arduino-cli board list to identify the <PORT> (e.g., COM3 on Windows, /dev/ttyACM0 on Linux).
  2. Install Libraries: Ensure the required third-party libraries are installed:
    arduino-cli lib install "MFRC522" "RTClib" "SD"
  3. Set the RTC Time:
    • Save the first code block in a folder named set_rtc_time.
    • Compile: arduino-cli compile --fqbn arduino:avr:uno set_rtc_time
    • Upload: arduino-cli upload --fqbn arduino:avr:uno --port <PORT> set_rtc_time
    • Monitor: arduino-cli monitor --port <PORT> --config baudrate=9600 to verify the time was set.
  4. Flash the Main Logger:
    • Save the second code block in a folder named attendance_logger.
    • Compile: arduino-cli compile --fqbn arduino:avr:uno attendance_logger
    • Upload: arduino-cli upload --fqbn arduino:avr:uno --port <PORT> attendance_logger
    • Monitor: arduino-cli monitor --port <PORT> --config baudrate=9600 to view the live system.

Step‑by‑step Validation

Use these checkpoints while monitoring the serial output to ensure your prototype is fully functional.

  1. Checkpoint: RTC Initialization
    • Action: Reset the Arduino and watch the serial monitor.
    • Expected observation: The monitor prints “RTC initialized successfully.”
    • Pass condition: The system does not halt with “ERROR: Couldn’t find RTC.”
  2. Checkpoint: SD Card Mounting
    • Action: Continue watching the serial monitor during boot.
    • Expected observation: The monitor prints “Initializing SD card…” followed by “SD card initialized.”
    • Pass condition: The system successfully mounts the FAT32 filesystem and does not halt.
  3. Checkpoint: RFID Module Initialization
    • Action: Observe the final boot messages.
    • Expected observation: The monitor prints “MFRC522 initialized successfully.” and “— System Ready. Waiting for RFID tags —“.
    • Pass condition: Both SPI devices (SD and RFID) have initialized without causing bus conflicts.
  4. Checkpoint: Tag Scanning and Logging
    • Action: Tap a 13.56 MHz RFID tag against the MFRC522 antenna.
    • Expected observation: The serial monitor outputs “Scanned: [Date/Time] | UID: [Hex String]” followed by ” -> Logged to SD card successfully.”
    • Pass condition: The UID matches your card, the timestamp is accurate, and the SD write reports success.
  5. Checkpoint: CSV Data Verification
    • Action: Power down the Arduino, remove the microSD card, and read it on your computer.
    • Expected observation: A file named ATTEND.CSV exists. Opening it reveals a header row (Timestamp,UID) and a row for each card tap.
    • Pass condition: The data is properly comma-separated and human-readable in a spreadsheet application.

Troubleshooting

SymptomLikely causeFix
Couldn't find RTCI2C wiring issue.Verify SDA is on A4 and SCL is on A5. Ensure the module has 5V and GND.
SD card initialization failed!Incorrect formatting or CS pin.Ensure the SD card is formatted to FAT32 (not exFAT or NTFS). Verify CS is connected to Pin 4.
SD fails only when RFID is connectedSPI MISO conflict (Cheap SD modules).Some SD modules do not release the MISO line when their CS is HIGH. Try powering the SD module from a separate 5V source or add a tri-state buffer to the SD MISO line.
RFID does not detect cardsPower supply or SPI wiring.Ensure MFRC522 VCC is 3.3V, NOT 5V. Verify MOSI (11), MISO (12), SCK (13), SDA (10), and RST (9).
Timestamp is resetting to 2000-01-01RTC battery depleted.Replace the CR2032 battery on the DS3231 module and re-run the set_rtc_time sketch.

Improvements

Once the basic logger is working, consider these thematic enhancements for a more robust prototype:

  • User Feedback Mechanisms:
    • Add a piezoelectric buzzer to provide an audible “beep” upon a successful scan and log.
    • Integrate a dual-color LED (Green for successful log, Red for SD card error) so the device can be used without a serial monitor attached.
  • Data Management & Integrity:
    • Implement a daily file rotation system (e.g., LOG_1024.CSV for October 24) to prevent a single CSV file from becoming too large to parse quickly.
    • Add a known-UID database in the Arduino’s flash memory (using PROGMEM) to reject unknown cards and only log authorized users.
  • Power and Deployment:
    • Add a sleep mode routine to power down the SPI peripherals and put the ATmega328P to sleep when no card is present, waking via a hardware interrupt (if using a different RFID module that supports IRQ wake).

Find this product and/or books on this topic on Amazon

Go to Amazon

As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.

Quick Quiz

Question 1: What is the main objective of the hardware prototype described in the article?




Question 2: Which component provides the current time for the log events?




Question 3: What communication protocol is shared by the microSD and RFID components?




Question 4: What communication protocol is used for the real-time clock (RTC)?




Question 5: What is the name of the file created on the microSD card to store the log entries?




Question 6: What is the expected read latency for displaying detected card UIDs and timestamps?




Question 7: Which of the following is listed as a use case for this prototype?




Question 8: What specific data does the prototype log to the CSV file?




Question 9: How does the prototype assist with Lab Equipment Access Logging?




Question 10: What foundational principles does the Security Auditing use case demonstrate?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Telecommunications Electronics Engineer and Computer Engineer (official degrees in Spain).

Follow me:
Scroll to Top