用STM32F103C8T6和PN532模块DIY一个带短信报警的智能门禁(附完整代码)
用STM32F103C8T6和PN532打造智能门禁系统从硬件搭建到短信报警实战在创客圈子里智能门禁系统一直是个经久不衰的热门项目。不同于市面上动辄上千元的商业解决方案今天我要分享的这套基于STM32F103C8T6和PN532模块的自制系统不仅成本控制在200元以内还能实现刷卡开门、密码解锁、非法入侵短信报警等完整功能。最棒的是所有代码和接线图都会完整公开跟着做就能复现。1. 硬件选型与核心组件解析1.1 主控芯片为什么选择STM32F103C8T6STM32F103C8T6这颗Cortex-M3内核的MCU堪称电子DIY界的瑞士军刀。72MHz主频、64KB Flash、20KB RAM的配置对于门禁系统绰绰有余。我特别看重它的几个特性丰富的外设接口3个USART刚好满足RFID、GSM和调试需求、2个I2COLED和扩展、11个定时器PWM控制舵机低功耗表现运行模式下仅36mA电流待机模式低至2μA开发生态完善Arduino核心、HAL库、标准库多种开发方式可选提示购买时注意区分正版和兼容版后者虽然便宜但可能存在Flash容量缩水问题。实测用STM32CubeProgrammer连接后查看芯片ID可以鉴别。1.2 RFID读卡模块PN532的三种通信模式对比PN532是NFC论坛认证的13.56MHz读写器芯片支持ISO/IEC 14443A/MIFARE协议。实际使用中有三种连接方式可选接口类型接线复杂度通信速率适用场景UART最简单RX/TX115200bps快速原型开发I2C中等SDA/SCL400kHz多设备共享总线SPI最复杂MOSI/MISO/SCK/CS10MHz高速数据传输我最终选择了UART模式因为// 初始化代码示例 Serial2.begin(115200); // STM32的USART2 pn532.begin(Serial2);1.3 报警系统SIM800L GSM模块的实战技巧短信报警功能选用SIM800L模块实现相比原始资料中的GA6模块它有三大优势价格更低约35元支持4频段GSM/GPRS850/900/1800/1900MHz内置TCP/IP协议栈常见问题解决方案供电不足必须外接2A以上电源USB转TTL的5V输出带不动天线摆放陶瓷天线应朝向窗口方向避免金属屏蔽AT指令超时添加重试机制bool sendATCommand(const char* cmd, const char* expect, uint8_t retries3) { while(retries--) { gsmSerial.println(cmd); if(gsmSerial.find(expect)) return true; delay(1000); } return false; }2. 硬件搭建与电路设计2.1 系统接线图详解整个系统的接线遵循核心外设分离原则电源部分5V/2A开关电源单独给SIM800L供电3.3V LDO为STM32和PN532供电1000μF电容并联在电源输入端滤波信号连接STM32F103C8T6 外设模块 ---------- -------- PA2(TX) ---- SIM800L RX PA3(RX) ---- SIM800L TX PA10(TX) ---- PN532 RX PA9(RX) ---- PN532 TX PB6(SCL) ---- OLED SCL PB7(SDA) ---- OLED SDA PC13 ---- 舵机信号线2.2 防干扰设计实战调试过程中最头疼的就是GSM模块对RFID读卡的干扰。通过示波器捕获到的电源噪声如下表所示场景峰峰值噪声读卡距离单独RFID供电120mV4-6cmGSM发送短信时1.2V1cm解决方案在SIM800L的VBAT引脚添加470μF0.1μF并联电容RFID天线周围铺铜并接地使用铁氧体磁环过滤高频噪声3. 核心功能代码实现3.1 RFID卡号读取与验证PN532读取MIFARE卡的UID后需要实现白名单验证功能。我采用以下数据结构存储授权卡typedef struct { uint8_t uid[7]; // 卡号 char name[16]; // 用户名称 uint32_t validTo; // 有效期时间戳 } CardRecord; CardRecord authorizedCards[] { {{0x4A, 0x3B, 0x8C, 0x12}, Alice, 1735689600}, // 2024-12-31 {{0x5B, 0x2C, 0x7D, 0x34}, Bob, 1733011200} // 2024-07-31 };验证逻辑包含三个层次的安全检查UID长度校验防伪卡白名单比对有效期检查3.2 短信指令解析引擎SIM800L收到的短信需要支持多种控制指令OPEN#123456密码开门ADD#4A3B8C12#Alice添加新卡LOCK远程锁定采用状态机实现解析enum SMSState { WAIT_CMD, PARSE_ARGS, EXECUTE }; void processSMS(const char* text) { static SMSState state WAIT_CMD; char buffer[32]; for(int i0; text[i]; i) { switch(state) { case WAIT_CMD: if(text[i]#) { strncpy(buffer, text, i); buffer[i]0; state PARSE_ARGS; } break; // 其他状态处理... } } }3.3 多任务调度设计在没有RTOS的情况下使用时间片轮询实现多任务void loop() { static uint32_t lastRFIDCheck 0; static uint32_t lastGSMCheck 0; uint32_t now millis(); // 每200ms检查RFID if(now - lastRFIDCheck 200) { checkRFID(); lastRFIDCheck now; } // 每5秒检查短信 if(now - lastGSMCheck 5000) { checkSMS(); lastGSMCheck now; } // 实时处理键盘输入 processKeypad(); }4. 调试技巧与性能优化4.1 串口调试的三大神器逻辑分析仪抓取UART波形确认时序问题推荐Saleae Logic Pro 8串口数据监视# Python简易串口监视器 import serial ser serial.Serial(COM3, 115200) while True: print(ser.readline().decode(), end)自定义调试协议在代码中添加调试输出等级控制#define DEBUG_LEVEL 2 // 0-关闭, 1-错误, 2-信息, 3-详细 void debugPrint(int level, const char* msg) { if(level DEBUG_LEVEL) { Serial.printf([%lu] %s\n, millis(), msg); } }4.2 电源效率优化方案通过实测各模块电流消耗发现几个优化点模块工作电流待机电流优化措施STM3236mA2μA启用STOP模式PN53280mA0.5mA动态关闭RF场SIM800L1.2A1mA禁用GPRS启用DRX模式优化后的电源管理代码void enterLowPowerMode() { // 关闭RFID场 pn532.PowerDown(); // 配置GSM进入DRX模式 gsmSerial.println(ATCFUN0); // STM32进入STOP模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }5. 扩展功能与升级路线5.1 物联网集成方案通过ESP-01S WiFi模块添加远程控制功能硬件连接ESP-01S STM32 -------- ------ TX - PA3 RX - PA2 VCC 3.3V CH_PD 3.3V GND GNDMQTT通信示例void publishDoorEvent(const char* event) { wifiSerial.printf(ATCIPSEND%d\r\n, strlen(event)10); delay(100); wifiSerial.printf(topic/door %s\r\n, event); }5.2 生物识别扩展预留的USART3接口可以接入指纹模块如AS608// 指纹录入流程 void enrollFingerprint(uint8_t id) { sendCmd(FINGERPRINT_ENROLL, id); while(!getImage()); delay(500); while(!generateTemplate()); storeTemplate(id); }实际测试中发现将RFID卡与指纹双重认证结合安全性提升显著认证方式破解难度用户体验成本仅密码低中低RFID卡中高中指纹高高高RFID指纹极高中高6. 完整项目代码结构最终工程采用模块化设计主要文件如下/SmartDoorLock ├── /lib │ ├── PN532 # RFID驱动 │ ├── SIM800L # GSM驱动 │ └── SSD1306 # OLED驱动 ├── /src │ ├── main.cpp # 主逻辑 │ ├── config.h # 参数配置 │ ├── rfid.cpp # 卡处理 │ ├── gsm.cpp # 短信处理 │ └── ui.cpp # 用户界面 └── platformio.ini # 构建配置关键配置参数config.h节选// 系统参数 #define MAX_RETRY 3 // 密码尝试次数 #define LOCK_TIMEOUT 30000 // 自动锁定时间(ms) // 硬件引脚定义 #define SERVO_PIN PC13 #define BUZZER_PIN PC14 #define KEYPAD_ROWS {PB12, PB13, PB14, PB15} #define KEYPAD_COLS {PA5, PA6, PA7, PA8}在项目开发过程中最耗时的部分是GSM模块的稳定性调试。后来发现在AT指令发送间添加至少300ms的延迟同时启用硬件流控制RTS/CTS能显著降低通信失败率。另一个实用技巧是在OLED显示中添加实时状态图标比如信号强度、未读短信数量等这对现场调试帮助很大。