diff --git a/rx/UART.c b/rx/UART.c deleted file mode 100644 index e69de29..0000000 diff --git a/rx/UART.h b/rx/UART.h deleted file mode 100644 index 9fc09ec..0000000 --- a/rx/UART.h +++ /dev/null @@ -1,4 +0,0 @@ -# ifndef CONFIG -# define CONFIG -# include "CONFIG.h" -# endif \ No newline at end of file diff --git a/rx/CONFIG.h b/rx/config.h similarity index 95% rename from rx/CONFIG.h rename to rx/config.h index 847d69d..c5e911e 100644 --- a/rx/CONFIG.h +++ b/rx/config.h @@ -19,12 +19,6 @@ #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字节 */ @@ -87,3 +81,6 @@ static volatile uint8_t uart_cmd_ready = 0; /* 定时器计数 (用于LED闪烁) */ static volatile uint16_t sys_tick = 0; + +void (*code runModel)(void) = PwmModel; +void (*code outputFun)(void) = PwmUpdate; \ No newline at end of file diff --git a/rx/main.c b/rx/main.c index 5d5990e..6cb9bd7 100644 --- a/rx/main.c +++ b/rx/main.c @@ -17,60 +17,57 @@ */ # ifndef CONFIG # define CONFIG -# include "CONFIG.h" +# include "config.h" # endif -#include "NRF24.h" -#include "UART.h" +#include "nrf24.h" +#include "uart.h" -/* ======================================================================== - * 函数声明 - * ======================================================================== */ +void EEPROM_LoadConfig(); +void Init(); -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); +void main(void) { + /* 系统初始化 */ + System_Init(); + GPIO_Init(); + Timer0_Init(); + UART1_Init(); + ADC_Init(); + IAP_Init(); -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); + /* 初始化NRF24L01 */ + NRF24L01_Init(); -static void EEPROM_LoadConfig(void); -static void EEPROM_SaveConfig(void); -static uint8_t EEPROM_IsBound(void); + /* 初始PWM: 中位 */ + PWM_SetAllFailsafe(); -static void LED_SetMode(uint8_t mode); -static void LED_Update(void); + // 从EEPROM加载配置 */ + EEPROM_LoadConfig(); -static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us); -static void PWM_SetAllFailsafe(void); + /* 检测NRF模块 */ + if (!NRF24L01_Check()) { + /* NRF模块未检测到, 设置硬件错误标志, LED双闪 */ + nrf_hw_error = 1; + } -static void UART1_SendByte(uint8_t dat); -static void UART1_SendString(const char *s); -static void UART1_SendStringLen(const char *s, uint8_t len); + while (1) { + /* 处理串口命令 */ + UART1_ProcessCmd(); -static void SBUS_SendFrame(void); -static void SBUS_Init(void); + if (NRF_IRQ == 1) { + // 处理NRF24L01接收数据 + NRF24L01_ProcessRX(); + // 更新输出数据 + outputFun(); + } -static void CRFS_SendFrame(void); -static void CRFS_Init(void); + /* LED状态指示 */ + LED_Update(); + } +} -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) { +void Init() { + // System_Init() /* 切换到内部24MHz IRC */ P_SW2 |= EAXFR; /* 使能访问扩展SFR */ CLKDIV = 0x00; /* 主时钟不分频 */ @@ -80,9 +77,8 @@ static void System_Init(void) { /* 设置内部IRC为24MHz */ IRC24MCR = 0x80; /* 使能内部24MHz IRC */ while (!(IRC24MCR & 0x01)); /* 等待IRC稳定 */ -} - -static void GPIO_Init(void) { + + // GPIO_Init() /* P3.4-P3.7: 推挽输出 (PWM通道) */ P3M0 |= 0xF0; P3M1 &= ~0xF0; @@ -128,13 +124,8 @@ static void GPIO_Init(void) { NRF_CSN = 1; NRF_SCK = 0; NRF_MOSI = 0; -} -/* ======================================================================== - * 定时器0 - PWM 时基 (4us 中断) - * ======================================================================== */ - -static void Timer0_Init(void) { + // Timer_Init() /* 16位自动重载模式, 1T */ TMOD &= ~0x0F; TMOD |= 0x01; /* T0: 16位定时器 */ @@ -146,863 +137,4 @@ static void Timer0_Init(void) { 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; -} - -/* 读取指定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 操作 - * ======================================================================== */ - -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; - } -} - -/* ======================================================================== - * 串口命令解析 - * ======================================================================== */ - -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(); - } -} +} \ No newline at end of file diff --git a/rx/mainbak.c b/rx/mainbak.c new file mode 100644 index 0000000..41118fc --- /dev/null +++ b/rx/mainbak.c @@ -0,0 +1,590 @@ +/** + * 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(); + } +} diff --git a/rx/STC8.H b/rx/src/STC8.H similarity index 100% rename from rx/STC8.H rename to rx/src/STC8.H diff --git a/rx/STC8_SDCC.H b/rx/src/STC8_SDCC.H similarity index 100% rename from rx/STC8_SDCC.H rename to rx/src/STC8_SDCC.H diff --git a/rx/src/crfs.c b/rx/src/crfs.c new file mode 100644 index 0000000..9c0ab34 --- /dev/null +++ b/rx/src/crfs.c @@ -0,0 +1,62 @@ +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; + } +} diff --git a/rx/src/crfs.h b/rx/src/crfs.h new file mode 100644 index 0000000..0118e5d --- /dev/null +++ b/rx/src/crfs.h @@ -0,0 +1,43 @@ +/* ======================================================================== + * 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); +static void CRFS_Init(void); \ No newline at end of file diff --git a/rx/src/eeprom.c b/rx/src/eeprom.c new file mode 100644 index 0000000..0d92c95 --- /dev/null +++ b/rx/src/eeprom.c @@ -0,0 +1,105 @@ +/* ======================================================================== + * 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]); + } +} diff --git a/rx/src/eeprom.h b/rx/src/eeprom.h new file mode 100644 index 0000000..0c24ab2 --- /dev/null +++ b/rx/src/eeprom.h @@ -0,0 +1,12 @@ +# ifndef CONFIG +# define CONFIG +# include "config.h" +# endif + +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 uint8_t EEPROM_IsBound(void); +static void EEPROM_LoadConfig(void); +static void EEPROM_SaveConfig(void); diff --git a/rx/NRF24.c b/rx/src/nrf24.c similarity index 100% rename from rx/NRF24.c rename to rx/src/nrf24.c diff --git a/rx/NRF24.h b/rx/src/nrf24.h similarity index 100% rename from rx/NRF24.h rename to rx/src/nrf24.h diff --git a/rx/src/sbus.c b/rx/src/sbus.c new file mode 100644 index 0000000..1642cf1 --- /dev/null +++ b/rx/src/sbus.c @@ -0,0 +1,59 @@ + +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; + } +} diff --git a/rx/src/sbus.h b/rx/src/sbus.h new file mode 100644 index 0000000..fc67786 --- /dev/null +++ b/rx/src/sbus.h @@ -0,0 +1,8 @@ +/* ======================================================================== + * SBUS 输出 (100kbps 8E2, 与UART1共用TX) + * ======================================================================== + */ + +static void SBUS_Init(void); +static void SBUS_SendFrame(void); +static const uint8_t __code crsf_crc8_tab[256]; diff --git a/rx/src/uart.c b/rx/src/uart.c new file mode 100644 index 0000000..7195946 --- /dev/null +++ b/rx/src/uart.c @@ -0,0 +1,83 @@ +#include "uart.h" + +/* ======================================================================== + * 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_Interrupt(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]); + } +} diff --git a/rx/src/uart.h b/rx/src/uart.h new file mode 100644 index 0000000..935ffd7 --- /dev/null +++ b/rx/src/uart.h @@ -0,0 +1,27 @@ +# ifndef CONFIG +# define CONFIG +# include "CONFIG.h" +# endif + +/* +uart初始化, +uart发送, +uart接收, +uart命令解析, +uart命令响应, +uart接收缓冲区, +uart发送缓冲区, +uart接收索引, +uart命令就绪标志, +uart中断服务程序, +uart波特率设置 +*/ +void UART1_Init(void); + +void UART1_Interrupt(void) __interrupt(4); + +void UART1_Send(void); +void UART1_Receive(void); +void UART1_ParseCommand(void); +void UART1_Response(void); +void UART1_SetBaudRate(void); \ No newline at end of file diff --git a/rx/test_compile.c b/rx/test_compile.c deleted file mode 100644 index 3175388..0000000 --- a/rx/test_compile.c +++ /dev/null @@ -1,11 +0,0 @@ -__sfr __at (0xb2) P3M0; -__sfr __at (0xb1) P3M1; -__sfr __at (0x90) P1; -__sfr __at (0xb0) P3; -__sfr __at (0xc8) P5; -__sbit __at (0x97) P15; -__sbit __at (0xb5) P35; -void main(void) { - P3M0 = 0x00; - P3M1 = 0x00; -}