125K RFID解码
曼彻斯特编码能够把数据速率对应的时钟信息嵌入到消息中,便于接收端恢复时钟。此外,曼彻斯特编码还有一个额外优点:其平均直流(DC)电平始终为 50%。这对解调器电路设计以及调制后发射射频(RF)频谱的管理都有积极意义。这意味着在一些调制方式中(例如调幅 AM),若输出功率是消息信号的函数,则平均功率保持恒定,不随编码后的数据流变化。
曼彻斯特编码规定:在每个数据比特帧的中点,消息信号一定会发生一次跳变。至于在比特边界处是否跳变,则取决于前一个比特帧的状态,因此不一定总会产生跳变。
ID卡(如EM4100)输出的数据已经是曼彻斯特编码了。需要对捕获的信号进行曼彻斯特解码(不是编码),才能得到正确的数据位。
曼彻斯特编码的方式一般有两种:

我们使用的EM4100属于第一种。即:1用 0 1表示,0 用 1 0表示。

协议规定:1 bit 占用 64 个载波周期,载波频率:fc=125 kHz
所以:数据位速率就是:



所以:全位脉宽为512us,半位脉宽为256us。
当 64 位的最后一位发完之后,芯片会立刻从第一位重新开始发送,一直循环,直到磁场消失(掉电)。


我们使用状态机的方法进行数据解析:
#include "Time_Caputer.h"
/*接收RFID数据 变量*/
// FreeRTOS队列句柄,用于存放接收到的原始数据(128字节的数组)
QueueHandle_t xHalfBitsQueue = NULL;
// 全局标志位,用于通知主程序RFID数据已接收完成
uint8_t g_bitResevData = false;
// RFID状态机上下文结构体,保存状态机的所有状态信息,初始化为0
rfid_sm_context_t g_sm;
//volatile uint8_t g_bDataReady = FALSE; // volatile 很重要,因为会被中断和主程序同时访问
uint8_t g_ucHalfBits[128]; // 存储128个原始电平
void Time_Caputer_init(void)
{
TIM_ICInitType TIM_ICInitStructure;
TIM_TimeBaseInitType TIM_TimeBaseStructure1;
/* 0. 使能TIM3时钟(必须放在最前面!) */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);
/* 1. GPIO配置 */
Time_Caputer_GPIO_Configuration();
/* 2. 定时器时基配置 */
// 假设系统时钟是64MHz
// 64MHz/(255+1) = 250kHz,每个计数4μs
TIM_TimeBaseStructure1.Period = 65535; // 最大计数值
TIM_TimeBaseStructure1.Prescaler = 255; // 256分频,每个计数4μs
TIM_TimeBaseStructure1.ClkDiv = TIM_CLK_DIV1; // 时钟不分频
TIM_TimeBaseStructure1.CntMode = TIM_CNT_MODE_UP; // 向上计数
// 先配置时基
TIM_InitTimeBase(TIM3, &TIM_TimeBaseStructure1);
/* 3. 输入捕获配置 - 更完整的配置 */
// 通道2配置
TIM_ICInitStructure.Channel = TIM_CH_2;
TIM_ICInitStructure.IcPolarity = TIM_IC_POLARITY_BOTHEDGE; // 双边沿触发
TIM_ICInitStructure.IcSelection = TIM_IC_SELECTION_DIRECTTI; // 直接输入
TIM_ICInitStructure.IcPrescaler = TIM_IC_PSC_DIV1; // 不分频,每个边沿都捕获
TIM_ICInitStructure.IcFilter = 0x8; // 8个时钟滤波(约32μs滤波)
// 初始化输入捕获
TIM_ICInit(TIM3, &TIM_ICInitStructure);
/* 4. 重置计数器 */
TIM_SetCnt(TIM3, 0);
/* 5. 清除所有中断标志 */
TIM_ClrIntPendingBit(TIM3, TIM_INT_CC2 | TIM_INT_UPDATE);
/* 6. 中断配置 */
Time_Caputer_NVIC_Configuration();
/* 7. 使能中断 */
// 捕获比较中断(通道2)
TIM_ConfigInt(TIM3, TIM_INT_CC2, ENABLE);
// 溢出中断(用于超时检测)
TIM_ConfigInt(TIM3, TIM_INT_UPDATE, ENABLE);
}
void Time_Caputer_start(void)
{
/* 现在只需要使能定时器 */
TIM_Enable(TIM3, ENABLE);
}
void Time_Caputer_GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
GPIO_InitStruct(&GPIO_InitStructure);
/* TIM3通道2 (PB.05) 配置 */
GPIO_InitStructure.Pin = GPIO_PIN_5;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP; // 复用推挽
GPIO_InitStructure.GPIO_Current = GPIO_DC_LOW; // 低驱动
GPIO_InitStructure.GPIO_Alternate = GPIO_AF2_TIM3; // 复用功能2:TIM3
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
}
void Time_Caputer_NVIC_Configuration(void)
{
NVIC_InitType NVIC_InitStructure;
/* 配置TIM3中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1; // 较高优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// ==================== 状态转换表 ====================
static const rfid_state_transition_t state_transition_table[] =
{
/*******************************************************************
* 状态1:空闲状态 (RFID_STATE_IDLE)
*******************************************************************/
{
.current_state = RFID_STATE_IDLE, // 当前状态:空闲
.event = RFID_EVT_RISING_EDGE, // 事件:检测到上升沿
.next_state = RFID_STATE_WAIT_SECOND_EDGE, // 下一状态:等待第二个边沿
.callback = on_idle_rising_edge // 回调函数:处理上升沿事件
},
/*******************************************************************
* 状态2:等待第二个边沿 (RFID_STATE_WAIT_SECOND_EDGE)
*******************************************************************/
{
.current_state = RFID_STATE_WAIT_SECOND_EDGE, // 当前状态:等待第二个边沿
.event = RFID_EVT_INTERVAL_256US, // 事件:间隔为256μs(半位)
.next_state = RFID_STATE_CHECK_SYNC, // 下一状态:检查同步头
.callback = on_wait_second_256us // 回调函数:处理256μs间隔事件
},
{
.current_state = RFID_STATE_WAIT_SECOND_EDGE,
.event = RFID_EVT_INVALID_INTERVAL, // 统一的不合格间隔事件
.next_state = RFID_STATE_IDLE,
.callback = on_check_sync_invalid // 统一的失败处理
},
{
.current_state = RFID_STATE_WAIT_SECOND_EDGE,
.event = RFID_EVT_INTERVAL_512US,
.next_state = RFID_STATE_IDLE,
.callback = on_check_sync_invalid // 统一的失败处理
},
/*******************************************************************
* 状态3:检查同步头 (RFID_STATE_CHECK_SYNC)
*******************************************************************/
{
.current_state = RFID_STATE_CHECK_SYNC, // 当前状态:检查同步头
.event = RFID_EVT_INTERVAL_256US, // 事件:间隔为256μs(半位)
.next_state = RFID_STATE_CHECK_SYNC, // 下一状态:保持检查同步头状态
.callback = on_sync_check_256us // 回调函数:处理256μs间隔,计数同步头
},
{
.current_state = RFID_STATE_CHECK_SYNC,
.event = RFID_EVT_INVALID_INTERVAL, // 统一的不合格间隔事件
.next_state = RFID_STATE_IDLE,
.callback = on_check_sync_invalid // 统一的失败处理
},
/*******************************************************************
* 状态4:接收数据 (RFID_STATE_RECEIVE_DATA)
*******************************************************************/
{
.current_state = RFID_STATE_RECEIVE_DATA, // 当前状态:接收数据
.event = RFID_EVT_INTERVAL_512US, // 事件:间隔为512μs(全位)
.next_state = RFID_STATE_RECEIVE_DATA, // 下一状态:保持接收数据状态
.callback = on_data_512us // 回调函数:存储2个相同电平(全位)
},
{
.current_state = RFID_STATE_RECEIVE_DATA, // 当前状态:接收数据
.event = RFID_EVT_INTERVAL_256US, // 事件:间隔为256μs(半位)
.next_state = RFID_STATE_RECEIVE_DATA, // 下一状态:保持接收数据状态
.callback = on_data_256us // 回调函数:存储1个电平(半位)
},
{
.current_state = RFID_STATE_RECEIVE_DATA,
.event = RFID_EVT_INVALID_INTERVAL, // 统一的不合格间隔事件
.next_state = RFID_STATE_IDLE,
.callback = on_check_sync_invalid // 统一的失败处理
},
/* 结束标记 */
// 状态转换表的结束标记,用于遍历时检测表尾
{RFID_STATE_COUNT, RFID_EVT_NONE, RFID_STATE_IDLE, NULL}
};
// ==================== 回调函数实现 ====================
/**
* @brief 空闲状态上升沿事件回调函数
* @param current_level 上升沿发生后的引脚电平状态(应为1,表示高电平)
* @param interval 时间间隔(此参数在IDLE状态下始终为0)
* 示例时序:
* 空闲状态: 低电平 → 上升沿发生 → 记录[0,1] → 等待第二个边沿
*/
void on_idle_rising_edge(uint8_t current_level, uint16_t interval)
{
// 清零计数器,准备开始新的帧接收
g_sm.sync_count = 1; // 同步头边沿计数清零
g_sm.half_bit_count = 0; // 半位计数清零
g_sm.data_bit_count = 0; // 数据位计数清零
// 记录第二个电平(上升沿后的高电平)到缓冲区,并且补充第一个0
if(g_sm.half_bit_count < 128) // 检查缓冲区是否未满
{
g_sm.half_bits[g_sm.half_bit_count++] = 0;
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
}
// 调试输出:打印检测到第一个上升沿的信息
#ifdef RFID_DEBUG
printf("IDLE: First rising edge detected\n");
#endif
}
/**
* @brief 等待第二个边沿状态 - 256μs间隔回调函数
*
* 典型调用场景:
* - 检测到第一个逻辑"1"后,256μs内出现下一个边沿
* - 验证同步头开始的正确性
* - 如果间隔不是256μs,则触发on_check_sync_invalid函数重置状态机
*/
void on_wait_second_256us(uint8_t current_level, uint16_t interval)
{
// 存储第二个电平到缓冲区
if(g_sm.half_bit_count < 128) // 检查缓冲区是否未满
{
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
}
// 设置同步头计数为1,表示已检测到第一个逻辑"1"(一个完整的"01"模式)
(g_sm.sync_count)++;
// 调试输出:打印256μs间隔信息和同步计数
#ifdef RFID_DEBUG
printf("WAIT_SECOND: 256μs interval, sync count=%d\n", g_sm.sync_count);
#endif
}
/**
* @brief 无效时间间隔处理回调函数
* @param current_level 当前引脚电平状态(0=低电平,1=高电平)
* @param interval 检测到的时间间隔(单位:微秒)
* @warning 此函数会清空半位缓冲区和同步计数器,确保状态机从头开始新的数据接收。
*/
void on_check_sync_invalid (uint8_t current_level, uint16_t interval)
{
// 无效时间间隔,丢弃数据
g_sm.half_bit_count = 0;
g_sm.sync_count = 0;
#ifdef RFID_DEBUG
printf("WAIT_SECOND: Invalid interval %dμs, reset\n", interval);
#endif
}
/**
* @brief 同步头检查状态 - 256μs间隔回调函数
* @details
* EM4100协议同步头由9个连续的逻辑"1"组成,每个逻辑"1"对应曼彻斯特编码的"01"模式,
* 每个半位持续256μs。本函数通过计数连续256μs间隔的数量来验证同步头。
* 函数执行流程:
* 1. 将当前电平存入半位缓冲区,构建完整的原始数据序列
* 2. 递增同步头计数器(sync_count),跟踪已检测到的256μs间隔数量
* 3. 检查是否已收到完整的同步头(同步头计数器≥17时触发完成标志)
*/
void on_sync_check_256us(uint8_t current_level, uint16_t interval)
{
// 连续256μs间隔,同步头的一部分
// 存储电平
if(g_sm.half_bit_count < 128 && g_sm.sync_count <= 16)
{
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
}
// 增加同步计数
g_sm.sync_count++;
#ifdef RFID_DEBUG
printf("CHECK_SYNC: 256μs interval, sync count=%d\n", g_sm.sync_count);
#endif
// 检查是否收到完整的同步头(9个逻辑"1" = 18个间隔)
// 注意:第一个"1"已在WAIT_SECOND状态计数,所以总共需要17个
if(g_sm.sync_count >= 17) // 9个"1" = 18个间隔 - 1(已计数)
{
// 设置同步完成标志
g_sm.sync_complete_flag = 1;
#ifdef RFID_DEBUG
printf("CHECK_SYNC: Sync header complete!\n");
#endif
// 立即处理内部事件,触发状态转换
process_state_machine(RFID_EVT_SYNC_OK, current_level, interval);
}
}
/**
* @brief 512μs间隔处理(完整数据位)
* @note 每个完整数据位存储2个相同的电平
*/
void on_data_512us(uint8_t current_level, uint16_t interval)
{
// 存储2个相同的电平
if(g_sm.half_bit_count < 128)
{
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
if(g_sm.half_bit_count < 128)
{
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
}
}
#ifdef RFID_DEBUG
printf("DATA: 512μs, level=%d, half_bits=%d\n",
current_level, g_sm.half_bit_count);
#endif
// 检查是否收到完整数据(128个半位 = 64个数据位)
// 注意:我们从第17个半位开始计数,所以需要接收111个半位
if(g_sm.half_bit_count >= 128) // 17 + 111 = 128
{
g_sm.data_complete_flag = 1;
process_state_machine(RFID_EVT_DATA_OK, current_level, interval);
}
}
/**
* @brief 256μs间隔处理(半位)
* @note 连续相同位时的中间跳变,只存储1个电平
*/
void on_data_256us(uint8_t current_level, uint16_t interval)
{
// 存储1个电平
if(g_sm.half_bit_count < 128)
{
g_sm.half_bits[g_sm.half_bit_count++] = current_level;
}
#ifdef RFID_DEBUG
printf("DATA: 256μs, level=%d, half_bits=%d\n",
current_level, g_sm.half_bit_count);
#endif
// 检查是否收到完整数据
if(g_sm.half_bit_count >= 128)
{
g_sm.data_complete_flag = 1;
process_state_machine(RFID_EVT_DATA_OK, current_level, interval);
}
}
/**
* @brief 数据接收完成回调函数(队列发送)
*/
void on_frame_complete(void)
{
// 声明队列句柄
extern QueueHandle_t xRFIDDataQueue;
#ifdef RFID_DEBUG
printf("FRAME_COMPLETE: Sending data to queue\n");
#endif
// 1. 检查数据长度
if (g_sm.half_bit_count < 128)
{
#ifdef RFID_DEBUG
printf("FRAME_COMPLETE: Error - Only %d half bits\n", g_sm.half_bit_count);
#endif
rfid_state_machine_reset();
return;
}
// 2. 创建并发送数据包
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xRFIDDataQueue != NULL) {
// 直接使用全局g_sm.half_bits数组
uint32_t timestamp = xTaskGetTickCountFromISR();
// 发送三个参数:数据指针、长度、时间戳
// 注意:这里假设队列接收一个结构体,或者你可以简化发送方式
BaseType_t xStatus = xQueueSendFromISR(xRFIDDataQueue,
&g_sm.half_bits[0],
&xHigherPriorityTaskWoken);
if (xStatus == pdPASS)
{
g_bitResevData = true;
}
}
// 3. 重置状态机
rfid_state_machine_reset();
}
// 计算数组大小
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/**
* @brief RFID 解码状态机驱动入口:根据“事件 + 当前电平 + 边沿间隔”查表执行回调并完成状态跳转。
* @param event 状态机事件类型,用于匹配状态转换表。
* @param current_level 当前边沿发生后引脚的电平状态(0=低,1=高),用于记录半位电平序列/辅助校验。
* @param interval 相邻两次边沿之间的时间间隔
*/
void process_state_machine(rfid_event_t event, uint8_t current_level, uint16_t interval)
{
// ==================== 步骤1:处理内部事件标志 ====================
// 目的:检查是否有内部事件标志被设置,如果有,将它们转换为对应的事件
// 解释:在回调函数中可能会设置一些内部标志(如sync_complete_flag),
// 这些标志需要在下一个处理周期转换为具体的事件
if(g_sm.sync_complete_flag)
{
// 同步完成标志被设置且当前事件为RFID_EVT_NONE时,
// 将事件替换为RFID_EVT_SYNC_OK(同步完成事件)
event = RFID_EVT_SYNC_OK;
g_sm.state =RFID_STATE_RECEIVE_DATA;
// 清除标志,防止重复处理
g_sm.sync_complete_flag = 0;
// 调试输出
#ifdef RFID_DEBUG
printf("PROCESS: Internal event SYNC_OK triggered\n");
#endif
}
else if(g_sm.data_complete_flag)
{
// 清除标志,防止重复处理
g_sm.data_complete_flag = 0;
// 调试输出
#ifdef RFID_DEBUG
printf("PROCESS: Internal event DATA_OK triggered\n");
#endif
// 直接调用帧完成处理函数
on_frame_complete();
return; // 直接返回,不进行后续处理
}
// ==================== 1. 遍历状态转换表,找匹配项 ====================
// 说明:状态机由 state_transition_table 驱动,
// 这里就是“根据当前状态 + 当前事件”去查表找下一步怎么走。
else
{
for(int i = 0; i < ARRAY_SIZE(state_transition_table); i++)
{
if(state_transition_table[i].current_state == g_sm.state && state_transition_table[i].event == event)
{
// 执行回调函数
if(state_transition_table[i].callback != NULL)
{
state_transition_table[i].callback(current_level, interval);
}
// 只有内部事件标志没有被置位的时候,才使用表中的next_state
if(!(g_sm.sync_complete_flag || g_sm.data_complete_flag))
{
g_sm.state = state_transition_table[i].next_state;
}
// 状态转换
// 更新电平记录
g_sm.last_level = current_level;
#ifdef RFID_DEBUG
printf("STATE: %d -> %d, Event: %d\n",
state_transition_table[i].current_state,
state_transition_table[i].next_state,
event);
#endif
break;
}
}
}
}
// ==================== 定时器状态结构体 ====================
typedef struct
{
uint32_t last_capture_time; // 上次捕获时间(32位组合时间)
uint16_t overflow_count; // 溢出计数(用于扩展16位定时器到32位)
uint8_t last_level; // 上次电平状态(0=低,1=高)
uint32_t last_edge_tick; // 上次边沿时间(用于超时检测)
} timer_state_t;
// 全局定时器状态变量(volatile确保中断和主程序正确访问)
static volatile timer_state_t g_timer_state = {0};
/**
* @brief TIM3 中断服务函数(输入捕获 + 溢出超时管理)
* @note
* - TIM3 计数分辨率为 4us/tick(64MHz / 256 = 250kHz),间隔换算为 interval_us = interval_ticks * 4。
* - 输入捕获配置为双边沿触发,current_level 通过读取 PB5 电平得到(1=高,0=低)。
*/
void TIM3_IRQHandler(void)
{
// 1. 检查并处理输入捕获中断(通道2)
if (TIM_GetIntStatus(TIM3, TIM_INT_CC2) == SET)
{
// 清除中断标志,防止重复进入中断
TIM_ClrIntPendingBit(TIM3, TIM_INT_CC2);
// 获取当前捕获值(定时器在边沿发生时的计数值)
uint16_t current_capture = TIM_GetCap2(TIM3);
// 读取当前引脚电平(PB.05),判断是上升沿还是下降沿
// 1 = 上升沿(刚刚变为高电平),0 = 下降沿(刚刚变为低电平)
uint8_t current_level = (GPIO_ReadInputDataBit(GPIOB, GPIO_PIN_5) == SET) ? 1 : 0;
// 更新上次边沿时间,用于超时检测
g_timer_state.last_edge_tick = xTaskGetTickCountFromISR();
// ============ 根据当前状态进行处理 ============
switch (g_sm.state)
{
// 情况1:空闲状态,等待第一个上升沿
case RFID_STATE_IDLE:
// 空闲状态只处理上升沿,忽略下降沿
if (current_level == 1)
{
// 记录起始时间(开始一个新的帧接收)
g_timer_state.last_capture_time = current_capture; // 捕获值作为起始时间
g_timer_state.overflow_count = 0; // 重置溢出计数
g_timer_state.last_level = current_level; // 记录当前电平
// 触发上升沿事件,通知状态机
// 参数:RFID_EVT_RISING_EDGE = 上升沿事件
// current_level = 当前电平(1 = 高电平)
// 0 = 第一次边沿没有时间间隔
process_state_machine(RFID_EVT_RISING_EDGE, current_level, 0);
#ifdef RFID_DEBUG
printf("IDLE: 检测到上升沿,电平=%d\n", current_level);
#endif
}
else
{
// 下降沿,忽略(在空闲状态我们只关心上升沿)
#ifdef RFID_DEBUG
printf("IDLE: 下降沿被忽略\n");
#endif
}
break;
// 情况2:非空闲状态(等待第二个边沿、检查同步头、接收数据)
// 状态2:等待第二个边沿
case RFID_STATE_WAIT_SECOND_EDGE:
// 状态3:检查同步头
case RFID_STATE_CHECK_SYNC:
// 状态4:接收数据
case RFID_STATE_RECEIVE_DATA:
{
// 计算时间差(考虑定时器溢出)
// 步骤1:将16位捕获值扩展为32位时间值
// current_capture = 当前捕获值(16位,0-65535)
// overflow_count = 定时器溢出次数
// 组合时间 = 当前捕获值 + 溢出次数 * 65536
uint32_t current_time = current_capture + (g_timer_state.overflow_count * 65536UL);
// 步骤2:获取上次捕获时间
uint32_t last_time = g_timer_state.last_capture_time;
// 步骤3:计算时间间隔(以定时器计数值为单位)
uint16_t interval_ticks;
if (current_time >= last_time)
{
// 正常情况:当前时间大于上次时间,直接相减
interval_ticks = (uint16_t)(current_time - last_time);
}
else
{
// 处理溢出回绕:定时器从65535溢出到0
// 计算从上次时间到65535的差值,加上从0到当前时间的差值
interval_ticks = (uint16_t)((0xFFFFFFFFUL - last_time) + current_time + 1);
}
// 转换为微秒(每个tick=4μs,因为64MHz/256分频=250kHz=4μs/tick)
uint16_t interval_us = interval_ticks * 4;
// 根据间隔时间判断事件类型(允许±20%的误差提高抗干扰性)
rfid_event_t interval_event = RFID_EVT_INVALID_INTERVAL;
if (interval_us >= 204 && interval_us <= 308)
{
// 256μs ±20% 范围(204-308μs)
interval_event = RFID_EVT_INTERVAL_256US;
}
else if (interval_us >= 409 && interval_us <= 615)
{
// 512μs ±20% 范围(409-615μs)
interval_event = RFID_EVT_INTERVAL_512US;
}
else
{
// 不在有效范围内的间隔
interval_event = RFID_EVT_INVALID_INTERVAL;
}
// 更新记录:将这次捕获作为下一次计算的"上次捕获"
g_timer_state.last_capture_time = current_capture;
g_timer_state.last_level = current_level;
// 触发事件到状态机
process_state_machine(interval_event, current_level, interval_us);
break;
}
}
}
// 2. 检查并处理溢出中断(更新中断)
if (TIM_GetIntStatus(TIM3, TIM_INT_UPDATE) == SET)
{
// 清除溢出中断标志
TIM_ClrIntPendingBit(TIM3, TIM_INT_UPDATE);
// 增加溢出计数(用于时间间隔计算)
g_timer_state.overflow_count++;
// 超时检测:如果超过5ms没有边沿,回到空闲状态
// 获取当前系统滴答数
uint32_t current_tick = xTaskGetTickCountFromISR();
// 检查是否超时(5ms)
if ((current_tick - g_timer_state.last_edge_tick) > pdMS_TO_TICKS(5))
{
if (g_sm.state != RFID_STATE_IDLE)
{
// 如果不是空闲状态,说明接收过程被打断,直接调用无效间隔回调函数
// 这相当于触发了RFID_EVT_INVALID_INTERVAL事件
#ifdef RFID_DEBUG
printf("TIMEOUT: 5ms内无边沿,触发无效间隔事件\n");
#endif
// 直接调用on_check_sync_invalid 回调函数(参数为0,0,因为超时没有具体电平和间隔)
// 这个函数会重置状态机
on_check_sync_invalid (0, 0);
}
// 重置超时检测(无论是否在空闲状态都重置)
g_timer_state.last_edge_tick = current_tick;
}
}
}
/**
* @brief RFID状态机复位函数。
*/
void rfid_state_machine_reset(void)
{
g_sm.state = RFID_STATE_IDLE;
g_sm.last_capture = 0;
g_sm.sync_count = 0;
g_sm.data_bit_count = 0;
g_sm.half_bit_count = 0;
g_sm.current_level = 0;
g_sm.last_level = 0;
g_sm.timeout_timer = 0;
g_sm.sync_complete_flag = 0;
g_sm.data_complete_flag = 0;
memset(g_sm.half_bits, 0, sizeof(g_sm.half_bits));
}
#ifndef __TIME_CAPUTER_H__
#define __TIME_CAPUTER_H__
#include "n32wb03x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "FreeRtos_task.h"
#include <string.h>
// ==================== 宏定义 ====================
// 时间定义(假设定时器频率1MHz,1计数=1μs)
#define FULL_BIT_TIME 512 // 全位时间512μs
#define HALF_BIT_TIME 256 // 半位时间256μs
#define ERROR_MARGIN 40 // 误差范围±40μs
#define FULL_BIT_MIN (FULL_BIT_TIME - ERROR_MARGIN)
#define FULL_BIT_MAX (FULL_BIT_TIME + ERROR_MARGIN)
#define HALF_BIT_MIN (HALF_BIT_TIME - ERROR_MARGIN)
#define HALF_BIT_MAX (HALF_BIT_TIME + ERROR_MARGIN)
#define BIT_HAFE_TIME 768 // 1.5倍位时间,用于超时检测
// 引脚定义
#define DATA_PORT GPIOB
#define DATA_PIN GPIO_Pin_5
#define DATA_TIMER TIM3
#define TIMEOUT_TIMER TIM2
// 调试开关
// #define RFID_DEBUG
// ==================== 类型定义 ====================
// ==================== 状态枚举 ====================
typedef enum {
RFID_STATE_IDLE = 0, // 空闲:等待第一个上升沿
RFID_STATE_WAIT_SECOND_EDGE, // 等待第二个边沿
RFID_STATE_CHECK_SYNC, // 检查同步头
RFID_STATE_RECEIVE_DATA, // 接收数据
RFID_STATE_COUNT // 状态数量(用于状态转换表结束标记)
} rfid_state_t;
// ==================== 事件枚举 ====================
typedef enum {
RFID_EVT_NONE = 0, // 无事件
RFID_EVT_RISING_EDGE, // 上升沿
RFID_EVT_INTERVAL_256US, // 256μs间隔(合格)
RFID_EVT_INTERVAL_512US, // 512μs间隔(合格)
RFID_EVT_INVALID_INTERVAL, // 不合格间隔(统一事件)
RFID_EVT_SYNC_OK, // 同步头验证成功(内部事件)
RFID_EVT_DATA_OK, // 数据接收完成(内部事件)
RFID_EVT_COUNT // 事件数量
} rfid_event_t;
// ==================== 数据结构 ====================
// 状态转换回调函数类型
typedef void (*rfid_state_callback_t)(uint8_t, uint16_t);
// 状态转换表项
typedef struct {
rfid_state_t current_state; // 当前状态
rfid_event_t event; // 事件
rfid_state_t next_state; // 下一个状态
rfid_state_callback_t callback; // 回调函数
} rfid_state_transition_t;
// 状态机上下文
typedef struct {
rfid_state_t state; // 当前状态
uint16_t last_capture; // 上次捕获值
uint8_t sync_count; // 同步头边沿计数
uint8_t data_bit_count; // 数据位计数
uint8_t half_bit_count; // 半位计数
uint8_t half_bits[128]; // 原始电平缓冲区
uint8_t current_level; // 当前电平
uint8_t last_level; // 上次电平
uint32_t timeout_timer; // 超时计时器
uint8_t sync_complete_flag; // 同步完成标志
uint8_t data_complete_flag; // 数据完成标志
} rfid_sm_context_t;
// RFID数据包结构(用于队列传输)
typedef struct {
uint8_t half_bits[128]; // 半位数据
uint8_t half_bit_count; // 半位数量
uint8_t data_bit_count; // 数据位数量
uint32_t timestamp; // 时间戳
} rfid_data_packet_t;
// ==================== 全局变量声明 ====================
extern QueueHandle_t xRFIDDataQueue; // RFID数据队列(更新为正确名称)
extern uint8_t g_bitResevData; // 数据接收标志
extern rfid_sm_context_t g_sm; // 状态机上下文
// ==================== 函数声明 ====================
// 状态机初始化函数
void rfid_state_machine_init(void);
// 中断处理函数
void TIM3_IRQHandler(void);
void TIM2_IRQHandler(void);
// 状态机处理函数
void process_state_machine(rfid_event_t event, uint8_t current_level, uint16_t interval);
// 状态机重置函数
void rfid_state_machine_reset(void);
// ==================== 回调函数声明 ====================
// 空闲状态回调函数
void on_idle_rising_edge(uint8_t current_level, uint16_t interval);
// 等待第二个边沿状态回调函数
void on_wait_second_256us(uint8_t current_level, uint16_t interval);
// 检查同步头状态回调函数
void on_sync_check_256us(uint8_t current_level, uint16_t interval);
void on_sync_ok(uint8_t current_level, uint16_t interval);
// 接收数据状态回调函数
void on_data_512us(uint8_t current_level, uint16_t interval);
void on_data_256us(uint8_t current_level, uint16_t interval);
// 数据完成处理回调函数
void on_frame_complete(void);
void on_check_sync_invalid (uint8_t current_level, uint16_t interval);
void Time_Caputer_init(void);
void Time_Caputer_start(void);
void Time_Caputer_GPIO_Configuration(void);
void Time_Caputer_NVIC_Configuration(void);
#endif
浙公网安备 33010602011771号