yincheng.zhong
9 天以前 68c43c5adef03f00836d83b37cb83a294d8b0354
STM32H743/FML/SBUS_ʹÓÃ˵Ã÷.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,412 @@
# 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
维护者:项目团队