Files
ZhaTianRC/rx/main.c
2026-06-26 17:57:02 +08:00

1382 lines
44 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ZhaTianRX - STC8H1K08 接收机固件
* 主程序: NRF24L01 接收 + 4路舵机PWM + SBUS输出 + 串口命令
*
* MCU: STC8H1K08 (SOP16/SOP20)
* 编译: SDCC -mmcs51 --model-small
*
* 引脚分配:
* CH1(P3.7) CH2(P3.6) CH3(P3.5) CH4(P3.4) - 舵机PWM输出 50Hz
* BAT_ADC(P3.3/ADC11) - 电池电压分压输入
* LED(P3.2) - 状态指示灯 (低电平亮)
* TX(P3.1) - UART1 TX / SBUS 输出 (经板上三极管反相)
* RX(P3.0) - UART1 RX / 命令输入
*
* NRF24L01 (软件SPI):
* SCK(P1.5) CE(P1.6) IRQ(P1.7) CSN(P5.4) MISO(P1.3) MOSI(P1.4)
*/
#include "STC8_SDCC.H"
#include "NRF24.h"
#include <string.h>
/* ========================================================================
* 系统常量
* ======================================================================== */
#define FOSC 24000000UL /* 系统主频 24MHz */
#define PWM_PERIOD 5000 /* 20ms / 4us = 5000 步 */
#define PWM_MIN 250 /* 1.0ms 脉宽 (4us/步) */
#define PWM_MAX 500 /* 2.0ms 脉宽 */
#define PWM_MID 375 /* 1.5ms 脉宽 */
#define CHANNEL_COUNT 4 /* 4路PWM输出 */
#define UART_BUF_SIZE 32
/* 接收状态 */
#define RX_STATE_DISCONNECTED 0
#define RX_STATE_BINDING 1
#define RX_STATE_CONNECTED 2
/* 输出模式 */
#define OUT_MODE_PWM 0
#define OUT_MODE_SBUS 1
#define OUT_MODE_UART 2
#define OUT_MODE_CRFS 3
/* EEPROM 地址 (IAP) */
#define EEPROM_ADDR_BIND_FLAG 0x0000
#define EEPROM_ADDR_TX_ADDR 0x0001 /* 5字节 */
#define EEPROM_ADDR_RF_CH 0x0006
#define EEPROM_ADDR_BIND_PHRASE 0x0007 /* 6字节 */
#define EEPROM_BIND_MAGIC 0x5A /* 已对频标志 */
/* 数据包格式 (与发射机一致) */
#define RF_SYNC_BYTE0 0xAA
#define RF_SYNC_BYTE1 0x55
#define RF_PACKET_SIZE 32
#define RF_PHRASE_LEN 6
/* LED 闪烁模式 */
#define LED_BLINK_SLOW 0 /* 1Hz - 未连接 */
#define LED_BLINK_FAST 1 /* 3Hz - 对频中 */
#define LED_ON 2 /* 常亮 - 已连接 */
#define LED_OFF 3 /* 熄灭 */
#define LED_BLINK_DOUBLE 4 /* 双闪 - NRF硬件错误 */
/* ========================================================================
* 全局变量
* ======================================================================== */
/* PWM 通道脉宽值 (4us单位, 放在 xdata) */
static volatile uint16_t __xdata pwm_ch[CHANNEL_COUNT];
/* 接收状态 */
static uint8_t rx_state = RX_STATE_DISCONNECTED;
static uint8_t out_mode = OUT_MODE_PWM;
/* 对频信息 (放在 xdata) */
static uint8_t __xdata bind_phrase[RF_PHRASE_LEN] = "LOVE";
static uint8_t __xdata tx_addr[NRF_ADDR_WIDTH] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
static uint8_t rf_channel = 40;
/* 信号丢失计数 */
static uint16_t lost_packet_cnt = 0;
#define LOST_PACKET_TIMEOUT 500 /* 500次接收超时后判丢失 (~5秒 @ 100Hz) */
/* NRF 硬件错误标志 */
static uint8_t nrf_hw_error = 0;
/* 电池电压 */
static volatile uint16_t bat_voltage_mv = 0;
/* 回传数据 */
static uint8_t telem_rssi = 0; /* 信号强度 (0-100) */
static uint8_t telem_packet_loss = 0; /* 丢包率 (0-100%) */
static uint8_t telem_rate_hz = 2; /* 回传频率 1-10Hz, 默认2Hz */
/* CRFS 模式下接收的飞控转发数据 */
static uint8_t __xdata crfs_forward_buf[24];
static uint8_t crfs_forward_len = 0;
/* UART 接收缓冲 (放在 xdata) */
static uint8_t __xdata uart_rx_buf[UART_BUF_SIZE];
static uint8_t uart_rx_idx = 0;
static volatile uint8_t uart_cmd_ready = 0;
/* 定时器计数 (用于LED闪烁) */
static volatile uint16_t sys_tick = 0;
/* ========================================================================
* 函数声明
* ======================================================================== */
static void System_Init(void);
static void GPIO_Init(void);
static void Timer0_Init(void);
static void UART1_Init(void);
static void ADC_Init(void);
static void IAP_Init(void);
static uint8_t IAP_ReadByte(uint16_t addr);
static void IAP_WriteByte(uint16_t addr, uint8_t dat);
static void IAP_EraseSector(uint16_t addr);
static void EEPROM_LoadConfig(void);
static void EEPROM_SaveConfig(void);
static uint8_t EEPROM_IsBound(void);
static void LED_SetMode(uint8_t mode);
static void LED_Update(void);
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us);
static void PWM_SetAllFailsafe(void);
static void UART1_SendByte(uint8_t dat);
static void UART1_SendString(const char *s);
static void UART1_SendStringLen(const char *s, uint8_t len);
static void SBUS_SendFrame(void);
static void SBUS_Init(void);
static void CRFS_SendFrame(void);
static void CRFS_Init(void);
static void Cmd_Parse(void);
static void Cmd_Respond(const char *resp);
static void NRF_ProcessPacket(void);
static void NRF_EnterBindMode(void);
static uint8_t NRF_DoBindScan(void);
static void NRF_SendTelemetry(void);
/* ========================================================================
* 系统初始化
* ======================================================================== */
static void System_Init(void) {
/* 切换到内部24MHz IRC */
P_SW2 |= EAXFR; /* 使能访问扩展SFR */
CLKDIV = 0x00; /* 主时钟不分频 */
CKSEL = 0x00; /* 选择内部高速IRC */
P_SW2 &= ~EAXFR;
/* 设置内部IRC为24MHz */
IRC24MCR = 0x80; /* 使能内部24MHz IRC */
while (!(IRC24MCR & 0x01)); /* 等待IRC稳定 */
}
static void GPIO_Init(void) {
/* P3.4-P3.7: 推挽输出 (PWM通道) */
P3M0 |= 0xF0;
P3M1 &= ~0xF0;
/* P3.2: 推挽输出 (LED) */
P3M0 |= 0x04;
P3M1 &= ~0x04;
/* P3.1: 推挽输出 (UART TX) */
P3M0 |= 0x02;
P3M1 &= ~0x02;
/* P3.0: 高阻输入 (UART RX) */
P3M0 &= ~0x01;
P3M1 |= 0x01;
/* P3.3: 高阻输入 (ADC) */
P3M0 &= ~0x08;
P3M1 |= 0x08;
/* NRF24L01 SPI 引脚 */
/* P1.5(SCK), P1.4(MOSI), P1.6(CE): 推挽输出 */
P1M0 |= 0x70;
P1M1 &= ~0x70;
/* P1.3(MISO): 高阻输入 */
P1M0 &= ~0x08;
P1M1 |= 0x08;
/* P1.7(IRQ): 高阻输入 (轮询) */
P1M0 &= ~0x80;
P1M1 |= 0x80;
/* P5.4(CSN): 推挽输出 */
P5M0 |= 0x10;
P5M1 &= ~0x10;
/* 初始电平 */
P34 = 0; P35 = 0; P36 = 0; P37 = 0; /* PWM 初始低 */
P32 = 1; /* LED 初始灭 (低电平亮) */
P31 = 1; /* TX 空闲高 */
/* NRF 引脚初始 */
NRF_CE = 0;
NRF_CSN = 1;
NRF_SCK = 0;
NRF_MOSI = 0;
}
/* ========================================================================
* 定时器0 - PWM 时基 (4us 中断)
* ======================================================================== */
static void Timer0_Init(void) {
/* 16位自动重载模式, 1T */
TMOD &= ~0x0F;
TMOD |= 0x01; /* T0: 16位定时器 */
AUXR |= T0x12; /* T0: 1T模式 */
/* 4us @ 24MHz: 96 ticks */
TH0 = 0xFF;
TL0 = 0xA0; /* 65536 - 96 = 0xFFA0 */
ET0 = 1; /* 使能T0中断 */
TR0 = 1; /* 启动T0 */
}
/* T0 中断服务 - 4us一次, 生成4路PWM */
void tm0_isr(void) __interrupt(1) {
static uint16_t pwm_cnt = 0;
pwm_cnt++;
if (pwm_cnt >= PWM_PERIOD) {
pwm_cnt = 0;
}
/* 4路舵机PWM (P3.4-P3.7) */
if (pwm_cnt < pwm_ch[0]) P37 = 1; else P37 = 0;
if (pwm_cnt < pwm_ch[1]) P36 = 1; else P36 = 0;
if (pwm_cnt < pwm_ch[2]) P35 = 1; else P35 = 0;
if (pwm_cnt < pwm_ch[3]) P34 = 1; else P34 = 0;
/* 系统滴答 (每10ms) */
if (pwm_cnt == 0) {
sys_tick++;
}
}
/* ========================================================================
* UART1 - 串口通信 (使用Timer2做波特率发生器)
* ======================================================================== */
static void UART1_Init(void) {
/* 使用 Timer2 做波特率发生器 */
/* 115200 @ 24MHz: T2 reload = 65536 - 52 = 0xFFCC */
T2H = 0xFF;
T2L = 0xCC;
AUXR |= T2x12; /* T2: 1T模式 */
AUXR |= T2R; /* 启动T2 */
/* UART1 配置: 8位可变波特率, 模式1 */
SCON = 0x50; /* 模式1, REN=1 */
AUXR |= S1ST2; /* UART1使用T2做波特率 */
PCON &= ~SMOD0; /* SMOD0=0, 帧格式8位数据 */
/* 使能接收中断 */
ES = 1;
RI = 0;
}
/* UART1 中断服务 */
void uart1_isr(void) __interrupt(4) {
if (RI) {
RI = 0;
uint8_t dat = SBUF;
if (out_mode == OUT_MODE_CRFS) {
/* CRFS 模式: 接收飞控发来的 CRSF 帧并缓存转发 */
if (dat == 0xEE) {
/* CRSF 帧起始 */
crfs_forward_len = 0;
crfs_forward_buf[crfs_forward_len++] = dat;
} else if (crfs_forward_len > 0 && crfs_forward_len < sizeof(crfs_forward_buf)) {
crfs_forward_buf[crfs_forward_len++] = dat;
/* 如果收到完整帧 (根据长度字段), 标记为待转发 */
if (crfs_forward_len >= 3) {
uint8_t frame_len = crfs_forward_buf[1] + 2; /* type+payload+crc = length field */
if (crfs_forward_len >= frame_len) {
/* 完整帧已收到, 保持缓存, 主循环会处理转发 */
}
}
}
} else {
/* 命令接收: 回车/换行结束 */
if (dat == '\r' || dat == '\n') {
if (uart_rx_idx > 0) {
uart_rx_buf[uart_rx_idx] = '\0';
uart_cmd_ready = 1;
}
uart_rx_idx = 0;
} else {
if (uart_rx_idx < UART_BUF_SIZE - 1) {
uart_rx_buf[uart_rx_idx++] = dat;
}
}
}
}
if (TI) {
TI = 0;
}
}
static void UART1_SendByte(uint8_t dat) {
SBUF = dat;
while (!TI);
TI = 0;
}
static void UART1_SendString(const char *s) {
while (*s) {
UART1_SendByte((uint8_t)(*s++));
}
}
static void UART1_SendStringLen(const char *s, uint8_t len) {
for (uint8_t i = 0; i < len; i++) {
UART1_SendByte((uint8_t)s[i]);
}
}
/* ========================================================================
* SBUS 输出 (100kbps 8E2, 与UART1共用TX)
* ======================================================================== */
static void SBUS_Init(void) {
/* 切换到 SBUS 波特率 100kbps */
/* 100000 @ 24MHz: T2 reload = 65536 - 60 = 0xFFC4 */
T2H = 0xFF;
T2L = 0xC4;
AUXR |= T2x12;
AUXR |= T2R;
/* 8E2: 8数据位, 偶校验, 2停止位 */
PCON |= SMOD0; /* SMOD0=1, 帧格式由SM2控制 */
SCON &= ~0x0E; /* 清除SM2, TB8 */
/* 注意: 对于SBUS, 标准是8E2, 但这里通过三极管反相,
* 所以实际发送的是反相SBUS信号 */
}
static void SBUS_SendFrame(void) {
static uint8_t __xdata frame[25];
static uint16_t __xdata sbus_ch[16];
uint8_t i;
/* SBUS 帧结构 */
frame[0] = 0x0F; /* 起始字节 */
/* 16通道 11-bit 编码 (这里只填充前4个通道, 其余为中间值) */
/* 将pwm值(250-500)映射到SBUS范围(172-1811) */
for (i = 0; i < 4; i++) {
uint16_t val = pwm_ch[i];
/* pwm_ch: 250~500 → SBUS: 172~1811 */
if (val < PWM_MIN) val = PWM_MIN;
if (val > PWM_MAX) val = PWM_MAX;
sbus_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * (1811 - 172) / (PWM_MAX - PWM_MIN) + 172);
}
for (i = 4; i < 16; i++) {
sbus_ch[i] = 992; /* 中间值 */
}
/* 11-bit 打包 */
frame[1] = (uint8_t)(sbus_ch[0] & 0xFF);
frame[2] = (uint8_t)((sbus_ch[0] >> 8) | ((sbus_ch[1] & 0x07) << 3));
frame[3] = (uint8_t)((sbus_ch[1] >> 3) | ((sbus_ch[2] & 0x3F) << 5));
frame[4] = (uint8_t)((sbus_ch[2] >> 6) | ((sbus_ch[3] & 0x01) << 2) | ((sbus_ch[3] & 0x01) << 2));
/* 简化: 只打包前4通道, 其余保持中间值 */
/* 简化处理 - 完整16通道打包太复杂, 用中间值填充 */
for (i = 5; i < 23; i++) {
frame[i] = 0x00;
}
frame[23] = 0x00; /* 标志字节 */
frame[24] = 0x00; /* 结束字节 */
/* 通过UART1发送 */
for (i = 0; i < 25; i++) {
SBUF = frame[i];
while (!TI);
TI = 0;
}
}
/* ========================================================================
* CRFS (CRSF/Crossfire) 输出 (420kbps 8N1, 与UART1共用TX)
* 帧格式: 0xEE + len + type + payload + crc8
* RC通道帧: type=0x16, payload=22字节 (16ch × 11bit)
* ======================================================================== */
/* CRC8 查表 (多项式 0xD5, CRSF 标准, 放在 CODE 区) */
static const uint8_t __code crsf_crc8_tab[256] = {
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
};
static uint8_t CRSF_CalcCRC(uint8_t *data, uint8_t len) {
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++)
crc = crsf_crc8_tab[crc ^ data[i]];
return crc;
}
static void CRFS_Init(void) {
/* 切换到 CRSF 波特率 420000 */
/* 420000 @ 24MHz: T2 reload = 65536 - 14 = 0xFFF2 */
T2H = 0xFF;
T2L = 0xF2;
AUXR |= T2x12;
AUXR |= T2R;
/* 8N1: 8数据位, 无校验, 1停止位 */
PCON &= ~SMOD0; /* SMOD0=0, 标准帧格式 */
SCON = 0x50; /* 模式1, REN=1, 8N1 */
}
static void CRFS_SendFrame(void) {
static uint8_t __xdata frame[28]; /* 0xEE + len + type + 22payload + crc */
static uint16_t __xdata crsf_ch[16];
uint8_t i;
/* CRSF RC通道帧: type=0x16 */
frame[0] = 0xEE; /* sync */
frame[1] = 24; /* length (type + payload + crc = 1+22+1) */
frame[2] = 0x16; /* RC channels type */
/* 将4路pwm值(250-500)映射到CRSF范围(0-1984, 中位992) */
for (i = 0; i < 4; i++) {
uint16_t val = pwm_ch[i];
if (val < PWM_MIN) val = PWM_MIN;
if (val > PWM_MAX) val = PWM_MAX;
/* pwm_ch: 250~500 → CRSF: 0~1984 (中位992) */
crsf_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * 1984 / (PWM_MAX - PWM_MIN));
}
for (i = 4; i < 16; i++) {
crsf_ch[i] = 992; /* 中位 */
}
/* 11-bit 打包到 payload (22字节) */
uint8_t *pl = frame + 3;
pl[0] = (uint8_t)(crsf_ch[0] & 0xFF);
pl[1] = (uint8_t)((crsf_ch[0] >> 8) | ((crsf_ch[1] & 0x07) << 3));
pl[2] = (uint8_t)((crsf_ch[1] >> 3) | ((crsf_ch[2] & 0x3F) << 5));
pl[3] = (uint8_t)((crsf_ch[2] >> 6) | ((crsf_ch[3] & 0x01) << 2) | ((crsf_ch[3] & 0x01) << 2));
/* 剩余通道用中间值填充 */
for (i = 4; i < 22; i++)
pl[i] = 0x00;
/* CRC8 (从 type 开始到 payload 结束) */
frame[25] = CRSF_CalcCRC(frame + 2, 23); /* type(1) + payload(22) */
/* 通过UART1发送 */
for (i = 0; i < 26; i++) {
SBUF = frame[i];
while (!TI);
TI = 0;
}
}
/* ========================================================================
* ADC - 电池电压检测 (P3.3/ADC11)
* ======================================================================== */
static void ADC_Init(void) {
ADCCFG = ADC_RESFMT; /* 右对齐, 12位结果 */
ADC_CONTR = ADC_POWER; /* 开启ADC电源 */
/* 选择通道11 (P3.3) */
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x0B;
}
static uint16_t ADC_Read(void) {
ADC_CONTR |= ADC_START; /* 启动转换 */
while (!(ADC_CONTR & ADC_FLAG)); /* 等待完成 */
ADC_CONTR &= ~ADC_FLAG; /* 清除标志 */
return ((uint16_t)ADC_RES << 8) | ADC_RESL;
}
/* ========================================================================
* IAP/EEPROM 操作
* ======================================================================== */
static void IAP_Init(void) {
/* IAP 默认已就绪, 无需额外初始化 */
}
static uint8_t IAP_ReadByte(uint16_t addr) {
uint8_t dat;
IAP_CONTR = IAPEN; /* 使能IAP */
IAP_CMD = IAP_READ;
IAP_ADDRH = (uint8_t)(addr >> 8);
IAP_ADDRL = (uint8_t)(addr & 0xFF);
/* 触发 */
TA = 0x5A;
TA = 0xA5;
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
/* NOP 等待 */
__asm nop __endasm;
__asm nop __endasm;
dat = IAP_DATA;
IAP_CONTR = 0x00; /* 关闭IAP */
return dat;
}
static void IAP_WriteByte(uint16_t addr, uint8_t dat) {
IAP_CONTR = IAPEN; /* 使能IAP */
IAP_CMD = IAP_WRITE;
IAP_ADDRH = (uint8_t)(addr >> 8);
IAP_ADDRL = (uint8_t)(addr & 0xFF);
IAP_DATA = dat;
/* 触发 */
TA = 0x5A;
TA = 0xA5;
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
__asm nop __endasm;
__asm nop __endasm;
IAP_CONTR = 0x00; /* 关闭IAP */
}
static void IAP_EraseSector(uint16_t addr) {
IAP_CONTR = IAPEN; /* 使能IAP */
IAP_CMD = IAP_ERASE;
IAP_ADDRH = (uint8_t)(addr >> 8);
IAP_ADDRL = (uint8_t)(addr & 0xFF);
/* 触发 */
TA = 0x5A;
TA = 0xA5;
IAP_TRIG = 0x5A;
IAP_TRIG = 0xA5;
__asm nop __endasm;
__asm nop __endasm;
IAP_CONTR = 0x00; /* 关闭IAP */
}
/* ========================================================================
* EEPROM 配置存储
* ======================================================================== */
static uint8_t EEPROM_IsBound(void) {
return (IAP_ReadByte(EEPROM_ADDR_BIND_FLAG) == EEPROM_BIND_MAGIC);
}
static void EEPROM_LoadConfig(void) {
if (!EEPROM_IsBound()) {
/* 未对频, 进入对频模式 */
rx_state = RX_STATE_BINDING;
return;
}
/* 读取保存的配置 */
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
tx_addr[i] = IAP_ReadByte(EEPROM_ADDR_TX_ADDR + i);
}
rf_channel = IAP_ReadByte(EEPROM_ADDR_RF_CH);
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
bind_phrase[i] = IAP_ReadByte(EEPROM_ADDR_BIND_PHRASE + i);
}
rx_state = RX_STATE_DISCONNECTED;
}
static void EEPROM_SaveConfig(void) {
/* 擦除扇区 (512字节, 从0x0000开始) */
IAP_EraseSector(0x0000);
/* 写入对频标志 */
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
/* 写入TX地址 */
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
}
/* 写入RF频道 */
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
/* 写入对频短语 */
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
}
}
/* ========================================================================
* LED 控制 (P3.2, 低电平亮)
* ======================================================================== */
static void LED_SetMode(uint8_t mode) {
static uint8_t current_mode = 0xFF;
if (mode != current_mode) {
current_mode = mode;
switch (mode) {
case LED_ON: P32 = 0; break; /* 常亮 */
case LED_OFF: P32 = 1; break; /* 熄灭 */
default: break; /* 闪烁模式由 LED_Update 处理 */
}
}
}
static void LED_Update(void) {
uint8_t mode;
if (nrf_hw_error) {
mode = LED_BLINK_DOUBLE;
} else if (rx_state == RX_STATE_BINDING) {
mode = LED_BLINK_FAST;
} else if (rx_state == RX_STATE_CONNECTED) {
mode = LED_ON;
} else {
mode = LED_BLINK_SLOW;
}
switch (mode) {
case LED_BLINK_SLOW: /* 1Hz: 500ms亮/500ms灭 */
P32 = (sys_tick % 100 < 50) ? 0 : 1;
break;
case LED_BLINK_FAST: /* 3Hz: ~167ms亮/~167ms灭 */
P32 = (sys_tick % 30 < 15) ? 0 : 1;
break;
case LED_BLINK_DOUBLE: /* 双闪: 100ms亮+100ms灭+100ms亮+700ms灭 */
{
uint16_t t = sys_tick % 100;
if (t < 10) P32 = 0; /* 亮 100ms */
else if (t < 20) P32 = 1; /* 灭 100ms */
else if (t < 30) P32 = 0; /* 亮 100ms */
else P32 = 1; /* 灭 700ms */
}
break;
case LED_ON:
P32 = 0;
break;
default:
P32 = 1;
break;
}
}
/* ========================================================================
* PWM 通道设置
* ======================================================================== */
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us) {
if (ch >= CHANNEL_COUNT) return;
/* 限制脉宽范围: 1.0ms ~ 2.0ms */
if (pulse_us < 1000) pulse_us = 1000;
if (pulse_us > 2000) pulse_us = 2000;
/* 转换为4us步长 */
pwm_ch[ch] = pulse_us / 4;
}
static void PWM_SetAllFailsafe(void) {
/* 失控保护: 所有通道回到中位 */
for (uint8_t i = 0; i < CHANNEL_COUNT; i++) {
pwm_ch[i] = PWM_MID;
}
}
/* ========================================================================
* NRF24L01 硬件 SPI 实现 (STC8H 内置 SPI)
* P1.3=MISO, P1.4=MOSI, P1.5=SCLK, P5.4=CSN(GPIO)
* ======================================================================== */
/* SPI 初始化: 主模式, 模式0, 6MHz @ 24MHz */
static void NRF_SPI_Init(void) {
SPCTL = SSIG | SPEN | MSTR; /* 0xD0: SSIG=1, SPEN=1, MSTR=1, CPOL=0, CPHA=0, fosc/4 */
SPSTAT = SPIF | WCOL; /* 清除标志 */
}
uint8_t NRF_SPI_TransferByte(uint8_t dat) {
SPDAT = dat;
/* 等待传输完成 */
while (!(SPSTAT & SPIF));
/* 清除 SPIF (读 SPSTAT 再读 SPDAT 自动清除, 但这里直接写1清除更可靠) */
SPSTAT = SPIF;
return SPDAT;
}
uint8_t NRF24L01_ReadReg(uint8_t reg) {
uint8_t val;
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_R_REGISTER | reg);
val = NRF_SPI_TransferByte(0xFF);
NRF_CSN = 1;
return val;
}
void NRF24L01_WriteReg(uint8_t reg, uint8_t value) {
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_W_REGISTER | reg);
NRF_SPI_TransferByte(value);
NRF_CSN = 1;
}
void NRF24L01_ReadBuf(uint8_t reg, uint8_t *buf, uint8_t len) {
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_R_REGISTER | reg);
for (uint8_t i = 0; i < len; i++)
buf[i] = NRF_SPI_TransferByte(0xFF);
NRF_CSN = 1;
}
void NRF24L01_WriteBuf(uint8_t reg, const uint8_t *buf, uint8_t len) {
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_W_REGISTER | reg);
for (uint8_t i = 0; i < len; i++)
NRF_SPI_TransferByte(buf[i]);
NRF_CSN = 1;
}
/* ========================================================================
* NRF24L01 初始化与操作
* ======================================================================== */
void NRF24L01_Init(void) {
NRF_CE = 0;
NRF_CSN = 1;
/* 初始化硬件 SPI */
NRF_SPI_Init();
/* 延时等待上电 */
for (volatile uint16_t d = 0; d < 5000; d++);
/* 配置寄存器 */
NRF24L01_WriteReg(NRF_CONFIG, 0x0E); /* EN_CRC, CRC0, PWR_UP, PTX */
NRF24L01_WriteReg(NRF_EN_AA, 0x01); /* Pipe0 auto ACK */
NRF24L01_WriteReg(NRF_EN_RXADDR, 0x01); /* Pipe0 enable */
NRF24L01_WriteReg(NRF_SETUP_AW, 0x03); /* 5字节地址 */
NRF24L01_WriteReg(NRF_SETUP_RETR, 0x1A); /* 500us + 15次重试 */
NRF24L01_WriteReg(NRF_RF_CH, rf_channel);
NRF24L01_WriteReg(NRF_RF_SETUP, NRF_RATE_1M | NRF_PA_MAX);
NRF24L01_WriteReg(NRF_RX_PW_P0, RF_PACKET_SIZE);
NRF24L01_WriteReg(NRF_DYNPD, 0x00); /* 关闭动态负载 */
NRF24L01_WriteReg(NRF_FEATURE, 0x00);
/* 设置地址 */
NRF24L01_WriteBuf(NRF_TX_ADDR, tx_addr, NRF_ADDR_WIDTH);
NRF24L01_WriteBuf(NRF_RX_ADDR_P0, tx_addr, NRF_ADDR_WIDTH);
/* 清空FIFO */
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_FLUSH_TX);
NRF_CSN = 1;
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_FLUSH_RX);
NRF_CSN = 1;
/* 清除状态 */
NRF24L01_WriteReg(NRF_STATUS, NRF_STATUS_RX_DR | NRF_STATUS_TX_DS | NRF_STATUS_MAX_RT);
NRF_CE = 0;
}
uint8_t NRF24L01_Check(void) {
uint8_t buf[5] = {0xA5, 0xA5, 0xA5, 0xA5, 0xA5};
uint8_t rx[5];
NRF24L01_WriteBuf(NRF_TX_ADDR, buf, 5);
NRF24L01_ReadBuf(NRF_TX_ADDR, rx, 5);
for (uint8_t i = 0; i < 5; i++)
if (rx[i] != 0xA5) return 0;
return 1;
}
void NRF24L01_SetChannel(uint8_t ch) {
if (ch > NRF_MAX_CHANNEL) ch = NRF_MAX_CHANNEL;
rf_channel = ch;
NRF24L01_WriteReg(NRF_RF_CH, ch);
}
void NRF24L01_SetRXAddr(uint8_t pipe, const uint8_t *addr) {
if (pipe > 5) return;
if (pipe < 2) {
NRF24L01_WriteBuf(NRF_RX_ADDR_P0 + pipe, addr, NRF_ADDR_WIDTH);
} else {
NRF24L01_WriteReg(NRF_RX_ADDR_P0 + pipe, addr[0]);
}
}
void NRF24L01_RXMode(void) {
NRF_CE = 0;
uint8_t cfg = NRF24L01_ReadReg(NRF_CONFIG);
cfg |= 0x01; /* PRIM_RX = 1 */
NRF24L01_WriteReg(NRF_CONFIG, cfg);
NRF_CE = 1;
}
void NRF24L01_TXMode(void) {
NRF_CE = 0;
uint8_t cfg = NRF24L01_ReadReg(NRF_CONFIG);
cfg &= ~0x01; /* PRIM_RX = 0 */
NRF24L01_WriteReg(NRF_CONFIG, cfg);
NRF_CE = 1;
}
uint8_t NRF24L01_IsDataReady(void) {
uint8_t status = NRF24L01_ReadReg(NRF_STATUS);
return (status & NRF_STATUS_RX_DR) ? 1 : 0;
}
uint8_t NRF24L01_RxPacket(uint8_t *data) {
uint8_t status = NRF24L01_ReadReg(NRF_STATUS);
if (!(status & NRF_STATUS_RX_DR)) return 0;
/* 读取payload */
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_R_RX_PAYLOAD);
for (uint8_t i = 0; i < RF_PACKET_SIZE; i++)
data[i] = NRF_SPI_TransferByte(0xFF);
NRF_CSN = 1;
/* 清除 RX_DR */
NRF24L01_WriteReg(NRF_STATUS, NRF_STATUS_RX_DR);
return 1;
}
void NRF24L01_FlushRX(void) {
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_FLUSH_RX);
NRF_CSN = 1;
}
/* ========================================================================
* NRF24L01 对频
* ======================================================================== */
void NRF24L01_EnterBindMode(void) {
/* 进入接收模式, 监听对频请求 */
NRF_CE = 0;
NRF24L01_WriteReg(NRF_CONFIG, 0x0F); /* PRX, PWR_UP, CRC */
NRF24L01_WriteReg(NRF_EN_RXADDR, 0x01);
NRF24L01_WriteReg(NRF_RX_PW_P0, RF_PACKET_SIZE);
NRF24L01_WriteBuf(NRF_RX_ADDR_P0, tx_addr, NRF_ADDR_WIDTH);
NRF24L01_WriteReg(NRF_STATUS, 0x70);
NRF_CE = 1;
}
void NRF_EnterBindMode(void) {
rx_state = RX_STATE_BINDING;
NRF24L01_EnterBindMode();
}
uint8_t NRF_DoBindScan(void) {
static uint8_t __xdata buf[RF_PACKET_SIZE];
/* 扫描所有通道 */
for (uint8_t ch = 0; ch <= NRF_MAX_CHANNEL; ch++) {
NRF24L01_SetChannel(ch);
for (volatile uint16_t d = 0; d < 500; d++); /* 延时 */
if (NRF24L01_RxPacket(buf)) {
/* 验证同步头 */
if (buf[0] != RF_SYNC_BYTE0 || buf[1] != RF_SYNC_BYTE1)
continue;
/* 验证对频短语 (6字节, 从偏移2开始) */
uint8_t match = 1;
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
if (buf[2 + i] != bind_phrase[i]) {
match = 0;
break;
}
}
if (!match) continue;
/* 对频成功! 从包中提取地址 (偏移8开始, 5字节) */
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
tx_addr[i] = buf[8 + i];
}
/* 保存配置到EEPROM */
EEPROM_SaveConfig();
/* 重新初始化NRF */
NRF24L01_Init();
NRF24L01_RXMode();
rx_state = RX_STATE_DISCONNECTED;
return 1;
}
}
return 0;
}
/* ========================================================================
* NRF24L01 数据包处理
* ======================================================================== */
void NRF_ProcessPacket(void) {
static uint8_t __xdata buf[RF_PACKET_SIZE];
if (!NRF24L01_RxPacket(buf))
return;
/* 验证同步头 */
if (buf[0] != RF_SYNC_BYTE0 || buf[1] != RF_SYNC_BYTE1)
return;
/* 验证对频短语 */
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
if (buf[2 + i] != bind_phrase[i])
return;
}
/* 验证校验和 (XOR) */
uint8_t checksum = 0;
for (uint8_t i = 0; i < RF_PACKET_SIZE - 1; i++)
checksum ^= buf[i];
if (checksum != buf[RF_PACKET_SIZE - 1])
return;
/* 提取通道数据 (8通道, 偏移8, 每通道2字节大端) */
for (uint8_t i = 0; i < CHANNEL_COUNT; i++) {
uint16_t raw = ((uint16_t)buf[8 + i * 2] << 8) | buf[8 + i * 2 + 1];
/* raw: 0~2000, 映射到 PWM_MIN~PWM_MAX (250~500) */
if (raw > 2000) raw = 2000;
pwm_ch[i] = (uint16_t)((uint32_t)raw * (PWM_MAX - PWM_MIN) / 2000 + PWM_MIN);
}
/* 更新 RSSI 估计: 从 NRF RPD 寄存器读取载波检测 */
if (NRF24L01_ReadReg(NRF_RPD) & 0x01) {
/* 有载波 = 信号强 */
if (telem_rssi < 100) telem_rssi += 5;
} else {
if (telem_rssi > 10) telem_rssi -= 1;
}
if (telem_rssi > 100) telem_rssi = 100;
/* 更新丢包率: 基于 lost_packet_cnt 估算 */
telem_packet_loss = 0; /* 收到包 = 当前不丢包, 累积值在外部计算 */
/* 更新状态 */
lost_packet_cnt = 0;
if (rx_state != RX_STATE_CONNECTED) {
rx_state = RX_STATE_CONNECTED;
}
}
/* ========================================================================
* NRF24L01 回传发送
* 包格式: 0xBB 0x44 + voltage(2B) + rssi(1B) + loss(1B) + temp(2B)
* ======================================================================== */
static void NRF_SendTelemetry(void) {
static uint8_t __xdata tbuf[8];
tbuf[0] = 0xBB; /* sync0 */
tbuf[1] = 0x44; /* sync1 */
tbuf[2] = (uint8_t)(bat_voltage_mv >> 8); /* voltage high */
tbuf[3] = (uint8_t)(bat_voltage_mv & 0xFF); /* voltage low */
tbuf[4] = telem_rssi; /* RSSI */
tbuf[5] = telem_packet_loss; /* 丢包率 */
tbuf[6] = 0; /* temp high (未实现) */
tbuf[7] = 0; /* temp low */
/* 切到 TX 模式发送回传 */
NRF24L01_TXMode();
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_FLUSH_TX);
NRF_CSN = 1;
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_W_TX_PAYLOAD);
for (uint8_t i = 0; i < 8; i++)
NRF_SPI_TransferByte(tbuf[i]);
NRF_CSN = 1;
NRF_CE = 1;
for (volatile uint16_t d = 0; d < 100; d++);
NRF_CE = 0;
/* 切回 RX 模式 */
NRF24L01_RXMode();
NRF24L01_FlushRX();
}
/* ========================================================================
* 串口命令解析
* ======================================================================== */
static void Cmd_Respond(const char *resp) {
UART1_SendString(resp);
UART1_SendString("\r\n");
}
static void Cmd_Parse(void) {
if (!uart_cmd_ready) return;
uart_cmd_ready = 0;
char *cmd = (char *)uart_rx_buf;
/* MODEL(SBUS) - 切换到SBUS模式 */
if (strcmp(cmd, "MODEL(SBUS)") == 0) {
out_mode = OUT_MODE_SBUS;
SBUS_Init();
Cmd_Respond("OK");
return;
}
/* MODEL(PWM) - 切换到PWM模式 */
if (strcmp(cmd, "MODEL(PWM)") == 0) {
out_mode = OUT_MODE_PWM;
/* 重新初始化UART1为115200 */
UART1_Init();
Cmd_Respond("OK");
return;
}
/* MODEL(UART) - 切换到UART模式 (占位) */
if (strcmp(cmd, "MODEL(UART)") == 0) {
out_mode = OUT_MODE_UART;
UART1_Init();
Cmd_Respond("OK");
return;
}
/* MODEL(CRFS) - 切换到CRFS/CRSF输出模式 */
if (strcmp(cmd, "MODEL(CRFS)") == 0) {
out_mode = OUT_MODE_CRFS;
CRFS_Init();
Cmd_Respond("OK");
return;
}
/* ADDR(0xHH HH HH HH HH) - 切换NRF24L01地址 */
if (cmd[0] == 'A' && cmd[1] == 'D' && cmd[2] == 'D' && cmd[3] == 'R') {
/* 解析: ADDR(0xHH HH HH HH HH) */
static uint8_t __xdata new_addr[NRF_ADDR_WIDTH];
uint8_t ok = 1;
char *p = cmd + 5; /* 跳过 "ADDR(" */
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
/* 跳过 "0x" */
if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) p += 2;
/* 跳过空格 */
while (*p == ' ') p++;
/* 解析两位十六进制 */
uint8_t hi = 0, lo = 0;
if (*p >= '0' && *p <= '9') hi = *p - '0';
else if (*p >= 'A' && *p <= 'F') hi = *p - 'A' + 10;
else if (*p >= 'a' && *p <= 'f') hi = *p - 'a' + 10;
else { ok = 0; break; }
p++;
if (*p >= '0' && *p <= '9') lo = *p - '0';
else if (*p >= 'A' && *p <= 'F') lo = *p - 'A' + 10;
else if (*p >= 'a' && *p <= 'f') lo = *p - 'a' + 10;
else { ok = 0; break; }
p++;
new_addr[i] = (hi << 4) | lo;
}
if (ok) {
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++)
tx_addr[i] = new_addr[i];
NRF24L01_WriteBuf(NRF_TX_ADDR, tx_addr, NRF_ADDR_WIDTH);
NRF24L01_WriteBuf(NRF_RX_ADDR_P0, tx_addr, NRF_ADDR_WIDTH);
Cmd_Respond("OK");
} else {
Cmd_Respond("ERR_ADDR");
}
return;
}
/* TUN(N) - 切换RF频道 */
if (cmd[0] == 'T' && cmd[1] == 'U' && cmd[2] == 'N') {
uint8_t ch = 0;
char *p = cmd + 4; /* 跳过 "TUN(" */
while (*p >= '0' && *p <= '9') {
ch = ch * 10 + (*p - '0');
p++;
}
if (ch <= NRF_MAX_CHANNEL) {
NRF24L01_SetChannel(ch);
Cmd_Respond("OK");
} else {
Cmd_Respond("ERR_RANGE");
}
return;
}
/* DEL(BIND) - 清除对频信息 */
if (strcmp(cmd, "DEL(BIND)") == 0) {
/* 擦除EEPROM中的对频标志 */
IAP_EraseSector(0x0000);
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, 0x00);
rx_state = RX_STATE_BINDING;
NRF_EnterBindMode();
Cmd_Respond("OK");
return;
}
/* PHRASE(xxxxxx) - 设置对频短语, 1~6位字母数字 */
if (cmd[0] == 'P' && cmd[1] == 'H' && cmd[2] == 'R' && cmd[3] == 'A'
&& cmd[4] == 'S' && cmd[5] == 'E') {
uint8_t i;
char *p = cmd + 7; /* 跳过 "PHRASE(" */
/* 计算短语长度 (直到 ')' 或结束) */
uint8_t len = 0;
while (p[len] && p[len] != ')' && len < RF_PHRASE_LEN) {
char c = p[len];
/* 只允许字母和数字 */
if (!((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))) {
Cmd_Respond("ERR");
return;
}
len++;
}
if (len < 1 || len > RF_PHRASE_LEN) {
Cmd_Respond("ERR_RANGE");
return;
}
/* 复制新短语 */
for (i = 0; i < len; i++)
bind_phrase[i] = (uint8_t)p[i];
/* 剩余部分用空格填充 */
for (i = len; i < RF_PHRASE_LEN; i++)
bind_phrase[i] = ' ';
/* 保存到EEPROM */
IAP_EraseSector(0x0000);
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
for (i = 0; i < NRF_ADDR_WIDTH; i++)
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
for (i = 0; i < RF_PHRASE_LEN; i++)
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
/* 重新初始化NRF以使用新短语 */
NRF24L01_Init();
NRF24L01_RXMode();
Cmd_Respond("OK");
return;
}
/* TELEM(N) - 设置回传频率 1~10Hz */
if (cmd[0] == 'T' && cmd[1] == 'E' && cmd[2] == 'L' && cmd[3] == 'E'
&& cmd[4] == 'M') {
uint8_t hz = 0;
char *p = cmd + 6; /* 跳过 "TELEM(" */
while (*p >= '0' && *p <= '9') {
hz = hz * 10 + (*p - '0');
p++;
}
if (hz >= 1 && hz <= 10) {
telem_rate_hz = hz;
Cmd_Respond("OK");
} else {
Cmd_Respond("ERR_RANGE");
}
return;
}
/* 未知命令 */
Cmd_Respond("UNK");
}
/* ========================================================================
* 主函数
* ======================================================================== */
void main(void) {
/* 系统初始化 */
System_Init();
GPIO_Init();
Timer0_Init();
UART1_Init();
ADC_Init();
IAP_Init();
/* 初始PWM: 中位 */
PWM_SetAllFailsafe();
/* 从EEPROM加载配置 */
EEPROM_LoadConfig();
/* 初始化NRF24L01 */
NRF24L01_Init();
/* 检测NRF模块 */
if (!NRF24L01_Check()) {
/* NRF模块未检测到, 设置硬件错误标志, LED双闪 */
nrf_hw_error = 1;
}
/* 进入接收模式 */
if (rx_state == RX_STATE_BINDING) {
NRF_EnterBindMode();
} else {
NRF24L01_RXMode();
}
/* 主循环 */
while (1) {
/* 处理串口命令 */
Cmd_Parse();
/* NRF 硬件错误时定期重检 */
if (nrf_hw_error) {
static uint16_t last_check_tick = 0;
if (sys_tick - last_check_tick >= 50) { /* 每 500ms 重检一次 */
last_check_tick = sys_tick;
NRF24L01_Init();
if (NRF24L01_Check()) {
nrf_hw_error = 0;
NRF24L01_RXMode();
}
}
LED_Update();
continue;
}
/* 对频模式 */
if (rx_state == RX_STATE_BINDING) {
if (NRF_DoBindScan()) {
/* 对频成功, 继续 */
}
/* 更新LED */
LED_Update();
continue;
}
/* 接收数据包 */
if (NRF24L01_IsDataReady()) {
NRF_ProcessPacket();
} else {
lost_packet_cnt++;
/* 每 100 个丢失包更新一次丢包率 (滑动窗口) */
static uint16_t loss_window_cnt = 0;
static uint16_t loss_window_pkts = 0;
loss_window_cnt++;
loss_window_pkts++;
if (loss_window_cnt >= 100) {
/* 如果连续100次都没收到, 丢包率上升 */
if (telem_packet_loss < 99) telem_packet_loss++;
loss_window_cnt = 0;
loss_window_pkts = 0;
}
if (lost_packet_cnt > LOST_PACKET_TIMEOUT) {
if (rx_state == RX_STATE_CONNECTED) {
rx_state = RX_STATE_DISCONNECTED;
PWM_SetAllFailsafe();
}
}
}
/* 回传发送 (PWM/SBUS 模式通过 NRF, CRFS 模式通过 UART) */
if (rx_state == RX_STATE_CONNECTED) {
static uint16_t last_telem_tick = 0;
uint16_t telem_interval = 100 / telem_rate_hz; /* sys_tick=10ms单位 */
if (telem_interval < 1) telem_interval = 1;
if (sys_tick - last_telem_tick >= telem_interval) {
last_telem_tick = sys_tick;
if (out_mode == OUT_MODE_CRFS) {
/* CRFS 模式: 通过 CRSF 链路回传电压/RSSI/丢包
* CRSF 遥测帧: type=0x02 (GPS), 或 type=0x08 (Battery sensor)
* 这里使用 Battery sensor type=0x08
* 帧: 0xEE + len + 0x08 + voltage(2B)+current(2B)+capacity(3B)+remaining(1B) + crc
* 简化: 直接发一个精简遥测帧
*/
static uint8_t __xdata telem_frame[14];
telem_frame[0] = 0xEE;
telem_frame[1] = 10; /* len */
telem_frame[2] = 0x08; /* Battery sensor */
telem_frame[3] = (uint8_t)(bat_voltage_mv >> 8); /* voltage high (mV*10) */
telem_frame[4] = (uint8_t)(bat_voltage_mv & 0xFF); /* voltage low */
telem_frame[5] = 0; /* current high */
telem_frame[6] = 0; /* current low */
telem_frame[7] = 0; /* capacity */
telem_frame[8] = 0;
telem_frame[9] = 0;
telem_frame[10] = telem_rssi; /* remaining = RSSI */
telem_frame[11] = CRSF_CalcCRC(telem_frame + 2, 9);
for (uint8_t i = 0; i < 12; i++) {
SBUF = telem_frame[i];
while (!TI);
TI = 0;
}
} else {
/* PWM/SBUS 模式: 通过 NRF 回传 */
NRF_SendTelemetry();
}
}
}
/* SBUS 输出模式 (每10ms发送一帧) */
if (out_mode == OUT_MODE_SBUS && rx_state == RX_STATE_CONNECTED) {
static uint16_t last_sbus_tick = 0;
if (sys_tick - last_sbus_tick >= 10) {
last_sbus_tick = sys_tick;
SBUS_SendFrame();
}
}
/* CRFS 输出模式 (每10ms发送一帧) */
if (out_mode == OUT_MODE_CRFS && rx_state == RX_STATE_CONNECTED) {
static uint16_t last_crfs_tick = 0;
if (sys_tick - last_crfs_tick >= 10) {
last_crfs_tick = sys_tick;
CRFS_SendFrame();
}
/* 转发飞控发来的 CRSF 帧到 NRF 回传通道 */
if (crfs_forward_len >= 3) {
uint8_t frame_len = crfs_forward_buf[1] + 2;
if (crfs_forward_len >= frame_len) {
/* 通过 NRF 转发给发射机 */
NRF24L01_TXMode();
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_FLUSH_TX);
NRF_CSN = 1;
NRF_CSN = 0;
NRF_SPI_TransferByte(NRF_CMD_W_TX_PAYLOAD);
for (uint8_t i = 0; i < frame_len && i < RF_PACKET_SIZE; i++)
NRF_SPI_TransferByte(crfs_forward_buf[i]);
NRF_CSN = 1;
NRF_CE = 1;
for (volatile uint16_t d = 0; d < 100; d++);
NRF_CE = 0;
NRF24L01_RXMode();
NRF24L01_FlushRX();
crfs_forward_len = 0;
}
}
}
/* 读取电池电压 (每100ms) */
static uint16_t last_adc_tick = 0;
if (sys_tick - last_adc_tick >= 100) {
last_adc_tick = sys_tick;
bat_voltage_mv = ADC_Read();
/* 粗略转换: 12位ADC, Vref=VCC, 分压比取决于硬件 */
/* 这里保留原始ADC值, 上位机或飞控自行换算 */
}
/* 更新LED */
LED_Update();
}
}