ESP32 雙 MFRC522 讀卡機管理 (中斷方式)
ESP32 雙 MFRC522 讀卡機管理,主要解決了原本 Wokwi 模擬器不支援硬體中斷 (IRQ) 暫存器以及 GPIO 34/35 無法設定內建上拉電阻 (Input-Only) 的問題。
一、 核心功能摘要
雙讀卡機獨立識別:透過獨立的 CS/SDA 腳位(GPIO 5 與 GPIO 4)交替控制兩台 MFRC522,並在輸出時分別加上自訂前綴標籤 (
AA:與BB:)。高響應速度(輕量輪詢):主迴圈設定
20ms的微短延遲,既不會過度佔用 CPU 資源,又能提供接近「即時感應」的刷卡體驗。GPIO 腳位相容性修正:將原本引發警告的 GPIO 34/35 改為支援
INPUT_PULLUP的 GPIO 13 與 GPIO 14,完全消除了 ESP32 底層驅動的gpio_pullup_en錯誤。防重複刷卡機制:每次成功讀卡後自動將卡片進入休眠(
PICC_HaltA()),並加入1000ms的冷卻延遲,防止卡片放在感應區時連續重複觸發。
二、 程式碼逐段詳細說明
1. 標頭檔與腳位定義區
#include <SPI.h>
#include <MFRC522.h>
// 定義 Reader 1 (CARD1) 的腳位與前綴
#define SS_1_PIN 5 // 片選腳位 (SDA)
#define RST_1_PIN 21 // 重置腳位
#define IRQ_1_PIN 13 // 中斷預留腳位 (支援內建 Pull-Up)
const String CARD1_PREFIX = "AA:";
// 定義 Reader 2 (CARD2) 的腳位與前綴
#define SS_2_PIN 4 // 片選腳位 (SDA)
#define RST_2_PIN 22 // 重置腳位
#define IRQ_2_PIN 14 // 中斷預留腳位 (支援內建 Pull-Up)
const String CARD2_PREFIX = "BB:";
MFRC522 rfid1(SS_1_PIN, RST_1_PIN);
MFRC522 rfid2(SS_2_PIN, RST_2_PIN);
說明:宣告 SPI 與 MFRC522 函式庫,並為兩台讀卡機建立獨立的實體物件(
rfid1與rfid2)。設定CARD1_PREFIX為"AA:",CARD2_PREFIX為"BB:"。
2. 自訂讀卡與格式化函式 readCard()
void readCard(MFRC522 &mfrc522, String prefix) {
// 1. 檢查是否有新卡片靠近,並嘗試讀取卡片 Serial 序號
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
return; // 若沒有卡片或讀取失敗,直接跳出函式
}
// 2. 組裝 Prefix + 16 進位 UID 格式 (如 "AA:01:02:03:04")
String fullCode = prefix;
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (i > 0) fullCode += ":";
if (mfrc522.uid.uidByte[i] < 0x10) fullCode += "0"; // 小於 0x10 時補上首位 0
fullCode += String(mfrc522.uid.uidByte[i], HEX);
}
fullCode.toUpperCase(); // 將字母轉為大寫
// 3. 輸出結果至 Serial Monitor
Serial.print("感應結果 -> ");
Serial.println(fullCode);
// 4. 卡片休眠與防重複感應延遲
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
delay(1000);
}
說明:採用引用傳遞(
MFRC522 &mfrc522),讓同一個函式可重複用於rfid1與rfid2。負責將讀到的 16 進位 UID 位元組轉換為直觀的大寫字串格式。
3. 初始化設定 setup()
void setup() {
Serial.begin(115200);
SPI.begin(); // 初始化 ESP32 的預設 SPI 匯流排 (SCK=18, MISO=19, MOSI=23)
// 設定 IRQ 腳位模式(消除 GPIO 34/35 的系統警告)
pinMode(IRQ_1_PIN, INPUT_PULLUP);
pinMode(IRQ_2_PIN, INPUT_PULLUP);
// 分別初始化兩台 MFRC522 晶片
rfid1.PCD_Init();
Serial.println("MFRC522 #1 (CARD1) 就緒");
rfid2.PCD_Init();
Serial.println("MFRC522 #2 (CARD2) 就緒");
}
說明:開啟串口並初始化硬體 SPI 介面。將 GPIO 13/14 宣告為
INPUT_PULLUP,確保轉移到實體板子時能隨時啟用中斷,並分別呼叫PCD_Init()完成讀卡機晶片暫存器初始化。
4. 主迴圈 loop()
void loop() {
// 依序輪詢 Reader 1 與 Reader 2
readCard(rfid1, CARD1_PREFIX);
readCard(rfid2, CARD2_PREFIX);
delay(20); // 20ms 微延遲,兼顧響應速度與降低 CPU 負載
}
說明:以每秒約 50 次的頻率交替檢查兩台讀卡機。當任何一台讀卡機感應到卡片時,即時在 Serial Monitor 印出帶有前綴的卡號。
連線總覽對照表
| 功能腳位 | Reader 1 (rfid1) | Reader 2 (rfid2) | ESP32 GPIO | 電源 / 備註 |
| SCK | SCK | SCK | GPIO 18 | SPI 時脈線(共用) |
| MISO | MISO | MISO | GPIO 19 | SPI 主入從出(共用) |
| MOSI | MOSI | MOSI | GPIO 23 | SPI 主出從入(共用) |
| SDA / SS | SDA | — | GPIO 5 | Reader 1 片選線 |
| — | — | SDA | GPIO 4 | Reader 2 片選線 |
| RST | RST | — | GPIO 21 | Reader 1 重置線 |
| — | — | RST | GPIO 22 | Reader 2 重置線 |
| IRQ | IRQ | — | GPIO 13 | 支援內建 Pull-Up 中斷 |
| — | — | IRQ | GPIO 14 | 支援內建 Pull-Up 中斷 |
| VCC / GND | 3.3V / GND | 3.3V / GND | 3V3 / GND | 供電 3.3V(切勿接 5V) |



沒有留言:
張貼留言