基于STM32F103微控制器与复旦微电子FM1702SL射频读卡芯片的驱动开发方案,整合了硬件配置、寄存器操作和通信协议实现:
一、硬件连接设计
1. 管脚映射表
FM1702SL引脚 |
STM32F103引脚 |
功能说明 |
VDD |
3.3V |
电源输入 |
GND |
GND |
地线 |
SCK |
PA5(SPI1_SCK) |
SPI时钟 |
MISO |
PA6(SPI1_MISO) |
主入从出 |
MOSI |
PA7(SPI1_MOSI) |
主出从入 |
CS |
PA4(GPIO) |
片选控制 |
RST |
PA3(GPIO) |
复位信号 |
IRQ |
PA2(GPIO) |
中断输入 |
2. 电路设计要点
- 电源滤波:在VDD和GND间并联104陶瓷电容+10μF电解电容
- 天线匹配:采用1.35μH电感+27pF电容的LC谐振电路(参考)
- ESD防护:在RST和CS引脚串联1kΩ电阻并联TVS管
二、软件架构设计
1. 驱动层结构
// 文件结构
fm1702_driver/
├── hal/
│ ├── spi.c # SPI底层驱动
│ └── gpio.c # GPIO控制
├── src/
│ ├── fm1702.c # 核心驱动
│ └── fm1702.h # 寄存器定义
└── example/
└── read_card.c # 示例应用
2. 关键数据结构
typedef struct {
uint8_t version; // 固件版本
uint16_t atqa; // ATS响应
uint8_t sak; // SEL_RES
uint8_t uid[4]; // UID存储
} FM1702_CardInfo;
typedef enum {
FM1702_STATE_IDLE,
FM1702_STATE_SELECTED,
FM1702_STATE_AUTHENTICATED
} FM1702_State;
三、核心功能实现
1. SPI初始化(HAL库)
void FM1702_SPI_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能时钟
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置SPI引脚
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// SPI参数配置
SPI_HandleTypeDef hspi1;
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
HAL_SPI_Init(&hspi1);
}
2. 寄存器操作
// 读寄存器函数
uint8_t FM1702_ReadReg(uint8_t addr) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS拉低
SPI_SendByte(addr & 0x7F); // 发送地址(低电平有效)
uint8_t data = SPI_ReceiveByte();
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS拉高
return data;
}
// 写寄存器函数
void FM1702_WriteReg(uint8_t addr, uint8_t data) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
SPI_SendByte(addr | 0x80); // 地址最高位设1表示写操作
SPI_SendByte(data);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}
3. 射频卡检测流程
FM1702_State FM1702_DetectCard(void) {
FM1702_WriteReg(0x0D, 0x07); // 设置射频场强度
// 发送请求命令
FM1702_WriteReg(0x0A, 0x52); // Request命令
HAL_Delay(10);
if(FM1702_ReadReg(0x0A) & 0x01) { // 检测到卡片
uint8_t uid[4];
FM1702_ReadUID(uid); // 读取UID
return FM1702_STATE_SELECTED;
}
return FM1702_STATE_IDLE;
}
四、中断处理机制
1. 中断服务例程
void EXTI0_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_LINE0) != RESET) {
FM1702_ClearIRQFlag(); // 清除中断标志
// 处理卡片插入/移除事件
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); // LED状态翻转
}
EXTI_ClearITPendingBit(EXTI_LINE0);
}
2. 中断配置
void FM1702_EnableIRQ(void) {
EXTI_InitTypeDef EXTI_InitStruct = {0};
// 配置EXTI0为下降沿触发
EXTI_InitStruct.Line = EXTI_LINE0;
EXTI_InitStruct.Trigger = EXTI_TRIGGER_FALLING;
EXTI_InitStruct.LineCmd = ENABLE;
HAL_EXTI_SetConfigLine(&EXTI_InitStruct);
}
五、调试与优化
1. 逻辑分析仪捕获
- 使用Saleae捕获SPI通信波形,验证时序是否符合手册要求(时钟极性CPOL=0,相位CPHA=0)
2. 常见问题解决
现象 |
可能原因 |
解决方案 |
无法检测卡片 |
天线匹配不良 |
调整L/C参数至1.35μH+27pF |
通信错误 |
SPI时钟频率过高 |
降低至1MHz以下 |
数据校验失败 |
CRC计算错误 |
实现ISO14443A CRC算法 |
六、完整代码示例
// 读卡器初始化
void FM1702_Init(void) {
FM1702_GPIO_Init(); // 配置GPIO
FM1702_SPI_Init(); // 初始化SPI
FM1702_Reset(); // 硬件复位
FM1702_WriteReg(0x02, 0x8D); // 启动射频场
}
// 主循环处理
int main(void) {
FM1702_Init();
while(1) {
FM1702_State state = FM1702_DetectCard();
if(state == FM1702_STATE_SELECTED) {
// 执行读写操作
uint8_t block_data[16];
FM1702_ReadBlock(0x08, block_data);
}
}
}
七、性能优化建议
- 低功耗模式:在IDLE状态下关闭射频场(设置Reg02[3]=0)
- DMA传输:使用DMA实现SPI数据传输(配置DMA1_Stream0)
- 加密加速:利用STM32硬件加密模块加速DES运算
八、参考资料
- 《FM1702SL数据手册》(复旦微电子官网)
- 代码 基于STM32F103的FM1702驱动程序 youwenfan.com/contentcsa/72737.html
- STM32F103参考手册(ARM Cortex-M3内核)
- ISO/IEC 14443-3标准文档(卡片通信协议)