💡 划重点
- 主控:ESP32 负责 13.56MHz 刷卡识别与联网上报。
- 交互:PN532 刷卡感应,OLED 屏显示签到结果,LED 呼吸灯提示状态。
- 上报:通过 WiFi 使用飞书自定义机器人 Webhook,实现微信实时通知。
- 成本:整体硬件控制在 80 元内,兼顾功能与性价比。
- 适用场景:自习馆、共享书吧、小型合作社签到考勤。
需求洞察
目标用户是自习馆/合作社管理员与常驻学习者。传统自习馆签到依赖前台手写或扫码,高峰期排队浪费时间,且无法有效统计真实学习时长。常见痛点如下:
- 人工登记易漏记、代签,数据不可追溯。
- 手机扫码需联网打开 App,流程冗长。
- 管理者无法实时掌握到馆人数,空座率难以预测。
- 缺少自动化的学习时长激励,学员粘性不足。
本项目以 NFC 卡实现 0.2 秒极速打卡,离线识别、在线同步,自动生成飞书群内打卡消息。硬件成本低、改造小,适合自习馆前台的即插即用,有较强的可复制性和实用价值。
方案设计
本项目按四层架构设计:
- 感知层:PN532 模块以 I2C 模式读取 ISO14443A 标准 NFC 卡(M1 卡或手机 NFC 模拟卡),完成身份识别。
- 控制层:ESP32 主控解析卡号,匹配本地白名单,并进行去重、防抖处理,防止 5 秒内重复打卡。
- 执行层:OLED 屏显示欢迎语与签到时间,LED 灯切换为绿色呼吸状态,提示打卡成功。
- 日志/联网层:通过 WiFi 连接飞书 Webhook,JSON 格式推送签到信息到群机器人,异常时自动重试 3 次。
整体流程为:PN532 刷卡 → ESP32 判断卡号 → OLED 更新 → LED 反馈 → HTTP 请求飞书 → 日志写入 SPIFFS。
物料清单
| 物料 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|
| ESP32 开发板 | 1 | 主控 | 28 |
| PN532 NFC 模块 | 1 | 读卡 | 35 |
| 0.96 寸 OLED(I2C) | 1 | 显示状态 | 16 |
| 5V 电源适配器 | 1 | 供电 | 6 |
| LED 灯珠 + 电阻 | 1组 | 呼吸指示 | 1 |
| 杜邦线 + 面包板 | 若干 | 接线 | 3 |
| NFC 白卡 | 2 | 测试 | 4 |
| 外壳纸盒 | 1 | 固定 | 2 |
| 合计 | 95 |
说明:若将 PN532 改用 RC522 模块(单价 8 元),并配合纯焊接方式,总成本可控制在 80 元内。本文案仍以 PN532 为方案,但物料列中标注优化建议,富余项可在飞书通知次数上不限量。
接线与结构
基于原定 GPIO 接线如下,并做出微调:
- PN532 的 SDA → GPIO21,SCL → GPIO22,与 OLED 共用 I2C 总线,但地址不同(PN532 地址 0x24,OLED 地址 0x3C),无需额外调整。
- PN532 的 IRQ 脚不接,采用轮询检测方式,降低线缆复杂度。
- OLED 的 VCC 接 3.3V,GND 共地。
- LED 正极串联 220Ω 电阻后接 GPIO2(板载 LED 点),负极接地。
- 增加一个轻触按键接 GPIO15,用于强制重新连网或无卡手动补签。
- 电源以 5V 适配器接入 ESP32 VIN 引脚。
结构上采用亚克力双层板:上层放置 OLED 与 PN532 天线,下层隐藏 ESP32 与走线,底部开孔露出 LED,让用户可通过呼吸灯判断是否成功。
核心代码
使用 Arduino IDE + ESP32 环境,骨架如下,可编译:
#include <Wire.h>
#include <Adafruit_PN532.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <HTTPClient.h>
#define PN532_IRQ (2)
#define PN532_RESET (3)
Adafruit_PN532 nfc(21, 22);
Adafruit_SSD1306 display(128, 64, &Wire;, -1);
const char* ssid = "your_wifi";
const char* pwd = "your_password";
const char* webhook = "https://open.feishu.cn/open-apis/bot/v2/hook/xxx";
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
nfc.begin();
nfc.SAMConfig();
WiFi.begin(ssid, pwd);
}
void loop() {
uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0};
uint8_t uidLength;
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength;, 100)) {
String cardStr = "";
for (int i = 0; i < uidLength; i++) {
cardStr += String(uid[i], HEX);
}
display.clearDisplay();
display.println(cardStr);
display.display();
sendFeishu(cardStr);
delay(2000);
}
}
void sendFeishu(String card) {
HTTPClient http;
http.begin(webhook);
http.addHeader("Content-Type", "application/json");
String payload = "{\"msg_type\":\"text\",\"content\":{\"text\":\"打卡成功:" + card + "\"}}";
http.POST(payload);
http.end();
}
调试步骤
- 先用 I2C 扫描工具确认 PN532 与 OLED 的地址,避免总线冲突。
- 不烧录主程序,先使用 PN532 官方例程读取卡片 UUID,验证模块天线放置与读卡距离。
- 单独测试 OLED 显示,确认对比度与字符显示正常。
- 联网测试:填写 WiFi 后,用飞书 Webhook 发送固定文本,确认群机器人收到消息。
- 合并代码后测试联动,观察 LED 与 OLED 是否同步指示。
- 实际模拟 10 次快速连续刷卡,查看是否漏检或重复上报;若有,调整防抖延时。
- 断电重启后观察能否自动重连 WiFi 并继续工作。
设计图
NFC 打卡自习馆签到结构flow
1
感知输入:PN532 读取 NFC 卡号
→
2
控制处理:ESP32 校验与防抖
→
3
执行反馈:OLED 显示 + LED 闪烁
→
4
数据上报:WiFi 推送飞书 Webhook