Update RX

This commit is contained in:
2026-06-27 14:44:10 +08:00
parent fc0fd36861
commit b71a35dcd3
8 changed files with 823 additions and 467 deletions
+43 -416
View File
@@ -12,99 +12,16 @@
* TX(P3.1) - UART1 TX / SBUS 输出 (经板上三极管反相)
* RX(P3.0) - UART1 RX / 命令输入
*
* NRF24L01 (件SPI):
* NRF24L01 (件SPI):
* SCK(P1.5) CE(P1.6) IRQ(P1.7) CSN(P5.4) MISO(P1.3) MOSI(P1.4)
*/
#include "STC8_SDCC.H"
# ifndef CONFIG
# define CONFIG
# include "CONFIG.h"
# endif
#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;
#include "UART.h"
/* ========================================================================
* 函数声明
@@ -513,13 +430,27 @@ static void ADC_Init(void) {
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; /* 清除标志 */
/* 读取指定ADC通道 */
static uint16_t ADC_ReadChannel(uint8_t ch) {
ADC_CONTR = (ADC_CONTR & 0xF0) | ch; /* 切换通道 */
__asm nop __endasm; /* 等待通道切换稳定 */
__asm nop __endasm;
ADC_CONTR |= ADC_START; /* 启动转换 */
while (!(ADC_CONTR & ADC_FLAG)); /* 等待完成 */
ADC_CONTR &= ~ADC_FLAG; /* 清除标志 */
return ((uint16_t)ADC_RES << 8) | ADC_RESL;
}
static uint16_t ADC_Read(void) {
return ADC_ReadChannel(0x0B); /* P3.3/ADC11 */
}
/* 读取内部带隙基准电压 (通道14), 用于反算VCC */
/* VCC(mV) = 1190 * 4096 / bandgap_adc */
static uint16_t ADC_ReadBandgap(void) {
return ADC_ReadChannel(0x0E); /* 内部带隙基准 */
}
/* ========================================================================
* IAP/EEPROM 操作
* ======================================================================== */
@@ -701,323 +632,6 @@ static void PWM_SetAllFailsafe(void) {
}
}
/* ========================================================================
* 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();
}
/* ========================================================================
* 串口命令解析
* ======================================================================== */
@@ -1304,8 +918,8 @@ void main(void) {
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[3] = (uint8_t)((bat_voltage_mv / 10) >> 8); /* voltage high (10mV单位) */
telem_frame[4] = (uint8_t)((bat_voltage_mv / 10) & 0xFF); /* voltage low */
telem_frame[5] = 0; /* current high */
telem_frame[6] = 0; /* current low */
telem_frame[7] = 0; /* capacity */
@@ -1370,9 +984,22 @@ void main(void) {
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值, 上位机或飞控自行换算 */
/* 读取电池分压 ADC (P3.3/ADC11) */
uint16_t bat_adc = ADC_Read();
/* 读取内部带隙基准 (通道14), 反算 VCC */
uint16_t bg_adc = ADC_ReadBandgap();
/* VCC(mV) = 1190 * 4096 / bg_adc
* V_bat(mV) = bat_adc * VCC / 4096 * 11 (分压比 1K:10K = 1/11)
* 合并: V_bat(mV) = bat_adc * 1190 * 11 / bg_adc
* = bat_adc * 13090 / bg_adc
*/
if (bg_adc > 0) {
uint32_t tmp = (uint32_t)bat_adc * 13090UL / bg_adc;
bat_voltage_mv = (uint16_t)tmp;
}
}
/* 更新LED */