Files
stc32g128k/Drivers/rf.c

401 lines
12 KiB
C
Raw Normal View History

#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 使 Timer0
* @param us
* @note STC32G 24MHz 12T Timer0 1 tick 0.5us (2MHz)
*/
void RF_Delay_us(u16 us)
{
u16 ticks = us * 2;
TL0 = 0;
TH0 = 0;
TR0 = 1; // 启动定时器 0
while (GetTimer0_Safe() < ticks);
TR0 = 0; // 停止定时器 0
}
/**
* @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 ( 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");
}
}
/**
* @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); // 关断射频
}