别再只会读卡号了!用STM32F103C8T6和MFRC522玩点花的:自制简易门禁系统(附完整HAL库代码)
从零构建STM32F103C8T6智能门禁系统硬件设计、状态机与权限管理实战当你的开发板上那块蓝色小屏幕终于显示出验证通过四个字时那种成就感比单纯读取卡号强烈十倍。本文将带你用STM32F103C8T6和MFRC522模块从零搭建一个具备完整业务流程的智能门禁原型系统。不同于基础教程中的简单读卡演示我们将实现多设备协同的硬件系统电磁锁、蜂鸣器、LED状态灯基于状态机的业务流程控制双层级权限管理管理员卡与普通卡实时系统日志输出异常处理机制1. 硬件架构设计与电路连接1.1 核心元件选型与功能规划我们的门禁系统需要以下硬件组件协同工作组件型号功能接口方式主控芯片STM32F103C8T6系统控制核心-RFID模块MFRC522卡号读取SPI电磁锁5V常闭型门体锁定GPIO继电器蜂鸣器有源3-5V声音提示GPIOLED指示灯双色共阴状态显示GPIO x2按键6x6轻触开关功能触发GPIO关键电路设计要点电磁锁需要单独5V供电通过S8050三极管驱动继电器控制蜂鸣器建议串联100Ω限流电阻RFID模块的SPI接口需要10K上拉电阻为所有外设配置0.1μF去耦电容1.2 硬件连接示意图// STM32F103C8T6引脚配置 #define RC522_CS_PIN PB12 // SPI片选 #define RC522_RST_PIN PB11 // 复位 #define LOCK_PIN PA8 // 电磁锁控制 #define BUZZER_PIN PA9 // 蜂鸣器 #define LED_GREEN_PIN PA10 // 绿灯 #define LED_RED_PIN PA11 // 红灯 #define KEY_PIN PA12 // 功能按键注意实际接线时MFRC522的IRQ引脚可以不连接但必须确保SPI的MOSI、MISO、SCK正确对应。电磁锁控制线必须经过继电器隔离不可直接连接GPIO。2. 系统软件架构设计2.1 状态机模型实现门禁系统的核心是一个状态机我们定义以下状态stateDiagram [*] -- IDLE IDLE -- CARD_READING: 检测到卡片 CARD_READING -- VERIFYING: 获取卡号 VERIFYING -- GRANTED: 验证通过 VERIFYING -- DENIED: 验证失败 GRANTED -- UNLOCKING: 触发开锁 UNLOCKING -- IDLE: 5秒后 DENIED -- IDLE: 3秒后对应代码实现typedef enum { SYS_IDLE, CARD_DETECTED, VERIFYING, ACCESS_GRANTED, ACCESS_DENIED, DOOR_UNLOCKING } SystemState; SystemState currentState SYS_IDLE; void SystemStateMachine(void) { static uint32_t timeout 0; switch(currentState) { case SYS_IDLE: if(CheckCardPresent()) { currentState CARD_DETECTED; } break; case CARD_DETECTED: if(ReadCardID(currentUID)) { currentState VERIFYING; } break; case VERIFYING: if(VerifyCard(currentUID)) { currentState ACCESS_GRANTED; } else { currentState ACCESS_DENIED; } break; case ACCESS_GRANTED: UnlockDoor(); timeout HAL_GetTick() 5000; currentState DOOR_UNLOCKING; break; case ACCESS_DENIED: AlertDenied(); timeout HAL_GetTick() 3000; break; case DOOR_UNLOCKING: if(HAL_GetTick() timeout) { LockDoor(); currentState SYS_IDLE; } break; } }2.2 权限管理系统实现我们采用两级权限设计管理员卡UID以0x63开头可添加/删除授权卡普通用户卡仅能触发开锁授权卡存储采用EEPROM模拟方案#define EEPROM_START_ADDR 0x0800FC00 // 使用最后一页Flash模拟EEPROM #define MAX_CARDS 20 typedef struct { uint8_t uid[4]; uint8_t cardType; // 0-普通用户, 1-管理员 } CardRecord; void SaveCardToEEPROM(uint8_t* uid, uint8_t type) { CardRecord newCard; memcpy(newCard.uid, uid, 4); newCard.cardType type; HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASH_ErasePage(EEPROM_START_ADDR); for(int i0; iMAX_CARDS; i) { HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, EEPROM_START_ADDR i*sizeof(CardRecord), *(uint32_t*)newCard); } HAL_FLASH_Lock(); } uint8_t VerifyCard(uint8_t* uid) { CardRecord storedCard; for(int i0; iMAX_CARDS; i) { uint32_t addr EEPROM_START_ADDR i*sizeof(CardRecord); memcpy(storedCard, (void*)addr, sizeof(CardRecord)); if(memcmp(storedCard.uid, uid, 4) 0) { return storedCard.cardType 1; // 返回1-普通用户, 2-管理员 } } return 0; // 未授权卡 }3. 外设驱动与功能实现3.1 电磁锁控制优化为避免继电器频繁切换导致寿命缩短我们采用PWM软启动void LockControl(uint8_t state) { if(state) { // 软启动 for(int i0; i100; i) { HAL_GPIO_WritePin(LOCK_GPIO_Port, LOCK_PIN, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(LOCK_GPIO_Port, LOCK_PIN, GPIO_PIN_RESET); HAL_Delay(1); } HAL_GPIO_WritePin(LOCK_GPIO_Port, LOCK_PIN, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(LOCK_GPIO_Port, LOCK_PIN, GPIO_PIN_RESET); } }3.2 声光提示系统多状态反馈设计void SystemFeedback(uint8_t type) { switch(type) { case FEEDBACK_CARD_READ: HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_PIN, GPIO_PIN_SET); HAL_Delay(100); HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_PIN, GPIO_PIN_RESET); break; case FEEDBACK_ACCESS_GRANTED: HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_PIN, GPIO_PIN_SET); Beep(200, 1); break; case FEEDBACK_ACCESS_DENIED: HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_PIN, GPIO_PIN_SET); Beep(50, 3); HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_PIN, GPIO_PIN_RESET); break; case FEEDBACK_ADMIN_MODE: HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_PIN); HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_PIN); HAL_Delay(200); break; } } void Beep(uint16_t duration, uint8_t times) { for(int i0; itimes; i) { HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_PIN, GPIO_PIN_SET); HAL_Delay(duration); HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_PIN, GPIO_PIN_RESET); HAL_Delay(100); } }4. 系统优化与功能扩展4.1 串口日志系统实现分级日志输出便于调试typedef enum { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR } LogLevel; void SystemLog(LogLevel level, const char* message) { const char* levelStr[] {DEBUG, INFO, WARN, ERROR}; char buffer[128]; snprintf(buffer, sizeof(buffer), [%s] %lu: %s\r\n, levelStr[level], HAL_GetTick(), message); HAL_UART_Transmit(huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY); if(level LOG_WARNING) { SystemFeedback(FEEDBACK_ACCESS_DENIED); } }4.2 看门狗与异常处理增强系统稳定性void SystemWatchdogInit(void) { IWDG_HandleTypeDef hiwdg; hiwdg.Instance IWDG; hiwdg.Init.Prescaler IWDG_PRESCALER_32; hiwdg.Init.Reload 0xFFF; hiwdg.Init.Window 0xFFF; if(HAL_IWDG_Init(hiwdg) ! HAL_OK) { Error_Handler(); } } void SystemReset(void) { SystemLog(LOG_ERROR, System will reset due to critical error); HAL_Delay(100); NVIC_SystemReset(); }4.3 功耗优化策略在空闲状态下降低功耗void EnterLowPowerMode(void) { // 关闭不需要的外设时钟 __HAL_RCC_SPI2_CLK_DISABLE(); __HAL_RCC_USART1_CLK_DISABLE(); // 配置GPIO为模拟输入以降低功耗 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_All; GPIO_InitStruct.Mode GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); HAL_GPIO_Init(GPIOB, GPIO_InitStruct); // 进入STOP模式通过外部中断唤醒 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后重新初始化系统 SystemInit(); }5. 完整项目集成与测试5.1 主程序逻辑框架int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI2_Init(); MX_USART1_UART_Init(); RC522_Init(); SystemWatchdogInit(); LoadAuthorizedCards(); SystemLog(LOG_INFO, System initialized); while(1) { HAL_IWDG_Refresh(hiwdg); SystemStateMachine(); if(HAL_GetTick() - lastCardCheck 1000) { CheckAdminButton(); lastCardCheck HAL_GetTick(); } if(noActivityCounter 300000) { EnterLowPowerMode(); noActivityCounter 0; } } }5.2 典型测试用例普通用户卡测试流程刷卡 → 绿灯亮短蜂鸣 → 电磁锁开启 → 5秒后自动锁定串口输出[INFO] 123456: User card accepted (UID: 0x12 0x34 0x56 0x78)管理员卡测试流程刷卡 → 红绿交替闪烁 → 进入管理模式按功能键选择添加卡 → 刷待添加卡 → 提示添加成功串口输出[INFO] 123457: New card added (UID: 0x23 0x45 0x67 0x89)异常情况测试使用未授权卡 → 红灯亮长蜂鸣 → 串口输出[WARN] 123458: Unauthorized card detected连续错误尝试 → 系统锁定 → 串口输出[ERROR] 123459: Security lock activated在项目开发过程中最耗时的部分是状态机的调试和权限管理系统的稳定性测试。实际部署时发现电磁锁的驱动电路需要特别注意反向电动势的防护建议在继电器线圈两端并联续流二极管。