Files
stc32g128k/Drivers/rf.c

429 lines
14 KiB
C
Raw Normal View History

#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_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));
}
/**
* @brief 线 EV1527
* @param out_addr 20
* @param out_data 4
* @return bit 1-0-
* @note
* 1. (1T高电平 + 31T低电平/ 31 15~48 )
* 2. T = low_time / 31
* 3. 24
* 4. bit raw_h > raw_l 1 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]; // 低电平时间寄存数组
// ====== 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. 自适应决策:组合成地址及数据位 ======
for (i = 0; i < 24; i++)
{
// 比较本位高低电平持续宽度:
// 如果高电平大于低电平,说明宽脉冲在高,判定该位为 1 (3T高+1T低)。
// 否则高电平短,判定为 0 (1T高+3T低)。
if (raw_h[i] > raw_l[i])
{
if (i < 20) addr = (addr << 1) | 1; // 高 20 位写入物理地址
else dat = (dat << 1) | 1; // 低 4 位写入状态码
}
else
{
if (i < 20) addr = (addr << 1);
else dat = (dat << 1);
}
}
*out_addr = addr;
*out_data = dat;
// 串口打印解码最终结果
Uart_SendString("Decoded ADDR: 0x");
Uart_SendHex20(addr);
Uart_SendString(", DATA: 0x");
Uart_SendHex4(dat);
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");
}