.. note::
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
**Why Join?**
- **Expert Support**: Solve post-sale issues and technical challenges with help from our community and team.
- **Learn & Share**: Exchange tips and tutorials to enhance your skills.
- **Exclusive Previews**: Get early access to new product announcements and sneak peeks.
- **Special Discounts**: Enjoy exclusive discounts on our newest products.
- **Festive Promotions and Giveaways**: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [|link_sf_facebook|] and join today!
.. _2.2.7_rfid_py_pi5:
2.2.7 MFRC522 RFID Module
==========================
Introduction
---------------
Radio Frequency Identification (RFID) refers to technologies that use
wireless communication between an object (or tag) and interrogating
device (or reader) to automatically track and identify such objects.
Some of the most common applications for this technology include retail
supply chains, military supply chains, automated payment methods,
baggage tracking and management, document tracking and pharmaceutical
management, to name a few.
In this project, we will use RFID for reading and writing.
Required Components
------------------------------
In this project, we need the following components.
.. image:: ../img/list_2.2.7.png
Schematic Diagram
-----------------
.. image:: ../img/image331.png
Experimental Procedures
-----------------------
**Step 1:** Build the circuit.
.. image:: ../img/image232.png
**Step 2:** Set up SPI (refer to :ref:`spi_configuration` for more details. If you have
set SPI, skip this step.)
**Step 3:** Go to the folder of the code.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python-pi5
**Step 4:** Run the ``2.2.10_write.py``.
.. raw:: html
.. code-block::
sudo python3 2.2.10_write.py
**Step 5:** After running the program, enter the text you wish to write (up to 16 characters), such as "welcome," and press Enter to confirm. After that, it will prompt "Data has been written to the card" Finally, press ``Ctrl+C`` to stop the code execution.
.. code-block::
Please place your RFID card on the reader...
Press Ctrl-C to stop.
RFID card detected!
Card UID: 9BF6210B
Please enter data to write to the card (up to 16 characters): welcome
Block 8 authentication successful
4 backdata &0x0F == 0x0A 10
Data written
Data has been written to the card
Reading data from block 8:
Sector 8 [119, 101, 108, 99, 111, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0]
**Step 6:** Now run ``2.2.10_read.py`` to read the information of the tag or card you have written.
.. raw:: html
.. code-block::
sudo python3 2.2.10_read.py
**Step 7:** After running, you will get the following information.
.. code-block::
Please place your RFID card on the reader...
Press Ctrl-C to stop.
RFID card detected!
Card UID: 9BF6210B
Block 8 authentication successful
Sector 8 [119, 101, 108, 99, 111, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0]
MFRC522_Read return type: , Data: [119, 101, 108, 99, 111, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Sector 8 [119, 101, 108, 99, 111, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Read data: welcome
Code Analysis for ``2.2.10_write.py``
---------------------------------------------
This Python script writes user-provided data to an RFID card using the MFRC522 RFID reader. The script continuously checks for a card, prompts the user to enter data to write, and confirms successful write and read operations.
#. Import Statements
* ``MFRC522``: Imports functions and classes required for RFID reader operations.
* ``signal`` and ``time``: ``signal`` is used to handle graceful termination via SIGINT (Ctrl+C), and ``time`` is used to add delays in the main loop.
#. Global Variable
* ``continue_reading``: Controls the main loop, allowing the script to terminate gracefully when set to ``False``.
.. code-block:: python
continue_reading = True
#. Signal Handling:
* ``end_read`` function: This function is triggered when ``Ctrl+C`` (SIGINT) is detected. It sets ``continue_reading`` to ``False``, allowing the script to exit gracefully.
* ``signal.signal(signal.SIGINT, end_read)``: Binds the SIGINT signal (Ctrl+C) to ``end_read``, so when interrupted, the script will display a message and terminate gracefully.
.. code-block:: python
signal.signal(signal.SIGINT, end_read)
#. RFID Reader Setup:
* ``rfid_reader``: An instance of the ``MFRC522`` class, used to control RFID reader operations.
* ``default_key``: A 6-byte list, typically ``0xFF`` for each byte. This is the default authentication key for most RFID cards.
.. code-block:: python
# Create an instance of the MFRC522 class
rfid_reader = MFRC522.MFRC522()
# Define the default key (6 bytes, default is all 0xFF)
default_key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
#. User Instructions
The script prints instructions to the console, informing the user to place their RFID card on the reader and use ``Ctrl+C`` to exit.
.. code-block:: python
print("Please place your RFID card on the reader...")
print("Press Ctrl-C to stop.")
#. Main Loop: Detecting, Writing, and Reading Data
* **Card Detection**: The script continuously calls ``MFRC522_Request`` to detect RFID cards. If a card is detected (``status == rfid_reader.MI_OK``), it proceeds to the next step.
.. code-block:: python
(status, TagType) = rfid_reader.MFRC522_Request(rfid_reader.PICC_REQIDL)
# If a card is detected
if status == rfid_reader.MI_OK:
print("RFID card detected!")
...
else:
# Wait for a while before trying again
time.sleep(0.5)
* **Retrieving the Card’s UID**: Calls ``MFRC522_SelectTagSN`` to retrieve the unique identifier (UID) of the card. If successful, the UID is converted to a hexadecimal string and printed. The UID is necessary for authentication.
.. code-block:: python
(status, uid) = rfid_reader.MFRC522_SelectTagSN()
# If we have the UID, continue
if status == rfid_reader.MI_OK:
# Print UID
uid_str = ''.join(['%02X' % i for i in uid])
print("Card UID: %s" % uid_str)
...
else:
print("Unable to get card UID")
* **Data Preparation**:
* **Prompting for Input**: The user is prompted to enter data to write to the card (up to 16 characters).
* **Data Truncation**: The data is truncated to 16 characters if the user enters more.
* **String to Byte Conversion**: The user’s string input is converted into a byte list padded to 16 bytes, as required by the RFID card’s storage format.
.. code-block:: python
write_data = input("Please enter data to write to the card (up to 16 characters): ")
# Ensure data does not exceed 16 characters
write_data = write_data[:16]
# Convert string to byte list, pad to 16 bytes
data_to_write = [0x00]*16
string_bytes = write_data.encode('utf-8')
for i in range(len(string_bytes)):
data_to_write[i] = string_bytes[i]
* **Specifying the Block Number**: The script specifies block 8 for writing the data. Note: Block numbers should avoid sector trailer blocks, typically the last block in each sector, as they are used for control information.
.. code-block:: python
block_num = 8 # For example, choose block 8
* **Card Authentication**: ``MFRC522_Auth`` authenticates the specified block using the default key and UID. If authentication is successful, the script proceeds with writing data. If not, an error message is printed, and encryption is stopped.
.. code-block:: python
status = rfid_reader.MFRC522_Auth(rfid_reader.PICC_AUTHENT1A, block_num, default_key, uid)
if status == rfid_reader.MI_OK:
print("Block %d authentication successful" % block_num)
...
else:
print("Authentication failed")
rfid_reader.MFRC522_StopCrypto1()
* **Writing Data to the Card**: ``MFRC522_Write`` writes the prepared data to the specified block on the RFID card. After writing, a message confirms that data has been successfully written to the card.
.. code-block:: python
rfid_reader.MFRC522_Write(block_num, data_to_write)
print("Data has been written to the card")
* **Reading Back the Data**: To verify the write operation, the script reads back the data from the same block using ``MFRC522_Read``. The retrieved data is printed to allow the user to verify the data.
.. code-block:: python
print("Reading data from block %d:" % block_num)
rfid_reader.MFRC522_Read(block_num)
* **Stopping Encryption**: ``MFRC522_StopCrypto1`` stops the encryption process after operations are complete. This step is necessary to reset the card’s communication state.
.. code-block:: python
# Stop encryption
rfid_reader.MFRC522_StopCrypto1()
* **Exiting the Loop**: After writing and verifying the data, ``continue_reading`` is set to ``False`` to exit the loop and end the script.
continue_reading = False
**Key Points**
* **Graceful Termination**: The script captures SIGINT (Ctrl+C) to safely terminate and print a message, allowing any ongoing operation to complete before exiting.
* **User Interaction**: Prompts the user for input, enabling data to be customized each time the card is written.
* **Authentication**: Ensures that access to the specified block is securely managed, handling authentication failures gracefully.
* **Data Formatting**: Converts string data to a byte list format compatible with the card’s storage structure, padding as necessary.
* **Verification**: Reads back data from the card to confirm a successful write, enhancing reliability.
* **Modularity**: The script is well-organized with clear functionality for detecting, writing, and reading, making it easier to follow and maintain.
This script is suitable for applications requiring both read and write capabilities with RFID cards, such as access control or user identification.
Code Explanation for ``2.2.10_read.py``
-----------------------------------------------
This Python script uses an **RFID reader (MFRC522)** to read data from RFID cards. The script is structured to continuously check for cards, retrieve their data, and gracefully handle exit requests using signal handling.
#. Import Statements:
* ``MFRC522``: This module provides methods to interact with the MFRC522 RFID reader.
* ``signal`` and ``time``: Used to handle script termination (e.g., ``Ctrl+C``) and control the timing of certain operations.
#. Global Variables:
* ``continue_reading``: A boolean flag that controls the main reading loop, allowing the script to stop gracefully when ``Ctrl+C`` is pressed.
.. code-block:: python
continue_reading = True
#. Signal Handling:
* ``end_read`` function: This function is triggered when ``Ctrl+C`` (SIGINT) is detected. It sets ``continue_reading`` to ``False``, allowing the script to exit gracefully.
* ``signal.signal(signal.SIGINT, end_read)``: Binds the SIGINT signal (Ctrl+C) to ``end_read``, so when interrupted, the script will display a message and terminate gracefully.
.. code-block:: python
signal.signal(signal.SIGINT, end_read)
#. RFID Reader Setup:
* ``rfid_reader``: An instance of the ``MFRC522`` class, used to control RFID reader operations.
* ``default_key``: A 6-byte list, typically ``0xFF`` for each byte. This is the default authentication key for most RFID cards.
* ``block_num``: Specifies the block number to be read from the RFID card, here set to block ``8``. The block number must match the one used when writing data to the card.
.. code-block:: python
# Create an instance of the MFRC522 class
rfid_reader = MFRC522.MFRC522()
# Define the default key (6 bytes, default is all 0xFF)
default_key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
# Define the block number to read (must match the block used during writing)
block_num = 8 # For example, block 8
#. User Instructions
The script prints instructions to the console, informing the user to place their RFID card on the reader and use ``Ctrl+C`` to exit.
.. code-block:: python
print("Please place your RFID card on the reader...")
print("Press Ctrl-C to stop.")
#. Main Loop: RFID Card Detection and Data Reading.
* **Scanning for Cards**: The main loop continuously calls ``MFRC522_Request`` to scan for RFID cards. If a card is detected, it proceeds to the next steps.
.. code-block:: python
(status, TagType) = rfid_reader.MFRC522_Request(rfid_reader.PICC_REQIDL)
if status == rfid_reader.MI_OK:
print("RFID card detected!")
...
else:
# If no card is detected, wait for a short period before retrying
time.sleep(0.5)
* **Retrieving Card UID**: Uses ``MFRC522_SelectTagSN`` to retrieve the card's unique identifier (UID). If successful, it converts the UID to a hexadecimal string and prints it. This UID is necessary for authenticating the card.
.. code-block:: python
(status, uid) = rfid_reader.MFRC522_SelectTagSN()
# If UID was successfully retrieved, proceed
if status == rfid_reader.MI_OK:
# Convert UID list to a hexadecimal string
uid_str = ''.join(['%02X' % i for i in uid])
print("Card UID: %s" % uid_str)
...
else:
print("Unable to get card UID")
* **Authenticating the Card**: ``MFRC522_Auth`` authenticates access to the specified block using the default key and the card's UID. If authentication succeeds, the script moves to reading data from the block.
.. code-block:: python
status = rfid_reader.MFRC522_Auth(rfid_reader.PICC_AUTHENT1A, block_num, default_key, uid)
if status == rfid_reader.MI_OK:
print("Block %d authentication successful" % block_num)
...
else:
print("Authentication failed, status code: %s" % status)
rfid_reader.MFRC522_StopCrypto1()
* **Reading Data**:
* ``MFRC522_Read`` reads data from the specified block.
* ``data``: This variable contains the block's raw data if the read operation is successful.
* The script converts each byte in ``data`` to characters and removes any padding null bytes (``\x00``). The processed data is then printed.
.. code-block:: python
read_status, data = rfid_reader.MFRC522_Read(block_num)
print(f"MFRC522_Read return type: {type(read_status)}, Data: {data}")
if read_status == rfid_reader.MI_OK and data:
print(f"Sector {block_num} {data}")
# Convert byte data to string and remove any padding null bytes
read_data = ''.join([chr(byte) for byte in data]).rstrip('\x00')
print("Read data: %s" % read_data)
else:
print("Data read failed, status code: %s" % read_status)
* ``MFRC522_StopCrypto1`` is called to stop encryption and reset card communication.
.. code-block:: python
# Stop encryption on the card
rfid_reader.MFRC522_StopCrypto1()
* **Waiting between Reads**: If no card is detected, the loop pauses for 0.5 seconds before retrying.
.. code-block:: python
else:
# If no card is detected, wait for a short period before retrying
time.sleep(0.5)
**Key Points**
* **Graceful Exit**: The script captures the ``SIGINT`` signal for graceful termination, allowing the RFID reader to complete any ongoing operations.
* **Block and UID Management**: Uses block and UID as key components in reading data from an RFID card, with proper handling of authentication and read errors.
* **Modular Design**: The use of dedicated functions from the ``MFRC522`` module makes the script readable and modular, simplifying RFID operations like authentication and data reading.
Phenomenon Picture
------------------
.. image:: ../img/image233.jpeg