Files
ZhaTianRC/rx/mainbak.c
T
2026-06-27 19:36:53 +08:00

591 lines
19 KiB
C

/**
* 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)
*/
# ifndef CONFIG
# define CONFIG
# include "CONFIG.h"
# endif
#include "NRF24.h"
#include "UART.h"
/* ========================================================================
* 函数声明
* ======================================================================== */
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) {
}
static void GPIO_Init(void) {
}
/* ========================================================================
* 定时器0 - PWM 时基 (4us 中断)
* ======================================================================== */
static void Timer0_Init(void) {
}
/* 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++;
}
}
/* ========================================================================
* 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;
}
/* 读取指定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); /* 内部带隙基准 */
}
/* ========================================================================
* 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;
}
}
/* ========================================================================
* 串口命令解析
* ======================================================================== */
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 / 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 */
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;
/* 读取电池分压 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 */
LED_Update();
}
}