# SBUS 航模遥控器接收模块使用说明 ## 概述 本模块实现了 SBUS 协议(Futaba SBUS)的解析,用于接收航模遥控器信号。 ### 硬件配置 - **UART**: UART4 (STM32H743) - **波特率**: 100kbps - **格式**: 8E2 (8 数据位, 偶校验, 2 停止位) - **接收模式**: DMA 循环接收 - **信号反向**: 已启用 RX 反向功能(适配 SBUS 反向逻辑) ### 协议规格 - **帧长度**: 25 字节 - **帧头**: 0x0F - **帧尾**: 0x00 - **通道数**: 16 个模拟通道 (11-bit, 0~2047) + 2 个数字通道 (CH17/CH18) - **标志位**: Frame Lost、Failsafe - **帧率**: 约 7~14 ms/帧 (取决于发射机) --- ## API 接口 ### 1. 初始化 ```c #include "SBUS.h" void app_task(void *pvParameters) { // 在任务初始化阶段调用(已集成到 app.c) SBUS_Init(); while(1) { // 主循环轮询 SBUS_Poll(); // ... } } ``` ### 2. 获取完整通道数据 ```c ST_SBUSData sbusData; if (SBUS_GetData(&sbusData) == HIDO_TRUE) { // 成功获取数据(信号有效) printf("CH0: %u, CH1: %u, CH2: %u\n", sbusData.m_au16Channels[0], sbusData.m_au16Channels[1], sbusData.m_au16Channels[2]); // 检查失控保护标志 if (sbusData.m_u8Failsafe) { printf("WARNING: Failsafe activated!\n"); } // 检查帧丢失标志 if (sbusData.m_u8FrameLost) { printf("WARNING: Frame lost!\n"); } // 数字通道 printf("CH17: %u, CH18: %u\n", sbusData.m_u8Ch17, sbusData.m_u8Ch18); } else { // 信号超时或无数据 printf("SBUS signal lost\n"); } ``` ### 3. 获取单个通道值 ```c // 获取油门通道 (假设 CH2 为油门) HIDO_UINT16 throttle = SBUS_GetChannel(2); // 0~2047 // 归一化到 [-1.0, 1.0] float throttle_normalized = (throttle - 1024.0f) / 1024.0f; // 映射到电机速度 (0~100%) uint8_t motor_speed = (throttle * 100) / 2047; ``` ### 4. 获取数字通道 ```c // 获取开关状态 (CH17 通常对应遥控器开关) HIDO_UINT8 switch_state = SBUS_GetDigitalChannel(17); // 0 或 1 if (switch_state == 1) { printf("Switch ON\n"); } else { printf("Switch OFF\n"); } ``` ### 5. 检查信号有效性 ```c // 检查最近 100ms 内是否收到 SBUS 帧 if (SBUS_IsSignalValid(100) == HIDO_TRUE) { printf("SBUS signal OK\n"); } else { printf("SBUS signal LOST (timeout)\n"); // 进入失控保护模式 // ... } ``` ### 6. 获取统计信息 ```c HIDO_UINT32 frameCount, errorCount; SBUS_GetStats(&frameCount, &errorCount); printf("Total frames: %u, Errors: %u (%.2f%%)\n", frameCount, errorCount, (frameCount > 0) ? (errorCount * 100.0f / frameCount) : 0.0f); ``` --- ## 数据结构详解 ### ST_SBUSData ```c typedef struct { HIDO_UINT16 m_au16Channels[16]; // 16 个模拟通道, 范围 0~2047 HIDO_UINT8 m_u8Ch17; // 数字通道 17, 值 0 或 1 HIDO_UINT8 m_u8Ch18; // 数字通道 18, 值 0 或 1 HIDO_UINT8 m_u8FrameLost; // 帧丢失标志 (发射机标记) HIDO_UINT8 m_u8Failsafe; // 失控保护标志 (接收机标记) HIDO_UINT32 m_u32LastUpdateTick; // 最后更新时刻 (HAL_GetTick) HIDO_UINT32 m_u32FrameCount; // 累计接收帧数 HIDO_UINT32 m_u32ErrorCount; // 累计错误帧数 (帧头/帧尾校验失败) } ST_SBUSData; ``` ### 通道映射示例(常见遥控器布局) | 通道 | 常见功能 | 值范围 | 中心值 | |------|----------|--------|--------| | CH0 | 横滚 (Aileron) | 0~2047 | 1024 | | CH1 | 俯仰 (Elevator) | 0~2047 | 1024 | | CH2 | 油门 (Throttle) | 0~2047 | 172 (最低) | | CH3 | 方向 (Rudder) | 0~2047 | 1024 | | CH4 | 辅助开关 1 | 0~2047 | - | | CH5 | 辅助开关 2 | 0~2047 | - | | ... | 其他自定义 | 0~2047 | - | | CH17 | 数字开关 1 | 0/1 | - | | CH18 | 数字开关 2 | 0/1 | - | --- ## 典型应用场景 ### 场景1:手动遥控草坪机 ```c void Manual_Control_Task(void) { ST_SBUSData sbus; if (SBUS_GetData(&sbus) != HIDO_TRUE) { // 信号丢失,停止电机 Motor_Stop(); return; } // 失控保护触发,停止 if (sbus.m_u8Failsafe) { Motor_Stop(); return; } // 提取控制量 (假设 CH1=前进/后退, CH3=左右转向) int16_t forward = (int16_t)sbus.m_au16Channels[1] - 1024; // -1024~+1023 int16_t turn = (int16_t)sbus.m_au16Channels[3] - 1024; // -1024~+1023 // 归一化到 [-100, 100] int8_t forward_cmd = (forward * 100) / 1024; int8_t turn_cmd = (turn * 100) / 1024; // 发送到差速电机控制器 DiffDrive_SetCommand(forward_cmd, turn_cmd); } ``` ### 场景2:模式切换(自动/手动) ```c void Mode_Switch_Task(void) { static uint8_t last_switch = 0; uint8_t current_switch = SBUS_GetDigitalChannel(17); // 检测开关状态变化 if (current_switch != last_switch) { if (current_switch == 1) { // 切换到自动模式 System_SetMode(MODE_AUTO); printf("Switched to AUTO mode\n"); } else { // 切换到手动模式 System_SetMode(MODE_MANUAL); printf("Switched to MANUAL mode\n"); } last_switch = current_switch; } } ``` ### 场景3:失控保护监控 ```c void Failsafe_Monitor_Task(void) { static uint32_t last_valid_tick = 0; if (SBUS_IsSignalValid(200) == HIDO_TRUE) { last_valid_tick = HAL_GetTick(); } else { uint32_t lost_duration = HAL_GetTick() - last_valid_tick; if (lost_duration > 1000) // 信号丢失超过 1 秒 { // 触发紧急停止 Emergency_Stop(); printf("EMERGENCY: SBUS signal lost for %u ms\n", lost_duration); } } } ``` --- ## 调试与诊断 ### 打印实时通道值 ```c void SBUS_Debug_Print(void) { ST_SBUSData sbus; if (SBUS_GetData(&sbus) == HIDO_TRUE) { printf("SBUS Channels:\n"); for (uint8_t i = 0; i < 16; i++) { printf(" CH%02u: %4u", i, sbus.m_au16Channels[i]); if ((i + 1) % 4 == 0) printf("\n"); } printf(" CH17: %u, CH18: %u\n", sbus.m_u8Ch17, sbus.m_u8Ch18); printf(" FrameLost: %u, Failsafe: %u\n", sbus.m_u8FrameLost, sbus.m_u8Failsafe); printf(" Stats: Frames=%u, Errors=%u\n", sbus.m_u32FrameCount, sbus.m_u32ErrorCount); } else { printf("SBUS: No signal\n"); } } ``` ### 信号质量检测 ```c void SBUS_Quality_Check(void) { HIDO_UINT32 frames, errors; SBUS_GetStats(&frames, &errors); if (frames > 1000) // 累积足够样本 { float error_rate = (errors * 100.0f) / frames; if (error_rate > 5.0f) { printf("WARNING: High SBUS error rate: %.2f%%\n", error_rate); printf(" -> Check cable connection\n"); printf(" -> Check RX pin inversion setting\n"); } else { printf("SBUS quality: Good (error rate: %.2f%%)\n", error_rate); } } } ``` --- ## 注意事项 ### 1. 信号反向 - SBUS 协议使用反向逻辑(idle high = 0V, idle low = 3.3V) - STM32H7 UART4 已启用 `UART_ADVFEATURE_RXINV_ENABLE` - 如果收到的数据全是错误帧,检查是否需要禁用反向功能 ### 2. 波特率容差 - SBUS 标准波特率为 100kbps - STM32 内部时钟误差需控制在 ±2% 以内 - 如果帧错误率高,可微调波特率 (99000 或 101000) ### 3. DMA 缓冲区大小 - 当前设置为 128 字节(可容纳 5 帧) - 如果主循环轮询间隔较长(>50ms),建议增大缓冲区 ### 4. 帧率与延迟 - SBUS 帧间隔约 7~14ms - `SBUS_Poll()` 应至少以 20Hz 频率调用(当前 app_task 约 74Hz) - 控制延迟: 采样延迟 + 解析延迟 < 20ms ### 5. 失控保护策略 - 建议同时监控 `m_u8Failsafe` 标志和 `SBUS_IsSignalValid()` 超时 - 失控时立即停止所有运动输出 - 恢复信号后需手动重新使能(防止意外启动) ### 6. 多线程安全 - 当前实现未使用临界区保护 - 如需在 ISR 或其他高优先级任务中访问,需添加互斥锁 --- ## 故障排查 | 问题 | 可能原因 | 解决方案 | |------|----------|----------| | 无法接收数据 | UART4 未正确初始化 | 检查 `MX_UART4_Init()` 调用顺序 | | 帧错误率 100% | RX 信号反向设置错误 | 切换 `UART_ADVFEATURE_RXINV` 状态 | | 信号超时 | 发射机未开启或距离过远 | 检查遥控器电源和天线 | | 通道值抖动 | 干扰或接触不良 | 检查接线屏蔽和接地 | | 部分通道无效 | 发射机通道未激活 | 检查发射机通道配置 | | DMA 未触发 | DMA 初始化未完成 | 确认 `HAL_UART_Receive_DMA()` 已调用 | --- ## 接线参考 ### 标准 SBUS 接口(3 线) ``` SBUS 模块 STM32H743 --------- ---------- GND -------> GND 5V -------> 5V (或 VCC) SBUS -------> UART4_RX (PA1 或根据实际引脚) ``` ### 注意 - SBUS 信号电平为 3.3V TTL(部分模块需要电平转换) - 确保 SBUS 输出端与 STM32 RX 引脚直连(无需上拉/下拉电阻) --- ## 扩展功能建议 ### 1. 中位校准 ```c void SBUS_CalibrateCenter(uint8_t channel) { uint16_t center_value = SBUS_GetChannel(channel); // 保存到 Flash 或配置文件 Config_SetChannelCenter(channel, center_value); } ``` ### 2. 通道映射重定义 ```c typedef enum { RC_AILERON = 0, RC_ELEVATOR = 1, RC_THROTTLE = 2, RC_RUDDER = 3, RC_SWITCH_A = 4, RC_SWITCH_B = 5, } E_RCChannel; uint16_t RC_GetMappedChannel(E_RCChannel ch) { return SBUS_GetChannel(g_channel_map[ch]); } ``` ### 3. 指数曲线调整 ```c int16_t RC_ApplyExpo(int16_t raw_value, float expo_factor) { float normalized = raw_value / 1024.0f; // -1.0 ~ 1.0 float expo = expo_factor * normalized * normalized * normalized + (1 - expo_factor) * normalized; return (int16_t)(expo * 1024.0f); } ``` --- 生成时间:2025-11-13 模块版本:v1.0 维护者:项目团队