debug(rf): revert to polling EV1527_Decode, ISR does pure edge counting
Diagnostic experiment: restore the commit d8df5d4 polling decode
algorithm/thresholds unchanged, while P3.6 ISR now only increments an
edge counter (no decode state machine). Successful decodes print the
edge-count delta over the decode window to compare against the
EV1527 theoretical 50-edges-per-frame, to validate/refute the
edge-interrupt glitch-noise hypothesis.
This commit is contained in:
300
Drivers/rf.c
300
Drivers/rf.c
@@ -45,9 +45,9 @@ void RF_Init(void)
|
||||
P3M0 &= ~(1 << 6);
|
||||
P3M0 |= ((1 << 5) | (1 << 7));
|
||||
|
||||
// 2.1 开启 P3.6 内部上拉:LR690L 在 SHUT=1 (休眠/发射时也会关断接收) 时数据脚为高阻输出,
|
||||
// 若不加上拉会悬空乱跳。P3.6 中断现在常态开启,悬空噪声会引发中断风暴,必须靠上拉钳位。
|
||||
P3PU |= 0x40;
|
||||
// DEBUG: 临时去掉 P3.6 内部上拉,测试是否是它干扰了真实信号接收 (isr_jump.asm 向量重定向
|
||||
// 修好后,即使没有上拉、芯片关闭时引脚悬空乱跳也只是空耗 CPU,不会再导致重启,可以安全去掉测试)
|
||||
// P3PU |= 0x40;
|
||||
|
||||
// 3. 设置系统默认的初始电平
|
||||
RF_TX = 0; // 断开发射天线通路
|
||||
@@ -63,9 +63,7 @@ void RF_Init(void)
|
||||
P3IM1 |= 0x40;
|
||||
P3IM0 |= 0x40; // 双边沿触发
|
||||
P3INTF = 0x00; // 清除挂起的中断标志
|
||||
// DEBUG: 临时屏蔽 P3.6 中断允许,测试是否是 Port3_Isr 触发本身(不管里面执行什么)导致重启,
|
||||
// 定位完成后改回 P3INTE |= 0x40;
|
||||
// P3INTE |= 0x40; // 开启 P3.6 中断允许 (全局 EA 由 Timer1_Init() 统一开启)
|
||||
P3INTE |= 0x40; // 开启 P3.6 中断允许 (全局 EA 由 Timer1_Init() 统一开启)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,182 +106,168 @@ void RF_Delay_us(u16 us)
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
* EV1527 边沿中断增量解码状态机
|
||||
* DEBUG 实验:验证方案 —— 解码逻辑临时切回已验证工作的轮询版本,
|
||||
* P3.6 边沿中断只做纯计数,不参与解码。轮询每次解码成功时,把"解码开始
|
||||
* 前"和"解码成功后"的中断边沿计数快照打印出来,跟 EV1527 协议理论边沿数
|
||||
* (同步头 2 个 + 24 位数据 × 每位 2 个 = 50 个) 对比,用来验证:"轮询解码
|
||||
* 成功的这段时间里,真实硬件边沿次数是否稳定、是否符合协议"。
|
||||
* ========================================================================= */
|
||||
|
||||
// 计时阈值 (单位: tick,0.5us/tick),与原阻塞版 EV1527_Decode 的判定区间保持一致
|
||||
#define RF_SYNC_HIGH_MIN_TICKS (50UL * 2UL) // 50us
|
||||
#define RF_SYNC_HIGH_MAX_TICKS (2500UL * 2UL) // 2500us
|
||||
#define RF_SYNC_LOW_MIN_TICKS (1500UL * 2UL) // 1500us
|
||||
#define RF_SYNC_LOW_MAX_TICKS (60000UL* 2UL) // 60000us
|
||||
#define RF_T_MIN_TICKS (100UL * 2UL) // 100us
|
||||
#define RF_T_MAX_TICKS (800UL * 2UL) // 800us
|
||||
|
||||
#define RF_ISR_STATE_IDLE 0 // 搜索同步头候选高电平
|
||||
#define RF_ISR_STATE_SYNC_SEEN 1 // 已见候选同步高电平,等待其后的低电平确认
|
||||
#define RF_ISR_STATE_COLLECTING 2 // 正在逐位收集 24 位数据
|
||||
|
||||
#define RF_DECODE_TIMEOUT_MS 200 // 半成品帧看门狗超时 (远大于一帧最坏情况约 95ms 的总耗时)
|
||||
|
||||
static volatile u8 rf_isr_state = RF_ISR_STATE_IDLE;
|
||||
static volatile u32 rf_isr_last_edge_ts = 0;
|
||||
static volatile u32 rf_isr_pending_high = 0; // 候选同步头高电平宽度 / 收集阶段暂存的本位高电平宽度
|
||||
static volatile u32 rf_isr_bit_T = 0; // 本帧的基准单位时间 T
|
||||
static volatile u8 rf_isr_bit_index = 0;
|
||||
static volatile u32 rf_isr_addr_acc = 0;
|
||||
static volatile u8 rf_isr_dat_acc = 0;
|
||||
static volatile u16 rf_isr_state_enter_ms = 0;
|
||||
|
||||
// 中断解码出的结果,供 EV1527_Decode() 非阻塞取用
|
||||
static volatile bit rf_decoded_ready = 0;
|
||||
static volatile u32 rf_decoded_addr = 0;
|
||||
static volatile u8 rf_decoded_data = 0;
|
||||
|
||||
static void RF_ResetDecodeState(void)
|
||||
{
|
||||
rf_isr_state = RF_ISR_STATE_IDLE;
|
||||
rf_isr_bit_index = 0;
|
||||
rf_isr_addr_acc = 0;
|
||||
rf_isr_dat_acc = 0;
|
||||
}
|
||||
// 纯计数用的边沿计数器 (由 RF_HandleEdgeInterrupt 递增,不做任何解码状态机处理)
|
||||
static volatile u32 dbg_isr_edge_count = 0;
|
||||
|
||||
/**
|
||||
* @brief P3.6 (RF_RX_DATA) 边沿中断增量解码处理 (由 main.c 的 Port3_Isr 调用)
|
||||
* @details 每次电平跳变调用一次。用本次跳变与上次跳变的时间差,还原刚刚结束的那段电平的宽度,
|
||||
* 驱动一个三态状态机 (空闲搜索 -> 同步头确认 -> 逐位收集) 增量推进解码,
|
||||
* 不在中断内做任何阻塞等待,无论是否解码成功都会在很短时间内返回。
|
||||
* @brief DEBUG: P3.6 边沿中断处理 —— 本实验阶段只做计数,不参与任何解码逻辑
|
||||
*/
|
||||
void RF_HandleEdgeInterrupt(void)
|
||||
{
|
||||
// DEBUG: 临时直接返回,先确认是否是本函数内部逻辑导致的重启,定位完成后删除这行
|
||||
return;
|
||||
|
||||
u32 now = Timer0_GetTimestamp();
|
||||
u32 duration = now - rf_isr_last_edge_ts; // 刚结束那段电平的宽度
|
||||
u8 new_level = RF_RX_DATA; // 跳变后的当前电平 (1: 刚结束的是低电平, 0: 刚结束的是高电平)
|
||||
rf_isr_last_edge_ts = now;
|
||||
|
||||
if (rf_isr_state == RF_ISR_STATE_IDLE)
|
||||
{
|
||||
// 空闲搜索阶段:只关心刚结束的高电平脉宽是否落在同步头候选区间
|
||||
if (new_level == 0 &&
|
||||
duration >= RF_SYNC_HIGH_MIN_TICKS && duration <= RF_SYNC_HIGH_MAX_TICKS)
|
||||
{
|
||||
rf_isr_pending_high = duration;
|
||||
rf_isr_state = RF_ISR_STATE_SYNC_SEEN;
|
||||
rf_isr_state_enter_ms = ms_tick;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rf_isr_state == RF_ISR_STATE_SYNC_SEEN)
|
||||
{
|
||||
// 期望本次为上升沿,duration 为同步头后续低电平宽度
|
||||
if (new_level == 1 &&
|
||||
duration >= RF_SYNC_LOW_MIN_TICKS && duration <= RF_SYNC_LOW_MAX_TICKS &&
|
||||
rf_isr_pending_high >= RF_T_MIN_TICKS && rf_isr_pending_high <= RF_T_MAX_TICKS)
|
||||
{
|
||||
rf_isr_bit_T = rf_isr_pending_high; // 基准单位时间 T 取自同步头高电平宽度
|
||||
rf_isr_bit_index = 0;
|
||||
rf_isr_addr_acc = 0;
|
||||
rf_isr_dat_acc = 0;
|
||||
rf_isr_state = RF_ISR_STATE_COLLECTING;
|
||||
rf_isr_state_enter_ms = ms_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
RF_ResetDecodeState(); // 不满足同步条件,放弃候选,回到空闲搜索
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ====== RF_ISR_STATE_COLLECTING:逐位收集数据 ======
|
||||
if (new_level == 0)
|
||||
{
|
||||
// 高电平刚结束,先暂存宽度,等对应的低电平结束后一起判定这一位
|
||||
rf_isr_pending_high = duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 total = rf_isr_pending_high + duration;
|
||||
if (total < rf_isr_bit_T * 3UL || total > rf_isr_bit_T * 6UL)
|
||||
{
|
||||
RF_ResetDecodeState(); // 单个数据位周期超出 3T~6T 范围,判定畸变,放弃本帧
|
||||
return;
|
||||
}
|
||||
|
||||
if (rf_isr_pending_high > duration * 2UL)
|
||||
{
|
||||
// 高电平明显长于低电平:逻辑 "1"
|
||||
if (rf_isr_bit_index < 20) rf_isr_addr_acc = (rf_isr_addr_acc << 1) | 1;
|
||||
else rf_isr_dat_acc = (rf_isr_dat_acc << 1) | 1;
|
||||
}
|
||||
else if (duration > rf_isr_pending_high * 2UL)
|
||||
{
|
||||
// 低电平明显长于高电平:逻辑 "0"
|
||||
if (rf_isr_bit_index < 20) rf_isr_addr_acc = (rf_isr_addr_acc << 1);
|
||||
else rf_isr_dat_acc = (rf_isr_dat_acc << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RF_ResetDecodeState(); // 电平脉冲比值不合规,放弃本帧
|
||||
return;
|
||||
}
|
||||
|
||||
rf_isr_bit_index++;
|
||||
if (rf_isr_bit_index >= 24)
|
||||
{
|
||||
// 24 位全部收齐,输出解码结果供主循环取用
|
||||
rf_decoded_addr = rf_isr_addr_acc;
|
||||
rf_decoded_data = rf_isr_dat_acc;
|
||||
rf_decoded_ready = 1;
|
||||
RF_ResetDecodeState();
|
||||
}
|
||||
}
|
||||
dbg_isr_edge_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 半成品帧看门狗:若中断状态机卡在同步头确认/数据收集阶段太久 (信号中途被干扰打断),
|
||||
* 超时后强制复位回空闲搜索,防止后续真实信号被误当作"半成品帧的延续"而永远解不出来。
|
||||
* @brief DEBUG: 打印 P3.6 边沿中断纯计数快照 (本实验阶段唯一保留的排查计数器)
|
||||
*/
|
||||
static void RF_CheckDecodeWatchdog(void)
|
||||
void RF_PrintDebugCounters(void)
|
||||
{
|
||||
u16 elapsed;
|
||||
if (rf_isr_state == RF_ISR_STATE_IDLE) {
|
||||
return;
|
||||
}
|
||||
if (ms_tick >= rf_isr_state_enter_ms) {
|
||||
elapsed = ms_tick - rf_isr_state_enter_ms;
|
||||
} else {
|
||||
elapsed = 1000 + ms_tick - rf_isr_state_enter_ms;
|
||||
}
|
||||
if (elapsed > RF_DECODE_TIMEOUT_MS) {
|
||||
RF_ResetDecodeState();
|
||||
Uart_SendString("[RF-DBG] isr_edge_count=");
|
||||
Uart_SendHex32(dbg_isr_edge_count);
|
||||
Uart_SendString("\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取特定引脚电平状态的持续微秒时间
|
||||
* @details 解码算法/阈值恢复自 commit d8df5d4 已验证工作的轮询版本,但测量方式改为对
|
||||
* 常驻自由运行的 Timer0 (Drivers/timer.c) 做快照差值读取,而不是像原始实现那样
|
||||
* 直接停表/清零/重启 TR0——因为现在 Timer0 已经是 RF_Delay_us()/TX 发射计时共用的
|
||||
* 自由运行时间戳源,若在这里停表清零,会导致解码尝试之后紧接的 TX 发射 RF_Delay_us()
|
||||
* 永远等不到时间戳前进而卡死。快照差值法不触碰 TR0/TL0/TH0,与自由运行架构兼容,
|
||||
* 且不影响本次实验要验证的解码算法本身。
|
||||
*/
|
||||
u16 GetPulseDuration(u8 state, u16 timeout_us)
|
||||
{
|
||||
u32 start = Timer0_GetTimestamp();
|
||||
u32 timeout_ticks = (u32)timeout_us * 2UL; // 0.5us/tick
|
||||
|
||||
while (RF_RX_DATA == state)
|
||||
{
|
||||
if ((u32)(Timer0_GetTimestamp() - start) > timeout_ticks)
|
||||
{
|
||||
return 0; // 判定超时,返回 0
|
||||
}
|
||||
}
|
||||
|
||||
return (u16)((Timer0_GetTimestamp() - start) / 2UL); // tick -> us
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 阻塞式检测并解码一个合法的 EV1527 射频信号数据帧
|
||||
* @details 改造后不再自行轮询电平做阻塞测量,真正的解码工作已经在 P3.6 边沿中断
|
||||
* (RF_HandleEdgeInterrupt) 中增量完成;本函数只是非阻塞地检查中断解码结果,
|
||||
* 函数签名与调用方式保持不变,RfMonitorApp/PairApp/RF_DiagnosticMode 均无需改动。
|
||||
* @details DEBUG 对照实验:恢复自 commit d8df5d4 已验证工作的轮询版本实现,
|
||||
* 解码成功时额外打印解码前后 P3.6 中断边沿计数快照,用于验证边沿中断
|
||||
* 在一次成功解码期间的实际触发次数是否稳定、是否符合 EV1527 协议理论值 (50)。
|
||||
*/
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_data)
|
||||
{
|
||||
bit ready;
|
||||
u16 high_time, low_time;
|
||||
u8 i;
|
||||
u32 addr = 0;
|
||||
u8 dat = 0;
|
||||
u16 T;
|
||||
u16 idata raw_h[24];
|
||||
u16 idata raw_l[24];
|
||||
u32 edge_before;
|
||||
|
||||
RF_CheckDecodeWatchdog();
|
||||
edge_before = dbg_isr_edge_count; // DEBUG: 解码尝试开始前的边沿计数快照
|
||||
|
||||
EA = 0; // 与中断互斥,保证 32 位地址与结果标志的原子性读取
|
||||
ready = rf_decoded_ready;
|
||||
if (ready) {
|
||||
*out_addr = rf_decoded_addr;
|
||||
*out_data = rf_decoded_data;
|
||||
rf_decoded_ready = 0;
|
||||
// ====== 1. 同步头引导脉冲捕获 ======
|
||||
{
|
||||
u16 wait_cnt = 0;
|
||||
while (RF_RX_DATA == 1)
|
||||
{
|
||||
Delay_us(5);
|
||||
wait_cnt++;
|
||||
if (wait_cnt > 2000) // 10 毫秒超时保护
|
||||
return 0;
|
||||
}
|
||||
|
||||
wait_cnt = 0;
|
||||
while (RF_RX_DATA == 0)
|
||||
{
|
||||
Delay_us(5);
|
||||
wait_cnt++;
|
||||
if (wait_cnt > 4000) // 20 毫秒超时保护
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EA = 1;
|
||||
|
||||
return ready;
|
||||
// 捕获引导头高电平时间
|
||||
high_time = GetPulseDuration(1, 2500);
|
||||
if (high_time < 50 || high_time > 2500) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 捕获引导头后续的 31T 低电平时间
|
||||
low_time = GetPulseDuration(0, 60000);
|
||||
if (low_time < 1500 || low_time > 60000) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 同步引导脉冲的基准时间 T 计算 (引导脉冲高电平宽度即为 1T)
|
||||
T = high_time;
|
||||
if (T < 100 || T > 800) return 0; // 自适应范围限幅: 100us ~ 800us
|
||||
|
||||
// ====== 2. 依次解析 24 个数据位脉宽 ======
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
raw_h[i] = GetPulseDuration(1, 2000);
|
||||
if (raw_h[i] == 0) return 0;
|
||||
|
||||
raw_l[i] = GetPulseDuration(0, 2000);
|
||||
if (raw_l[i] == 0) return 0;
|
||||
}
|
||||
|
||||
// ====== 3. 双端比值解调判定数据内容 ======
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
u16 total = raw_h[i] + raw_l[i];
|
||||
if (total < T * 3 || total > T * 6) return 0; // 单个数据位周期必须在 3T~6T 之间
|
||||
|
||||
if (raw_h[i] > raw_l[i] * 2)
|
||||
{
|
||||
// 高电平明显长于低电平,代表逻辑 "1"
|
||||
if (i < 20)
|
||||
addr = (addr << 1) | 1;
|
||||
else
|
||||
dat = (dat << 1) | 1;
|
||||
}
|
||||
else if (raw_l[i] > raw_h[i] * 2)
|
||||
{
|
||||
// 低电平明显长于高电平,代表逻辑 "0"
|
||||
if (i < 20)
|
||||
addr = (addr << 1);
|
||||
else
|
||||
dat = (dat << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; // 电平脉冲比值不合规,判定数据帧畸变,解码作废
|
||||
}
|
||||
}
|
||||
|
||||
// 校验无误,输出解调数据,并打印本次解码期间的边沿计数对照
|
||||
{
|
||||
u32 edge_after = dbg_isr_edge_count;
|
||||
Uart_SendString("[RF-ISR-CHECK] edges_before=");
|
||||
Uart_SendHex32(edge_before);
|
||||
Uart_SendString(" edges_after=");
|
||||
Uart_SendHex32(edge_after);
|
||||
Uart_SendString(" delta=");
|
||||
Uart_SendHex32(edge_after - edge_before);
|
||||
Uart_SendString(" (EV1527 理论值=50)\r\n");
|
||||
}
|
||||
|
||||
*out_addr = addr;
|
||||
*out_data = dat;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
22
Drivers/rf.h
22
Drivers/rf.h
@@ -40,20 +40,20 @@ void EV1527_TxFrame(u32 addr, u8 dat);
|
||||
void EV1527_Transmit(u32 addr, u8 dat);
|
||||
|
||||
/**
|
||||
* @brief P3.6 (RF_RX_DATA) 边沿中断增量解码处理,由 main.c 的 Port3_Isr 在每次电平跳变时调用
|
||||
* @details 内部维护一个三态状态机 (空闲搜索 -> 同步头确认 -> 逐位收集),用相邻两次跳变的时间差
|
||||
* 还原刚结束的电平宽度,增量推进 EV1527 解码,凑齐 24 位后把结果写入内部标志供
|
||||
* EV1527_Decode() 非阻塞取用。全程不做任何阻塞等待,适合在中断上下文中调用。
|
||||
* @brief DEBUG 对照实验:P3.6 (RF_RX_DATA) 边沿中断处理,由 main.c 的 Port3_Isr 在每次电平跳变时调用
|
||||
* @details 本实验阶段只做纯边沿计数 (dbg_isr_edge_count++),不参与任何解码逻辑;真正的解码
|
||||
* 已改回 EV1527_Decode() 内的阻塞轮询实现。用于验证:一次成功轮询解码期间,
|
||||
* 真实硬件触发的边沿中断次数是否稳定、是否符合 EV1527 协议理论值 (50)。
|
||||
*/
|
||||
void RF_HandleEdgeInterrupt(void);
|
||||
|
||||
/**
|
||||
* @brief 非阻塞地检查一次 EV1527 射频信号是否已解码完成
|
||||
* @brief 阻塞式检测并解码一个合法的 EV1527 射频信号数据帧 (DEBUG 对照实验:恢复自 commit d8df5d4 的轮询实现)
|
||||
* @param out_addr 输出参数指针:若解码成功,将写入解析得到的 20 位发送地址 (即 24 位帧除去 4 位数据位后的剩余高 20 位)
|
||||
* @param out_data 输出参数指针:若解码成功,将写入解析出的 4 位命令状态数据码 (例如报警/SOS等)
|
||||
* @return bit 1-本次调用取到了一帧新解码出的有效数据;0-当前尚无新结果
|
||||
* @note 真正的解码工作已经在 P3.6 边沿中断 (RF_HandleEdgeInterrupt) 中增量完成,
|
||||
* 本函数只是原子地检查并取出中断解码结果,可在主循环中高频调用而不会造成任何阻塞。
|
||||
* @return bit 1-本次调用解码出一帧有效数据;0-未检测到合法数据帧 (含超时/校验失败)
|
||||
* @note 解码成功时会额外通过串口打印本次解码期间 RF_HandleEdgeInterrupt 的边沿计数快照
|
||||
* (解码前/解码后/差值),用于对照验证。
|
||||
*/
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_data);
|
||||
|
||||
@@ -67,4 +67,10 @@ void RF_DiagnosticMode(char choice);
|
||||
*/
|
||||
void Loopback_Test(void);
|
||||
|
||||
/**
|
||||
* @brief DEBUG: 打印 P3.6 边沿中断纯计数快照 (本实验阶段唯一保留的排查计数器)
|
||||
* @note 排查用,定位问题完成后可以连同 rf.c 里的计数器一起删除
|
||||
*/
|
||||
void RF_PrintDebugCounters(void);
|
||||
|
||||
#endif // __RF_H__
|
||||
|
||||
Reference in New Issue
Block a user