1. 项目概述与设计思路
这个基于STM32的RFID刷卡识别系统是我最近完成的一个嵌入式项目,它整合了多种实用功能模块,形成了一个完整的门禁系统原型。系统核心功能包括RFID卡识别、OLED显示、状态指示灯、步进电机控制、卡片管理以及温度检测等模块。整个系统的设计思路是构建一个具备基础安防功能的智能门禁系统,特别适合作为嵌入式开发的综合实践项目。
选择STM32作为主控是因为其丰富的外设接口和强大的处理能力,能够轻松应对多模块协同工作的需求。RFID模块采用常见的13.56MHz频率方案,兼容市面上大多数门禁卡。系统工作流程设计为:刷卡识别→温度检测→权限验证→执行开锁,这种串行处理逻辑既保证了安全性,又实现了功能扩展性。
2. 硬件选型与电路设计
2.1 核心控制器选型
我选择了STM32F103C8T6作为主控芯片,这款芯片属于STM32F1系列的"蓝莓派"最小系统板,具有:
- 72MHz主频的Cortex-M3内核
- 64KB Flash + 20KB RAM
- 丰富的外设接口(USART、SPI、I2C、GPIO等)
- 价格亲民且开发资源丰富
对于这个项目来说,其性能完全够用,而且引脚数量(48个)足以连接所有外设模块。更重要的是,STM32的标准外设库和HAL库都相当成熟,大大降低了开发难度。
2.2 RFID模块连接
RFID读卡器选用的是RC522模块,通过SPI接口与STM32连接:
- SCK → PA5
- MOSI → PA7
- MISO → PA6
- NSS → PA4
- RST → PA3
这里需要注意,RC522的工作电压是3.3V,与STM32电平匹配。如果使用5V版本的模块,需要添加电平转换电路。我在实际测试中发现,SPI时钟频率设置在1MHz左右时通信最稳定。
2.3 步进电机驱动电路
28BYJ-48步进电机是常见的5V四相八拍电机,不能直接由STM32驱动。我采用了ULN2003驱动芯片搭建驱动电路:
- 电机接口A/B/C/D分别连接ULN2003的OUT1-OUT4
- ULN2003的IN1-IN4连接STM32的PB0-PB3
- 电机电源单独使用5V/1A适配器供电
重要提示:步进电机工作时会产生反向电动势,务必在电源端并联一个100μF的电解电容进行滤波,否则可能导致MCU复位。
3. 软件开发与功能实现
3.1 开发环境搭建
我使用Keil MDK作为主要开发环境,配合ST-Link V2调试器。项目需要包含以下关键库文件:
- STM32标准外设库
- RC522的SPI驱动库
- SSD1306 OLED驱动库
- DS18B20温度传感器驱动库
工程目录结构建议如下:
code复制/Project
/CMSIS # 内核支持文件
/StdPeriph_Driver # 标准外设库
/User
/inc # 头文件
/src # 源文件
/lib # 第三方驱动库
/MDK-ARM # Keil工程文件
3.2 RFID卡识别实现
RFID功能的核心是RC522的初始化和卡检测逻辑。以下是关键代码实现:
c复制// RC522初始化
void RFID_Init(void) {
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 启用SPI和GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置SPI引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// SPI配置
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
PCD_Init(); // RC522初始化
}
// 卡检测主循环
void RFID_Task(void) {
uint8_t status;
uint8_t str[MAX_LEN];
// 寻卡
status = PICC_IsNewCardPresent();
if (status) {
status = PICC_ReadCardSerial();
if (status == MI_OK) {
// 显示卡ID
sprintf((char *)str, "ID: %02X%02X%02X%02X",
serNum[0], serNum[1], serNum[2], serNum[3]);
OLED_ShowString(0, 0, str);
// 验证卡片权限
if(Check_Card(serNum)) {
LED_Success();
// 温度检测
float temp = DS18B20_GetTemp();
if(temp >= 36.0 && temp <= 37.5) {
Unlock_Door();
} else {
OLED_ShowString(0, 20, "Temp Abnormal!");
}
} else {
LED_Fail();
OLED_ShowString(0, 20, "Invalid Card!");
}
}
}
delay_ms(200);
}
3.3 多任务调度设计
由于系统需要同时处理多个外设,我采用了基于时间片轮询的简单调度机制:
c复制typedef struct {
void (*task_func)(void); // 任务函数指针
uint32_t interval; // 执行间隔(ms)
uint32_t last_run; // 上次执行时间
} Task_t;
Task_t task_list[] = {
{RFID_Task, 200, 0},
{Temperature_Task, 1000, 0},
{Key_Scan_Task, 50, 0},
{OLED_Refresh_Task, 500, 0}
};
void Scheduler_Run(void) {
uint32_t current_time = Get_SystemTick();
for(int i=0; i<sizeof(task_list)/sizeof(Task_t); i++) {
if(current_time - task_list[i].last_run >= task_list[i].interval) {
task_list[i].task_func();
task_list[i].last_run = current_time;
}
}
}
这种设计避免了使用实时操作系统的复杂性,同时保证了各功能模块的及时响应。在实际测试中,系统响应延迟控制在可接受范围内。
4. 功能模块详解
4.1 温度检测模块实现
DS18B20温度传感器采用单总线协议,硬件连接简单(只需要一个GPIO引脚),但时序要求严格。以下是温度读取的关键代码:
c复制#define DS18B20_DQ_PIN GPIO_Pin_8
#define DS18B20_DQ_PORT GPIOB
float DS18B20_ReadTemp(void) {
uint8_t temp_l, temp_h;
int16_t temp;
float temperature;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 启动温度转换
delay_ms(750); // 等待转换完成
DS18B20_Reset();
DS18B20_WriteByte(0xCC);
DS18B20_WriteByte(0xBE); // 读取暂存器
temp_l = DS18B20_ReadByte(); // LSB
temp_h = DS18B20_ReadByte(); // MSB
temp = (temp_h << 8) | temp_l;
temperature = temp * 0.0625; // 转换温度值
return temperature;
}
注意事项:DS18B20对时序要求非常严格,delay函数必须精确。我发现在72MHz主频下,使用SysTick定时器实现的微秒级延时最为可靠。另外,上拉电阻建议使用4.7kΩ,过大会导致信号上升沿太慢,过小则功耗增加。
4.2 步进电机控制优化
28BYJ-48步进电机的标准步距角是5.625°,采用四相八拍方式时,每转需要4096个脉冲(64×64)。但在实际使用中,我发现了几个需要优化的地方:
- 加速曲线:直接全速启动可能导致失步。我实现了简单的梯形加速算法:
c复制void Stepper_Run(int steps, uint16_t max_delay) {
uint16_t delay_time;
int i;
// 加速阶段
for(i=10; i<=max_delay; i+=10) {
delay_time = max_delay * max_delay / i;
Stepper_Step(1);
delay_us(delay_time);
steps--;
if(steps <= 0) break;
}
// 匀速阶段
while(steps > 0) {
Stepper_Step(1);
delay_us(max_delay);
steps--;
}
// 减速阶段
for(i=max_delay; i>=10; i-=10) {
delay_time = max_delay * max_delay / i;
Stepper_Step(1);
delay_us(delay_time);
steps--;
if(steps <= 0) break;
}
}
- 电流控制:持续通电会导致电机和驱动芯片发热。我添加了自动断电功能:
c复制void Stepper_Disable(void) {
GPIO_ResetBits(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);
}
- 定位精度:由于这种电机存在约5%的误差,对于要求精度的场合,建议添加限位开关进行位置校准。
5. 系统集成与调试
5.1 功能整合策略
将各模块功能整合时,我采用了状态机设计模式,定义了系统的主要状态:
c复制typedef enum {
STATE_IDLE, // 空闲状态
STATE_CARD_DETECTED, // 卡检测
STATE_TEMP_CHECKING, // 温度检测
STATE_UNLOCKING, // 开锁中
STATE_ADDING_CARD // 添加卡片
} SystemState_t;
状态转换逻辑如下:
- 默认处于IDLE状态,持续检测RFID卡
- 检测到卡片后,进入CARD_DETECTED状态,验证卡片权限
- 权限验证通过后,进入TEMP_CHECKING状态,读取温度
- 温度正常则进入UNLOCKING状态,驱动步进电机开锁
- 如果检测到添加卡片按键按下,进入ADDING_CARD状态
这种设计使系统逻辑清晰,便于调试和功能扩展。
5.2 调试技巧与问题排查
在开发过程中,我遇到了几个典型问题及解决方案:
-
RFID读取不稳定
- 现象:有时能读卡,有时不能
- 排查:用逻辑分析仪抓取SPI波形,发现时钟频率过高
- 解决:将SPI时钟分频从8调整为16,并缩短读卡间隔
-
步进电机抖动严重
- 现象:电机运行时抖动大,有时会失步
- 排查:测量电源电压发现电机启动时电压跌落严重
- 解决:在电机电源端增加大容量电容(1000μF),并采用独立电源供电
-
温度读取异常
- 现象:偶尔读取到85℃或-127℃的异常值
- 排查:检查时序发现转换未完成就读取数据
- 解决:增加足够的转换等待时间(750ms),并添加CRC校验
-
系统死机
- 现象:运行一段时间后系统无响应
- 排查:检查堆栈使用情况,发现局部数组过大导致栈溢出
- 解决:将大数组改为静态变量或使用动态内存分配
5.3 性能优化建议
经过实际测试,我总结了几点优化建议:
-
功耗优化:
- 在空闲状态关闭不必要的外设时钟
- 使用STM32的低功耗模式
- 降低OLED刷新频率
-
响应速度优化:
- 采用中断方式检测RFID卡
- 预读取温度值(在刷卡前就开始温度转换)
- 优化步进电机控制算法
-
稳定性增强:
- 添加看门狗定时器
- 关键数据添加CRC校验
- 实现错误恢复机制
6. 功能扩展与改进方向
这个基础系统还有很大的扩展空间,以下是我规划的几种改进方案:
-
无线通信扩展
- 添加ESP8266 WiFi模块,实现远程监控
- 通过MQTT协议上传开锁记录和温度数据
- 支持手机APP远程开锁
-
生物识别集成
- 增加指纹识别模块(FPM10A等)
- 实现多因素认证(RFID+指纹)
- 添加人脸识别选项
-
数据记录功能
- 使用SPI Flash或SD卡存储开锁记录
- 记录时间、卡号、温度等信息
- 支持记录导出分析
-
电源管理改进
- 设计备用电池电路
- 实现低功耗待机模式
- 添加电源状态监测
-
外壳与结构设计
- 3D打印定制外壳
- 优化读卡器天线位置
- 改进机械锁结构
在实际项目中,我首先实现了WiFi通信扩展,通过AT指令控制ESP8266模块,将系统状态和开锁记录上传到云服务器。这个改进使得系统管理更加方便,也为后续功能扩展奠定了基础。
