暂存
This commit is contained in:
392
Drivers/rf.c
392
Drivers/rf.c
@@ -1,4 +1,5 @@
|
||||
#include "rf.h"
|
||||
#include "timer.h"
|
||||
#include "../App/config.h"
|
||||
#include "../App/rgb.h"
|
||||
#include "intrins.h"
|
||||
@@ -14,7 +15,6 @@ sbit RF_RX_DATA = P3^6; // LR690L 接收解调数据输出引脚 (DATA) - 物
|
||||
// 声明外部延时及串口打印函数 (在 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);
|
||||
@@ -22,9 +22,12 @@ 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)
|
||||
{
|
||||
@@ -42,11 +45,27 @@ void RF_Init(void)
|
||||
P3M0 &= ~(1 << 6);
|
||||
P3M0 |= ((1 << 5) | (1 << 7));
|
||||
|
||||
// 2.1 开启 P3.6 内部上拉:LR690L 在 SHUT=1 (休眠/发射时也会关断接收) 时数据脚为高阻输出,
|
||||
// 若不加上拉会悬空乱跳。P3.6 中断现在常态开启,悬空噪声会引发中断风暴,必须靠上拉钳位。
|
||||
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; // 清除挂起的中断标志
|
||||
// DEBUG: 临时屏蔽 P3.6 中断允许,测试是否是 Port3_Isr 触发本身(不管里面执行什么)导致重启,
|
||||
// 定位完成后改回 P3INTE |= 0x40;
|
||||
// P3INTE |= 0x40; // 开启 P3.6 中断允许 (全局 EA 由 Timer1_Init() 统一开启)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,18 +95,195 @@ void RF_SetMode(u8 mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用单片机硬件 Timer0 实现高精度发射电平时延控制
|
||||
* @brief 使用 Timer0 自由运行时间戳实现的高精度微秒延时
|
||||
* @param us 延时微秒数
|
||||
* @note STC32G 在 24MHz 晶振 12T 模式下,Timer0 的 1 tick 正好等于 0.5us (2MHz)
|
||||
* @note 旧版实现会启停复位 Timer0,与本文件新增的常驻自由运行用法冲突 (会导致 RX 时间戳永久停摆),
|
||||
* 改为对运行中的 Timer0 做起止快照比较,纯只读、不影响其自由运行状态。
|
||||
*/
|
||||
void RF_Delay_us(u16 us)
|
||||
{
|
||||
u16 ticks = us * 2;
|
||||
TL0 = 0;
|
||||
TH0 = 0;
|
||||
TR0 = 1; // 启动定时器 0
|
||||
while (GetTimer0_Safe() < ticks);
|
||||
TR0 = 0; // 停止定时器 0
|
||||
u32 start = Timer0_GetTimestamp();
|
||||
u32 wait_ticks = (u32)us * 2UL; // 0.5us/tick
|
||||
while ((u32)(Timer0_GetTimestamp() - start) < wait_ticks);
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
* EV1527 边沿中断增量解码状态机
|
||||
* ========================================================================= */
|
||||
|
||||
// 计时阈值 (单位: tick,0.5us/tick),与原阻塞版 EV1527_Decode 的判定区间保持一致
|
||||
#define RF_SYNC_HIGH_MIN_TICKS (50UL * 2UL) // 50us
|
||||
#define RF_SYNC_HIGH_MAX_TICKS (2500UL * 2UL) // 2500us
|
||||
#define RF_SYNC_LOW_MIN_TICKS (1500UL * 2UL) // 1500us
|
||||
#define RF_SYNC_LOW_MAX_TICKS (60000UL* 2UL) // 60000us
|
||||
#define RF_T_MIN_TICKS (100UL * 2UL) // 100us
|
||||
#define RF_T_MAX_TICKS (800UL * 2UL) // 800us
|
||||
|
||||
#define RF_ISR_STATE_IDLE 0 // 搜索同步头候选高电平
|
||||
#define RF_ISR_STATE_SYNC_SEEN 1 // 已见候选同步高电平,等待其后的低电平确认
|
||||
#define RF_ISR_STATE_COLLECTING 2 // 正在逐位收集 24 位数据
|
||||
|
||||
#define RF_DECODE_TIMEOUT_MS 200 // 半成品帧看门狗超时 (远大于一帧最坏情况约 95ms 的总耗时)
|
||||
|
||||
static volatile u8 rf_isr_state = RF_ISR_STATE_IDLE;
|
||||
static volatile u32 rf_isr_last_edge_ts = 0;
|
||||
static volatile u32 rf_isr_pending_high = 0; // 候选同步头高电平宽度 / 收集阶段暂存的本位高电平宽度
|
||||
static volatile u32 rf_isr_bit_T = 0; // 本帧的基准单位时间 T
|
||||
static volatile u8 rf_isr_bit_index = 0;
|
||||
static volatile u32 rf_isr_addr_acc = 0;
|
||||
static volatile u8 rf_isr_dat_acc = 0;
|
||||
static volatile u16 rf_isr_state_enter_ms = 0;
|
||||
|
||||
// 中断解码出的结果,供 EV1527_Decode() 非阻塞取用
|
||||
static volatile bit rf_decoded_ready = 0;
|
||||
static volatile u32 rf_decoded_addr = 0;
|
||||
static volatile u8 rf_decoded_data = 0;
|
||||
|
||||
static void RF_ResetDecodeState(void)
|
||||
{
|
||||
rf_isr_state = RF_ISR_STATE_IDLE;
|
||||
rf_isr_bit_index = 0;
|
||||
rf_isr_addr_acc = 0;
|
||||
rf_isr_dat_acc = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief P3.6 (RF_RX_DATA) 边沿中断增量解码处理 (由 main.c 的 Port3_Isr 调用)
|
||||
* @details 每次电平跳变调用一次。用本次跳变与上次跳变的时间差,还原刚刚结束的那段电平的宽度,
|
||||
* 驱动一个三态状态机 (空闲搜索 -> 同步头确认 -> 逐位收集) 增量推进解码,
|
||||
* 不在中断内做任何阻塞等待,无论是否解码成功都会在很短时间内返回。
|
||||
*/
|
||||
void RF_HandleEdgeInterrupt(void)
|
||||
{
|
||||
// DEBUG: 临时直接返回,先确认是否是本函数内部逻辑导致的重启,定位完成后删除这行
|
||||
return;
|
||||
|
||||
u32 now = Timer0_GetTimestamp();
|
||||
u32 duration = now - rf_isr_last_edge_ts; // 刚结束那段电平的宽度
|
||||
u8 new_level = RF_RX_DATA; // 跳变后的当前电平 (1: 刚结束的是低电平, 0: 刚结束的是高电平)
|
||||
rf_isr_last_edge_ts = now;
|
||||
|
||||
if (rf_isr_state == RF_ISR_STATE_IDLE)
|
||||
{
|
||||
// 空闲搜索阶段:只关心刚结束的高电平脉宽是否落在同步头候选区间
|
||||
if (new_level == 0 &&
|
||||
duration >= RF_SYNC_HIGH_MIN_TICKS && duration <= RF_SYNC_HIGH_MAX_TICKS)
|
||||
{
|
||||
rf_isr_pending_high = duration;
|
||||
rf_isr_state = RF_ISR_STATE_SYNC_SEEN;
|
||||
rf_isr_state_enter_ms = ms_tick;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rf_isr_state == RF_ISR_STATE_SYNC_SEEN)
|
||||
{
|
||||
// 期望本次为上升沿,duration 为同步头后续低电平宽度
|
||||
if (new_level == 1 &&
|
||||
duration >= RF_SYNC_LOW_MIN_TICKS && duration <= RF_SYNC_LOW_MAX_TICKS &&
|
||||
rf_isr_pending_high >= RF_T_MIN_TICKS && rf_isr_pending_high <= RF_T_MAX_TICKS)
|
||||
{
|
||||
rf_isr_bit_T = rf_isr_pending_high; // 基准单位时间 T 取自同步头高电平宽度
|
||||
rf_isr_bit_index = 0;
|
||||
rf_isr_addr_acc = 0;
|
||||
rf_isr_dat_acc = 0;
|
||||
rf_isr_state = RF_ISR_STATE_COLLECTING;
|
||||
rf_isr_state_enter_ms = ms_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
RF_ResetDecodeState(); // 不满足同步条件,放弃候选,回到空闲搜索
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ====== RF_ISR_STATE_COLLECTING:逐位收集数据 ======
|
||||
if (new_level == 0)
|
||||
{
|
||||
// 高电平刚结束,先暂存宽度,等对应的低电平结束后一起判定这一位
|
||||
rf_isr_pending_high = duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 total = rf_isr_pending_high + duration;
|
||||
if (total < rf_isr_bit_T * 3UL || total > rf_isr_bit_T * 6UL)
|
||||
{
|
||||
RF_ResetDecodeState(); // 单个数据位周期超出 3T~6T 范围,判定畸变,放弃本帧
|
||||
return;
|
||||
}
|
||||
|
||||
if (rf_isr_pending_high > duration * 2UL)
|
||||
{
|
||||
// 高电平明显长于低电平:逻辑 "1"
|
||||
if (rf_isr_bit_index < 20) rf_isr_addr_acc = (rf_isr_addr_acc << 1) | 1;
|
||||
else rf_isr_dat_acc = (rf_isr_dat_acc << 1) | 1;
|
||||
}
|
||||
else if (duration > rf_isr_pending_high * 2UL)
|
||||
{
|
||||
// 低电平明显长于高电平:逻辑 "0"
|
||||
if (rf_isr_bit_index < 20) rf_isr_addr_acc = (rf_isr_addr_acc << 1);
|
||||
else rf_isr_dat_acc = (rf_isr_dat_acc << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RF_ResetDecodeState(); // 电平脉冲比值不合规,放弃本帧
|
||||
return;
|
||||
}
|
||||
|
||||
rf_isr_bit_index++;
|
||||
if (rf_isr_bit_index >= 24)
|
||||
{
|
||||
// 24 位全部收齐,输出解码结果供主循环取用
|
||||
rf_decoded_addr = rf_isr_addr_acc;
|
||||
rf_decoded_data = rf_isr_dat_acc;
|
||||
rf_decoded_ready = 1;
|
||||
RF_ResetDecodeState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 半成品帧看门狗:若中断状态机卡在同步头确认/数据收集阶段太久 (信号中途被干扰打断),
|
||||
* 超时后强制复位回空闲搜索,防止后续真实信号被误当作"半成品帧的延续"而永远解不出来。
|
||||
*/
|
||||
static void RF_CheckDecodeWatchdog(void)
|
||||
{
|
||||
u16 elapsed;
|
||||
if (rf_isr_state == RF_ISR_STATE_IDLE) {
|
||||
return;
|
||||
}
|
||||
if (ms_tick >= rf_isr_state_enter_ms) {
|
||||
elapsed = ms_tick - rf_isr_state_enter_ms;
|
||||
} else {
|
||||
elapsed = 1000 + ms_tick - rf_isr_state_enter_ms;
|
||||
}
|
||||
if (elapsed > RF_DECODE_TIMEOUT_MS) {
|
||||
RF_ResetDecodeState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 阻塞式检测并解码一个合法的 EV1527 射频信号数据帧
|
||||
* @details 改造后不再自行轮询电平做阻塞测量,真正的解码工作已经在 P3.6 边沿中断
|
||||
* (RF_HandleEdgeInterrupt) 中增量完成;本函数只是非阻塞地检查中断解码结果,
|
||||
* 函数签名与调用方式保持不变,RfMonitorApp/PairApp/RF_DiagnosticMode 均无需改动。
|
||||
*/
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_data)
|
||||
{
|
||||
bit ready;
|
||||
|
||||
RF_CheckDecodeWatchdog();
|
||||
|
||||
EA = 0; // 与中断互斥,保证 32 位地址与结果标志的原子性读取
|
||||
ready = rf_decoded_ready;
|
||||
if (ready) {
|
||||
*out_addr = rf_decoded_addr;
|
||||
*out_data = rf_decoded_data;
|
||||
rf_decoded_ready = 0;
|
||||
}
|
||||
EA = 1;
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,16 +293,16 @@ 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++)
|
||||
{
|
||||
@@ -137,163 +333,23 @@ 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 收发诊断测试功能 (支持发送与接收监听打印)
|
||||
*/
|
||||
@@ -315,7 +371,7 @@ void RF_DiagnosticMode(char choice)
|
||||
EV1527_TxFrame(0x37A86UL, 0x01);
|
||||
MOTOR = 0;
|
||||
RGB_Send(0, 0, 0, 0, 0, 0);
|
||||
|
||||
|
||||
Delay_ms(150); // 帧间隔
|
||||
}
|
||||
RF_TX_DAT = 0;
|
||||
@@ -327,11 +383,11 @@ void RF_DiagnosticMode(char choice)
|
||||
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++)
|
||||
{
|
||||
@@ -342,7 +398,7 @@ void RF_DiagnosticMode(char choice)
|
||||
Uart_SendString(", Cmd/Data: ");
|
||||
Uart_SendHex8(rx_data);
|
||||
Uart_SendString("\r\n");
|
||||
|
||||
|
||||
// 收到信号后马达震动并亮青色灯提醒
|
||||
MOTOR = 1;
|
||||
RGB_Send(0, 150, 150, 0, 150, 150);
|
||||
@@ -364,29 +420,29 @@ void Loopback_Test(void)
|
||||
{
|
||||
u16 match_count = 0;
|
||||
u16 i;
|
||||
|
||||
|
||||
EAXFR = 1;
|
||||
RF_SetMode(1); // 开启接收芯片
|
||||
Delay_ms(100);
|
||||
|
||||
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");
|
||||
@@ -395,6 +451,6 @@ void Loopback_Test(void)
|
||||
{
|
||||
Uart_SendString("Result: FAIL! GPIO coupling check failed. Short-circuit the pins and test again.\r\n");
|
||||
}
|
||||
|
||||
|
||||
RF_SetMode(0); // 关断射频
|
||||
}
|
||||
|
||||
17
Drivers/rf.h
17
Drivers/rf.h
@@ -40,19 +40,20 @@ void EV1527_TxFrame(u32 addr, u8 dat);
|
||||
void EV1527_Transmit(u32 addr, u8 dat);
|
||||
|
||||
/**
|
||||
* @brief 获取特定引脚电平状态的持续微秒时间
|
||||
* @param state 待检测的电平目标状态 (0-低电平, 1-高电平)
|
||||
* @param timeout_us 最大等待超时上限 (单位: 微秒)
|
||||
* @return u16 最终测得的脉冲宽度时长。如果超出 timeout_us 仍未改变电平,则直接返回超时值。
|
||||
* @brief P3.6 (RF_RX_DATA) 边沿中断增量解码处理,由 main.c 的 Port3_Isr 在每次电平跳变时调用
|
||||
* @details 内部维护一个三态状态机 (空闲搜索 -> 同步头确认 -> 逐位收集),用相邻两次跳变的时间差
|
||||
* 还原刚结束的电平宽度,增量推进 EV1527 解码,凑齐 24 位后把结果写入内部标志供
|
||||
* EV1527_Decode() 非阻塞取用。全程不做任何阻塞等待,适合在中断上下文中调用。
|
||||
*/
|
||||
u16 GetPulseDuration(u8 state, u16 timeout_us);
|
||||
void RF_HandleEdgeInterrupt(void);
|
||||
|
||||
/**
|
||||
* @brief 阻塞式检测并解码一个合法的 EV1527 射频信号数据帧
|
||||
* @brief 非阻塞地检查一次 EV1527 射频信号是否已解码完成
|
||||
* @param out_addr 输出参数指针:若解码成功,将写入解析得到的 20 位发送地址 (即 24 位帧除去 4 位数据位后的剩余高 20 位)
|
||||
* @param out_data 输出参数指针:若解码成功,将写入解析出的 4 位命令状态数据码 (例如报警/SOS等)
|
||||
* @return bit 1-成功解析出一帧有效数据;0-当前未捕获到合法脉冲或校验失败
|
||||
* @note 此函数通过对 P3.6 (RF_RX_DATA) 输入脉冲宽度进行软件精密测量,定位同步头,依次采集 24 个数据位,并进行 3 次重复性去噪校验。
|
||||
* @return bit 1-本次调用取到了一帧新解码出的有效数据;0-当前尚无新结果
|
||||
* @note 真正的解码工作已经在 P3.6 边沿中断 (RF_HandleEdgeInterrupt) 中增量完成,
|
||||
* 本函数只是原子地检查并取出中断解码结果,可在主循环中高频调用而不会造成任何阻塞。
|
||||
*/
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_data);
|
||||
|
||||
|
||||
94
Drivers/timer.c
Normal file
94
Drivers/timer.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "timer.h"
|
||||
#include "../App/clock.h"
|
||||
|
||||
// 外部引用的全局滴答/标志变量 (在 main.c 中定义)
|
||||
extern volatile u16 ms_tick;
|
||||
extern volatile bit alarm_flash_flag;
|
||||
extern volatile u16 key_scan_timer;
|
||||
|
||||
/* =========================================================================
|
||||
* Timer0:自由运行硬件时间戳基准
|
||||
* ========================================================================= */
|
||||
|
||||
// Timer0 溢出次数,扩展 16 位硬件计数为 32 位软件时间戳的高位部分
|
||||
static volatile u16 timer0_ovf_count = 0;
|
||||
|
||||
void Timer0_Init(void)
|
||||
{
|
||||
TMOD &= 0xF0; // Timer0 模式位清零 -> Mode 0 (STC 上为 16 位不停表计数)
|
||||
TL0 = 0;
|
||||
TH0 = 0;
|
||||
ET0 = 1; // 开启 Timer0 溢出中断允许
|
||||
TR0 = 1; // 启动 Timer0 计数,此后永不停止 (全局 EA 由 Timer1_Init() 统一开启)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Timer0 溢出中断服务程序 (每约 32.768ms 触发一次)
|
||||
* @details 只做计数扩展,不做任何耗时操作,保持中断尽量短。
|
||||
*/
|
||||
void Timer0_Isr(void) interrupt 1
|
||||
{
|
||||
timer0_ovf_count++;
|
||||
}
|
||||
|
||||
u32 Timer0_GetTimestamp(void)
|
||||
{
|
||||
u16 ovf1, ovf2;
|
||||
u8 h1, h2, l;
|
||||
do {
|
||||
ovf1 = timer0_ovf_count;
|
||||
h1 = TH0;
|
||||
l = TL0;
|
||||
h2 = TH0;
|
||||
ovf2 = timer0_ovf_count;
|
||||
} while (h1 != h2 || ovf1 != ovf2);
|
||||
return ((u32)ovf1 << 16) | ((u16)h1 << 8) | l;
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
* Timer1:系统 1ms 基准滴答
|
||||
* ========================================================================= */
|
||||
|
||||
// 主循环按键扫描定时标志 (由 1ms 中断置 1,主循环响应清除),定义详见 event.h 的 extern 声明
|
||||
volatile bit key_scan_flag = 0;
|
||||
|
||||
void Timer1_Init(void)
|
||||
{
|
||||
AUXR |= 0x40; // 设定定时器 1 为 1T 模式 (无分频,主频直接输入)
|
||||
TMOD &= 0x0F; // 设置定时器 1 模式寄存器,保留低四位 (定时器0配置)
|
||||
{
|
||||
// 按照系统主频 (MAIN_Fosc) 计算 1ms 对应的重装载值
|
||||
u16 reload = (u16)(65536UL - (MAIN_Fosc / 1000UL));
|
||||
TL1 = (u8)reload; // 载入低 8 位
|
||||
TH1 = (u8)(reload >> 8);// 载入高 8 位
|
||||
}
|
||||
ET1 = 1; // 开启定时器 1 中断允许
|
||||
TR1 = 1; // 启动定时器 1 计数
|
||||
EA = 1; // 开启全局中断允许
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器 1 中断服务程序 (每 1ms 触发一次)
|
||||
* @details 承担系统软时钟计算,并每 10ms 置位主循环按键扫描标志,不直接在中断中进行 ADC 多次采样。
|
||||
*/
|
||||
void Timer1_Isr(void) interrupt 3
|
||||
{
|
||||
// 1ms 递增全局滴答计数器 (0~999 循环),供各 App 的呼吸灯/闪烁/超时等周期性效果使用
|
||||
ms_tick++;
|
||||
if (ms_tick >= 1000) {
|
||||
ms_tick = 0;
|
||||
}
|
||||
|
||||
// 1ms 定时更新软时钟
|
||||
Clock_IncMS();
|
||||
|
||||
// 报警屏幕红边框以 100ms 周期亮灭,进行颜色爆闪指示
|
||||
alarm_flash_flag = (ms_tick / 100) % 2;
|
||||
|
||||
/* 物理按键定时计数 (每 10ms 置位一次标志位) */
|
||||
key_scan_timer++;
|
||||
if (key_scan_timer >= 10) {
|
||||
key_scan_timer = 0; // 重置扫描分频计数器
|
||||
key_scan_flag = 1; // 仅在中断里置起标志位,留待主循环中执行实际读取与消抖
|
||||
}
|
||||
}
|
||||
31
Drivers/timer.h
Normal file
31
Drivers/timer.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
#include "../App/config.h"
|
||||
|
||||
/* ====== Timer0:自由运行硬件时间戳基准 ====== */
|
||||
|
||||
/**
|
||||
* @brief 初始化 Timer0 为常驻自由运行计数器
|
||||
* @details 配置为 Mode 0 (STC 上为 16 位不停表计数),12T 模式下 24MHz 晶振对应 1 tick = 0.5us。
|
||||
* 开机启动后永不停止,配合溢出中断 (Timer0_Isr) 把 16 位硬件计数扩展为 32 位软件时间戳,
|
||||
* 供 RF 边沿中断解码等需要高精度时间差测量的场景使用。
|
||||
*/
|
||||
void Timer0_Init(void);
|
||||
|
||||
/**
|
||||
* @brief 获取以 Timer0 为基准的 32 位自由运行时间戳 (单位: 0.5us tick)
|
||||
* @details 内部处理了读取瞬间恰逢硬件计数器溢出的读数撕裂问题。
|
||||
*/
|
||||
u32 Timer0_GetTimestamp(void);
|
||||
|
||||
/* ====== Timer1:系统 1ms 基准滴答 ====== */
|
||||
|
||||
/**
|
||||
* @brief 初始化 Timer1 定时器,生成系统基准时钟 (1ms 中断)
|
||||
* @details 配置定时器 1 为 16 位自动重装载模式,设定中断周期为 1.0 毫秒,
|
||||
* 开启 Timer1 中断并启动计数,同时在此统一开启全局中断允许 (EA = 1)。
|
||||
*/
|
||||
void Timer1_Init(void);
|
||||
|
||||
#endif // __TIMER_H__
|
||||
Reference in New Issue
Block a user