本模块实现了 SBUS 协议(Futaba SBUS)的解析,用于接收航模遥控器信号。
#include "SBUS.h"
void app_task(void *pvParameters)
{
// 在任务初始化阶段调用(已集成到 app.c)
SBUS_Init();
while(1)
{
// 主循环轮询
SBUS_Poll();
// ...
}
}
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");
}
// 获取油门通道 (假设 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;
// 获取开关状态 (CH17 通常对应遥控器开关)
HIDO_UINT8 switch_state = SBUS_GetDigitalChannel(17); // 0 或 1
if (switch_state == 1)
{
printf("Switch ON\n");
}
else
{
printf("Switch OFF\n");
}
// 检查最近 100ms 内是否收到 SBUS 帧
if (SBUS_IsSignalValid(100) == HIDO_TRUE)
{
printf("SBUS signal OK\n");
}
else
{
printf("SBUS signal LOST (timeout)\n");
// 进入失控保护模式
// ...
}
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);
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 | - |
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);
}
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;
}
}
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);
}
}
}
UART_ADVFEATURE_RXINV_ENABLESBUS_Poll() 应至少以 20Hz 频率调用(当前 app_task 约 74Hz)m_u8Failsafe 标志和 SBUS_IsSignalValid() 超时| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 无法接收数据 | UART4 未正确初始化 | 检查 MX_UART4_Init() 调用顺序 |
| 帧错误率 100% | RX 信号反向设置错误 | 切换 UART_ADVFEATURE_RXINV 状态 |
| 信号超时 | 发射机未开启或距离过远 | 检查遥控器电源和天线 |
| 通道值抖动 | 干扰或接触不良 | 检查接线屏蔽和接地 |
| 部分通道无效 | 发射机通道未激活 | 检查发射机通道配置 |
| DMA 未触发 | DMA 初始化未完成 | 确认 HAL_UART_Receive_DMA() 已调用 |
SBUS 模块 STM32H743
--------- ----------
GND -------> GND
5V -------> 5V (或 VCC)
SBUS -------> UART4_RX (PA1 或根据实际引脚)
void SBUS_CalibrateCenter(uint8_t channel)
{
uint16_t center_value = SBUS_GetChannel(channel);
// 保存到 Flash 或配置文件
Config_SetChannelCenter(channel, center_value);
}
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]);
}
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
维护者:项目团队