编辑 | blame | 历史 | 原始文档

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. 初始化

#include "SBUS.h"

void app_task(void *pvParameters)
{
    // 在任务初始化阶段调用(已集成到 app.c)
    SBUS_Init();
    
    while(1)
    {
        // 主循环轮询
        SBUS_Poll();
        // ...
    }
}

2. 获取完整通道数据

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. 获取单个通道值

// 获取油门通道 (假设 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. 获取数字通道

// 获取开关状态 (CH17 通常对应遥控器开关)
HIDO_UINT8 switch_state = SBUS_GetDigitalChannel(17);  // 0 或 1

if (switch_state == 1)
{
    printf("Switch ON\n");
}
else
{
    printf("Switch OFF\n");
}

5. 检查信号有效性

// 检查最近 100ms 内是否收到 SBUS 帧
if (SBUS_IsSignalValid(100) == HIDO_TRUE)
{
    printf("SBUS signal OK\n");
}
else
{
    printf("SBUS signal LOST (timeout)\n");
    // 进入失控保护模式
    // ...
}

6. 获取统计信息

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

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:手动遥控草坪机

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:模式切换(自动/手动)

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:失控保护监控

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);
        }
    }
}

调试与诊断

打印实时通道值

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");
    }
}

信号质量检测

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. 中位校准

void SBUS_CalibrateCenter(uint8_t channel)
{
    uint16_t center_value = SBUS_GetChannel(channel);
    // 保存到 Flash 或配置文件
    Config_SetChannelCenter(channel, center_value);
}

2. 通道映射重定义

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. 指数曲线调整

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
维护者:项目团队