#include "rf.h" #include "../App/config.h" #include "intrins.h" // ATR5179 射频前端天线开关控制引脚定义 sbit RF_TX = P2^0; // V1 控制端 (1: 选通天线到发射 TX 路径) sbit RF_RX = P3^7; // V2 控制端 (1: 选通天线到接收 RX 路径) // 射频芯片数据与电源控制引脚定义 sbit RF_TX_DAT = P3^6; // LT4455 发射调制数据输入引脚 (DIN) sbit RF_RX_DATA = P2^1; // LR690L 接收解调数据输出引脚 (DATA),连接单片机中断管脚 sbit SHUT = P2^2; // LR690L 芯片休眠控制引脚 (1:休眠,0:工作) // 声明外部延时及串口打印函数 (在 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) { // 1. 配置 P2.0 (RF_TX) 和 P2.2 (SHUT) 为推挽输出模式 (M1=0, M0=1) // 配置 P2.1 (RF_RX_DATA) 为准双向口/输入模式 (M1=0, M0=0) P2M1 &= ~((1 << 0) | (1 << 1) | (1 << 2)); P2M0 &= ~(1 << 1); P2M0 |= ((1 << 0) | (1 << 2)); // 2. 配置 P3.6 (RF_TX_DAT) 和 P3.7 (RF_RX) 为推挽输出模式 (M1=0, M0=1) P3M1 &= ~((1 << 6) | (1 << 7)); P3M0 |= ((1 << 6) | (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_RX = 1; // 选通天线切换开关到 RX 路径,连通物理接收天线 RF_TX = 0; // 断开 TX 发射路径,防止回环烧毁前端 } else if (mode == 2) // ====== 模式 2: 射频发射模式 (Tx Mode) ====== { SHUT = 1; // 关闭 LR690L 接收芯片,避免发射大功率波形串入接收机 RF_RX = 0; // 断开接收路径天线 RF_TX = 1; // 选通天线切换开关至 TX 路径,连通物理天线进行发射 } } /** * @brief 按 EV1527 载波规范单次调制发送一帧 24 位无线射频数据 * @param addr 20 位的发射地址编码 * @param dat 4 位的命令状态码 * @details EV1527 是常见的无线编码格式: * - 一个基本脉冲周期设为 T ≈ 320us。 * - 同步头脉冲: 1T 高电平 (320us) + 31T 低电平 (9920us)。 * - 数据位 '1' (逻辑1) 编码: 3T 高电平 (960us) + 1T 低电平 (320us)。 * - 数据位 '0' (逻辑0) 编码: 1T 高电平 (320us) + 3T 低电平 (960us)。 */ void EV1527_TxFrame(u32 addr, u8 dat) { u8 i; // ====== 1. 发送同步引导脉冲 ====== RF_TX_DAT = 1; Delay_us(320); // 1T 高电平 RF_TX_DAT = 0; Delay_us(9920); // 31T 低电平 // ====== 2. 依次调制发送 20 位物理地址码 (高位 MSB 优先发送) ====== for (i = 0; i < 20; i++) { if ((addr >> (19 - i)) & 1) { // 数据 bit 1: 3T高 + 1T低 RF_TX_DAT = 1; Delay_us(960); RF_TX_DAT = 0; Delay_us(320); } else { // 数据 bit 0: 1T高 + 3T低 RF_TX_DAT = 1; Delay_us(320); RF_TX_DAT = 0; Delay_us(960); } } // ====== 3. 依次调制发送 4 位指令状态数据码 (高位 MSB 优先) ====== for (i = 0; i < 4; i++) { if ((dat >> (3 - i)) & 1) { // 数据 bit 1: 3T高 + 1T低 RF_TX_DAT = 1; Delay_us(960); RF_TX_DAT = 0; Delay_us(320); } else { // 数据 bit 0: 1T高 + 3T低 RF_TX_DAT = 1; Delay_us(320); RF_TX_DAT = 0; Delay_us(960); } } } /** * @brief 循环发射多帧无线 EV1527 信号以保证数据通信的完整性 * @param addr 20位源地址 * @param dat 4位命令码 */ void EV1527_Transmit(u32 addr, u8 dat) { u8 r; // 循环发射 25 次相同的射频帧 (累计耗时约 340 毫秒),抵御外界瞬间同频杂波干扰 for (r = 0; r < 25; r++) { EV1527_TxFrame(addr, dat); } } /** * @brief 使用定时器 0 (Timer0) 高精度的测量引脚指定电平状态的持续宽度时间 * @param state 待测电平状态 (1-测量高电平持续宽度, 0-测量低电平持续宽度) * @param timeout_us 最大等待超时微秒数上限,超时自动退出防锁死 * @return u16 最终测量的实际电平持续微秒数。若发生超时则直接返回 0。 */ u16 GetPulseDuration(u8 state, u16 timeout_us) { // 根据系统晶振频率计算在 12T 模式下目标超时的 Timer0 Tick 数值上限 u16 timeout_ticks = (u16)((u32)timeout_us * (MAIN_Fosc / 1000000UL) / 12UL); TL0 = 0; // 定时器 0 计数值清零 TH0 = 0; TR0 = 1; // 启动定时器 0 硬件计数 // 轮询引脚:只要电平仍旧等于目标待测状态,就继续保持循环 while (RF_RX_DATA == state) { // 软件防卡死判定:如果当前计数值超过了设定的最大允许超时 Tick 值 if (GetTimer0_Safe() > timeout_ticks) { TR0 = 0; // 关断定时器 return 0; // 判定超时,返回 0 } } TR0 = 0; // 关断定时器 // 将最终读取的 Timer0 硬件 Tick 数值,重新换算成微秒数返回 (1 Tick = 12 / 24MHz = 0.5us) return (u16)((u32)GetTimer0_Safe() * 12UL / (MAIN_Fosc / 1000000UL)); } #include "../App/xtell.h" // 模拟射频信号全局变量定义 volatile u32 mock_rx_addr = 0; volatile u8 mock_rx_data = 0; volatile bit mock_rf_ready = 0; 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]; // 高电平时间寄存数组 (置于 idata 区) 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; } } // 捕获引导头高电平时间 (放宽测量阈值上限至 2500 微秒) high_time = GetPulseDuration(1, 2500); if (high_time < 50 || high_time > 2500) { if (high_time > 10) { // 剔除高频毛刺噪声,防止调试串口满载 Uart_SendString("Sync H Err: "); Uart_SendHex16(high_time); Uart_SendString("us\r\n"); } return 0; } // 捕获引导头后续的 31T 低电平时间 (设定上限 60 毫秒) low_time = GetPulseDuration(0, 60000); if (low_time < 1500 || low_time > 60000) { Uart_SendString("Sync L Err H="); Uart_SendHex16(high_time); Uart_SendString(" L="); Uart_SendHex16(low_time); Uart_SendString("us\r\n"); return 0; } // 计算低电平与高电平的比值,以检验是否满足 EV1527 的 31:1 特征 { u32 ratio = (u32)low_time / high_time; if (ratio < 15 || ratio > 48) { // 允许 50% 左右的空气无线传输畸变误差 Uart_SendString("Sync Ratio Err H="); Uart_SendHex16(high_time); Uart_SendString(" L="); Uart_SendHex16(low_time); Uart_SendString(" R="); Uart_SendHex16((u16)ratio); Uart_SendString("\r\n"); return 0; } } // 自适应估算出基准脉冲时值 T T = low_time / 31; if (T == 0) T = 1; // 零安全防护 // ====== 2. 依次采集接下来的 24 个数据 bit 脉冲 ====== for (i = 0; i < 24; i++) { u16 wait_cnt = 0; // 等待下一个数据位跳变产生的上升沿 (低电平变高) while (RF_RX_DATA == 0) { Delay_us(5); wait_cnt++; if (wait_cnt > 1000) // 5ms 超时判定,防无线信号中断卡死 { return 0; // 捕获失败 } } // 精密测算本位的高电平与低电平宽度 raw_h[i] = GetPulseDuration(1, 5000); if (raw_h[i] == 0) return 0; // 超时错误直接退出 raw_l[i] = GetPulseDuration(0, 5000); if (raw_l[i] == 0) return 0; } // ====== 3. 串口输出捕获的时序参数 ====== Uart_SendString("Captured: Sync H="); Uart_SendHex16(high_time); Uart_SendString("us, L="); Uart_SendHex16(low_time); Uart_SendString("us, T="); Uart_SendHex16(T); Uart_SendString("us\r\n"); // ====== 4. 自适应决策:组合成 24 位完整射频数据帧 ====== for (i = 0; i < 24; i++) { // 比较本位高低电平持续宽度: // 如果高电平大于低电平,说明宽脉冲在高,判定该位为 1 (3T高+1T低)。 // 否则高电平短,判定为 0 (1T高+3T低)。 if (raw_h[i] > raw_l[i]) { addr = (addr << 1) | 1; // 写入 24 位物理地址与状态数据相结合的最终值 } else { addr = (addr << 1); } } *out_addr = addr; // 输出包含状态数据的 24 位完整射频编码作为传感器唯一 ID *out_data = (u8)(addr & 0x0F); // 输出低 4 位作为指令/状态,保持调用兼容性 // 串口打印解码最终结果 Uart_SendString("Decoded 24bit ADDR: 0x"); Uart_SendHex32(addr); Uart_SendString("\r\n"); return 1; // 成功解析 } /** * @brief 软硬件环路自检回环测试 * @details 将发射引脚置位并同时采样接收引脚,用于测试收发芯片控制连通性。 */ void Loopback_Test(void) { u16 match_count = 0; u16 i; SHUT = 0; // 强行开启接收芯片供电 RF_RX = 1; // 选通天线到 RX RF_TX = 0; // 发送引脚隔离 Delay_ms(100); Uart_SendString("Starting RF Loopback Self-Test...\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! Transmitter is emitting RF, and Receiver is picking it up!\r\n"); } else { Uart_SendString("Result: FAIL! No RF signal detected. Check hardware.\r\n"); } SHUT = 1; // 关闭接收芯片 RF_RX = 0; // 断开接收通道 } /** * @brief 统计接收引脚在 5 秒内的电平翻转次数,用以评估物理噪声污染度或管脚短路 */ void RF_Test_Pin(void) { u8 i; u16 j; u16 transitions = 0; bit last_state = RF_RX_DATA; Uart_SendString("=== RF RX Pin Data Test Start (5 seconds) ===\r\n"); Uart_SendString("SHUT pin state: "); Uart_SendByte(SHUT ? '1' : '0'); Uart_SendString("\r\n"); // 强制设为接收模式 RF_SetMode(1); Delay_ms(100); Uart_SendString("SHUT pin state (after RF_SetMode(1)): "); Uart_SendByte(SHUT ? '1' : '0'); Uart_SendString("\r\n"); Uart_SendString("Please trigger your 433MHz transmitter now...\r\n"); // 连续进行 5 秒的高频电平抖动采样 for (i = 0; i < 5; i++) { transitions = 0; // 1秒循环 for (j = 0; j < 1000; j++) { u8 k; // 每次内循环进行 5 次采样,每次间隔 200us for (k = 0; k < 5; k++) { bit current_state = RF_RX_DATA; if (current_state != last_state) { transitions++; // 统计电平边沿翻转次数 last_state = current_state; } Delay_us(200); } } // 输出本秒的电平跳转总数,若非发射期该数值很大,表明空中有丰富噪声噪底跳变,属接收机正常表现 Uart_SendString("Sampling... Transitions in last 1s: "); Uart_SendHex16(transitions); Uart_SendString(", current pin value: "); Uart_SendByte(RF_RX_DATA ? '1' : '0'); Uart_SendString("\r\n"); } Uart_SendString("=== RF Pin Test End ===\r\n"); }