#include "rf.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 u16 GetTimer0_Safe(void); 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); /** * @brief 初始化无线射频芯片相关的 GPIO 引脚方向与状态 */ 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)); // 3. 设置系统默认的初始电平 RF_TX = 0; // 断开发射天线通路 SHUT = 1; // 默认拉高 SHUT,使 LR690L 处于休眠关闭状态 RF_RX = 0; // 断开接收天线通路 RF_TX_DAT = 0; // 调制发送数据线置低 } /** * @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 按照 EV1527 协议单次调制发送一帧 24 位射频数据 (Sync + 24bit Data) */ void EV1527_TxFrame(u32 addr, u8 dat) { u8 i; u32 tx_val; // 合并 20 位物理地址与 4 位数据码,构建完整 24 位载波包 tx_val = (addr << 4) | (dat & 0x0F); // 1. 同步头发送:高电平持续 1T (约 350us),低电平持续 31T (约 10850us) RF_TX_DAT = 1; Delay_us(350); RF_TX_DAT = 0; Delay_us(10850); // 2. 依次调制发送 24 位脉宽数据位 for (i = 0; i < 24; i++) { if (tx_val & (0x800000UL >> i)) { // 数据 "1":高电平持续 3T (1050us),低电平持续 1T (350us) RF_TX_DAT = 1; Delay_us(1050); RF_TX_DAT = 0; Delay_us(350); } else { // 数据 "0":高电平持续 1T (350us),低电平持续 3T (1050us) RF_TX_DAT = 1; Delay_us(350); RF_TX_DAT = 0; Delay_us(1050); } } } /** * @brief 连续多次发送 EV1527 射频帧,防止单帧丢失 */ void EV1527_Transmit(u32 addr, u8 dat) { u8 i; RF_SetMode(2); // 切换为发射状态,接通发射开关并隔离接收端 Delay_ms(5); // 稳定天线射频通路 // 循环发送 10 帧,确保接收端至少有 1 帧被无差错捕获 for (i = 0; i < 10; i++) { EV1527_TxFrame(addr, dat); Delay_ms(10); // 帧间保护延时 } RF_TX_DAT = 0; // 归零发送数据线 RF_SetMode(1); // 重新恢复为接收监听常态,以便监测反馈 } /** * @brief 获取特定电平引脚状态的持续微秒时间 (利用 Timer0 硬件测量) */ u16 GetPulseDuration(u8 state, u16 timeout_us) { u16 timeout_ticks; // 强制关闭 Timer0 计数器,并将其计数值清零复位 TR0 = 0; TMOD &= 0xF0; // 设置 Timer0 寄存器为模式 0 (16位自动重载) TL0 = 0x00; TH0 = 0x00; // 换算 16 位定时器所需的最大 ticks 超时值 (在 1T 模式 24MHz 下,1 Tick = 1 / 24M = 0.0416us) // 但此系统 Timer0 默认配置为 12T 模式 (1 Tick = 12 / 24MHz = 0.5us) timeout_ticks = (u16)((u32)timeout_us * (MAIN_Fosc / 1000000UL) / 12UL); TR0 = 1; // 启动 Timer0 硬件计数器 // 根据要捕获的电平状态进行阻塞判断,直到电平发生翻转或计数超时 while (RF_RX_DATA == state) { if (GetTimer0_Safe() > timeout_ticks) { TR0 = 0; return 0; // 判定超时,返回 0 } } TR0 = 0; // 关断定时器 return (u16)((u32)GetTimer0_Safe() * 12UL / (MAIN_Fosc / 1000000UL)); } // 模拟射频信号全局变量定义 volatile u32 mock_rx_addr = 0; volatile u8 mock_rx_data = 0; volatile bit mock_rf_ready = 0; /** * @brief 阻塞式检测并解码一个合法的 EV1527 射频信号数据帧 */ 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]; // 检查模拟射频触发 if (mock_rf_ready) { mock_rf_ready = 0; *out_addr = mock_rx_addr; *out_data = mock_rx_data; return 1; } // ====== 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; // 电平脉冲比值不合规,判定数据帧畸变,解码作废 } } // 校验无误,输出解调数据 *out_addr = addr; *out_data = dat; return 1; } /** * @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"); } }