Files
stc32g128k/Drivers/rf.c
edisondeng 29194a4f5d 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.
2026-07-31 15:53:15 +08:00

441 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "rf.h"
#include "timer.h"
#include "../App/config.h"
#include "../App/rgb.h"
#include "intrins.h"
// ATR5179 射频前端天线开关控制引脚定义
sbit RF_TX = P2^0; // V1 控制端 (1: 选通天线到发射 TX 路径)
sbit RF_RX = P3^7; // V2 控制端 (1: 选通天线到接收 RX 路径)
// 射频芯片数据与电源控制引脚定义 (根据新版 PCB 引脚对调修正)
sbit RF_TX_DAT = P2^1; // LR690L 发射调制数据输入引脚 (DIN) - 物理连接 Pin 22 (P2.1)
sbit RF_RX_DATA = P3^6; // LR690L 接收解调数据输出引脚 (DATA) - 物理连接 Pin 19 (P3.6)
// 声明外部延时及串口打印函数 (在 system.c 中定义)
extern void Delay_us(u16 us);
extern void Delay_ms(u16 ms);
extern void Uart_SendString(char *s);
extern void Uart_SendHex4(u8 val);
extern void Uart_SendHex8(u8 val);
extern void Uart_SendHex16(u16 val);
extern void Uart_SendHex20(u32 val);
extern void Uart_SendHex32(u32 val);
extern void Uart_SendByte(u8 dat);
extern volatile u16 ms_tick; // 全局毫秒滴答 (0~999 循环),用于半成品帧看门狗超时判断
/**
* @brief 初始化无线射频芯片相关的 GPIO 引脚方向与状态
* @details 同时在此完成 Timer0 自由运行时间戳基准与 P3.6 (RF_RX_DATA) 常态双边沿中断的
* 一次性开机配置,供 RF_HandleEdgeInterrupt() 增量解码状态机全程使用。
*/
void RF_Init(void)
{
// EAXFR = 1 允许访问扩展特殊功能寄存器 (XSFR)
EAXFR = 1;
// 1. 配置 P2.0 (RF_TX) 和 P2.1 (RF_TX_DAT) 为推挽输出模式 (M1=0, M0=1)
P2M1 &= ~((1 << 0) | (1 << 1));
P2M0 |= ((1 << 0) | (1 << 1));
// 2. 配置 P3.7 (RF_RX) 和 P3.5 (SHUT) 为推挽输出模式 (M1=0, M0=1)
// 配置 P3.6 (RF_RX_DATA) 为高阻输入模式 (M1=1, M0=0)以匹配接收解调输入
P3M1 &= ~((1 << 5) | (1 << 7));
P3M1 |= (1 << 6);
P3M0 &= ~(1 << 6);
P3M0 |= ((1 << 5) | (1 << 7));
// DEBUG: 临时去掉 P3.6 内部上拉,测试是否是它干扰了真实信号接收 (isr_jump.asm 向量重定向
// 修好后,即使没有上拉、芯片关闭时引脚悬空乱跳也只是空耗 CPU不会再导致重启可以安全去掉测试)
// P3PU |= 0x40;
// 3. 设置系统默认的初始电平
RF_TX = 0; // 断开发射天线通路
SHUT = 1; // 默认拉高 SHUT使 LR690L 处于休眠关闭状态
RF_RX = 0; // 断开接收天线通路
RF_TX_DAT = 0; // 调制发送数据线置低
// 4. 启动 Timer0 常驻自由运行,作为边沿中断增量解码的时间戳基准 (实现见 Drivers/timer.c)
Timer0_Init();
// 5. P3.6 (RF_RX_DATA) 双边沿中断常态开启 (原来只在 Enter_Low_Power_Sleep 里临时开启,
// 现在改为开机后永久开启,休眠时复用同一路中断做唤醒源,不再需要单独切换)
P3IM1 |= 0x40;
P3IM0 |= 0x40; // 双边沿触发
P3INTF = 0x00; // 清除挂起的中断标志
P3INTE |= 0x40; // 开启 P3.6 中断允许 (全局 EA 由 Timer1_Init() 统一开启)
}
/**
* @brief 配置无线射频收发系统的运行模式与天线切换
* @param mode 运行模式 (0-休眠隔离, 1-接收工作, 2-发射工作)
*/
void RF_SetMode(u8 mode)
{
if (mode == 0) // ====== 模式 0: 休眠隔离模式 (Sleep/Idle) ======
{
SHUT = 1; // 强制拉高 SHUT 引脚,使 LR690L 彻底进入低功耗待机
RF_RX = 0; // 关闭接收天线开关,防止外界电磁杂波串入接收电路
RF_TX = 0; // 关闭发射天线开关
}
else if (mode == 1) // ====== 模式 1: 接收工作模式 (RX Mode) ======
{
SHUT = 0; // 拉低 SHUT 使能 LR690L 芯片,开始解调接收
RF_TX = 0; // 关闭发射开关
RF_RX = 1; // 选通天线到 RX 接收路径,使能接收链路高频放大
}
else if (mode == 2) // ====== 模式 2: 发发射工作模式 (TX Mode) ======
{
SHUT = 1; // 接收机停机,防止发射强信号顶坏接收前端
RF_RX = 0; // 关闭接收开关
RF_TX = 1; // 选通天线到 TX 发射路径,使能天线发射
}
}
/**
* @brief 使用 Timer0 自由运行时间戳实现的高精度微秒延时
* @param us 延时微秒数
* @note 旧版实现会启停复位 Timer0与本文件新增的常驻自由运行用法冲突 (会导致 RX 时间戳永久停摆)
* 改为对运行中的 Timer0 做起止快照比较,纯只读、不影响其自由运行状态。
*/
void RF_Delay_us(u16 us)
{
u32 start = Timer0_GetTimestamp();
u32 wait_ticks = (u32)us * 2UL; // 0.5us/tick
while ((u32)(Timer0_GetTimestamp() - start) < wait_ticks);
}
/* =========================================================================
* DEBUG 实验:验证方案 —— 解码逻辑临时切回已验证工作的轮询版本,
* P3.6 边沿中断只做纯计数,不参与解码。轮询每次解码成功时,把"解码开始
* 前"和"解码成功后"的中断边沿计数快照打印出来,跟 EV1527 协议理论边沿数
* (同步头 2 个 + 24 位数据 × 每位 2 个 = 50 个) 对比,用来验证:"轮询解码
* 成功的这段时间里,真实硬件边沿次数是否稳定、是否符合协议"。
* ========================================================================= */
// 纯计数用的边沿计数器 (由 RF_HandleEdgeInterrupt 递增,不做任何解码状态机处理)
static volatile u32 dbg_isr_edge_count = 0;
/**
* @brief DEBUG: P3.6 边沿中断处理 —— 本实验阶段只做计数,不参与任何解码逻辑
*/
void RF_HandleEdgeInterrupt(void)
{
dbg_isr_edge_count++;
}
/**
* @brief DEBUG: 打印 P3.6 边沿中断纯计数快照 (本实验阶段唯一保留的排查计数器)
*/
void RF_PrintDebugCounters(void)
{
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 DEBUG 对照实验:恢复自 commit d8df5d4 已验证工作的轮询版本实现,
* 解码成功时额外打印解码前后 P3.6 中断边沿计数快照,用于验证边沿中断
* 在一次成功解码期间的实际触发次数是否稳定、是否符合 EV1527 协议理论值 (50)。
*/
bit EV1527_Decode(u32 *out_addr, u8 *out_data)
{
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;
edge_before = dbg_isr_edge_count; // DEBUG: 解码尝试开始前的边沿计数快照
// ====== 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;
}
}
// 捕获引导头高电平时间
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;
}
/**
* @brief 按照 EV1527 协议单次调制发送一帧 24 位射频数据 (Sync + 24bit Data)
*/
void EV1527_TxFrame(u32 addr, u8 dat)
{
u8 i;
u32 tx_val;
// 合并 20 位地址与 4 位数据,成为 24 位完整 EV1527 帧
tx_val = (addr << 4) | (dat & 0x0F);
// 1. 同步头脉冲: 高电平 1T (350us) + 低电平 31T (10850us)
RF_TX_DAT = 1;
RF_Delay_us(350);
RF_TX_DAT = 0;
RF_Delay_us(10850);
// 2. 依次发送 24 个数据位 (MSB First)
for (i = 0; i < 24; i++)
{
if (tx_val & (0x800000UL >> i))
{
// 逻辑 "1": 高电平 3T (1050us) + 低电平 1T (350us)
RF_TX_DAT = 1;
RF_Delay_us(1050);
RF_TX_DAT = 0;
RF_Delay_us(350);
}
else
{
// 逻辑 "0": 高电平 1T (350us) + 低电平 3T (1050us)
RF_TX_DAT = 1;
RF_Delay_us(350);
RF_TX_DAT = 0;
RF_Delay_us(1050);
}
}
}
/**
* @brief 调制发射 25 帧 EV1527 射频同步电平信号以确保接收侧可靠触发
*/
void EV1527_Transmit(u32 addr, u8 dat)
{
u8 r;
bit ea_bak = EA; // 备份并屏蔽全局中断,确保发射高低电平周期的绝对纯净与防抖
EA = 0;
RF_SetMode(2); // 切换为发射状态,接通天线与射频模块通道
Delay_ms(5); // 稍作延时使射频通路稳定
// 连续发射 25 帧以保证接收设备顺利锁定并解码
for (r = 0; r < 25; r++)
{
EV1527_TxFrame(addr, dat);
// 去除帧与帧之间可能导致波形不连续的 Delay_ms
}
RF_TX_DAT = 0; // 结束发射,拉低数据脚
RF_SetMode(1); // 恢复为常态后台接收模式
EA = ea_bak; // 还原全局中断开关状态
}
/**
* @brief RF 收发诊断测试功能 (支持发送与接收监听打印)
*/
void RF_DiagnosticMode(char choice)
{
if (choice == 't')
{
u8 i;
Uart_SendString("=== RF TX Test: Transmitting 20 test frames... ===\r\n");
// 开启发射模式并配置天线开关
RF_SetMode(2);
Delay_ms(5);
for (i = 0; i < 20; i++)
{
// 连续发送测试包,每次发送伴随马达短震及指示灯闪烁
MOTOR = 1;
RGB_Send(0, 150, 0, 0, 150, 0); // 绿光闪烁
EV1527_TxFrame(0x37A86UL, 0x01);
MOTOR = 0;
RGB_Send(0, 0, 0, 0, 0, 0);
Delay_ms(150); // 帧间隔
}
RF_TX_DAT = 0;
RF_SetMode(1); // 重新恢复接收模式
Uart_SendString("[RF] Transmit Done!\r\n");
}
else if (choice == 'r')
{
u16 wait_ms;
u32 rx_addr;
u8 rx_data;
Uart_SendString("=== RF RX Test: Listening for 5 seconds... ===\r\n");
RF_SetMode(1); // 配置进入接收模式并使能天线
Delay_ms(10);
// 5秒的非阻塞监听
for (wait_ms = 0; wait_ms < 5000; wait_ms++)
{
if (EV1527_Decode(&rx_addr, &rx_data))
{
Uart_SendString("[RF] Decoded successfully! Addr: 0x");
Uart_SendHex32(rx_addr);
Uart_SendString(", Cmd/Data: ");
Uart_SendHex8(rx_data);
Uart_SendString("\r\n");
// 收到信号后马达震动并亮青色灯提醒
MOTOR = 1;
RGB_Send(0, 150, 150, 0, 150, 150);
Delay_ms(100);
MOTOR = 0;
RGB_Send(0, 0, 0, 0, 0, 0);
}
Delay_ms(1);
}
Uart_SendString("=== RF RX Test End ===\r\n");
}
}
/**
* @brief 电气回环自检测试 (物理短路 P2.1 与 P3.6 自检)
* @details 用户通过短路 P2.1 和 P3.6 来实现 GPIO 的物理连通性自检
*/
void Loopback_Test(void)
{
u16 match_count = 0;
u16 i;
EAXFR = 1;
RF_SetMode(1); // 开启接收芯片
Delay_ms(100);
Uart_SendString("Starting RF Hardware Loopback Test (P2.1 -> P3.6)...\r\n");
Uart_SendString("Please use a metal tweezers to short-circuit P2.1 (Pin 22) and P3.6 (Pin 19)!\r\n");
for (i = 0; i < 100; i++)
{
RF_TX_DAT = 1;
Delay_us(500);
if (RF_RX_DATA == 1) match_count++;
RF_TX_DAT = 0;
Delay_us(500);
if (RF_RX_DATA == 0) match_count++;
}
Uart_SendString("Loopback Match Count: ");
Uart_SendHex16(match_count);
Uart_SendString("/200\r\n");
if (match_count > 150)
{
Uart_SendString("Result: PASS! Pin P2.1 and P3.6 are electrical connected successfully!\r\n");
}
else
{
Uart_SendString("Result: FAIL! GPIO coupling check failed. Short-circuit the pins and test again.\r\n");
}
RF_SetMode(0); // 关断射频
}