SBUS 协议基础认知:核心定位与优势对比
在深入技术细节前,我们先通过对比和基础定义,快速建立对 SBUS 的认知。很多人会把 SBUS 和常见的 UART、PWM 等混淆,这里先明确其核心定位:SBUS 是基于反向电平 UART 的'应用层控制协议',专门用于遥控器与接收机、接收机与飞控/执行器之间的控制信号传输。
一、为什么需要 SBUS?传统方案的痛点
在 SBUS 出现之前,航模和早期无人机主要使用 PWM 或 PPM 协议传输控制信号,我们通过表格直观对比其局限性:
| 传输方案 |
|---|
SBUS 是一种基于反向电平 UART 的串行数字通信协议,广泛应用于无人机、航模和机器人领域。相比传统 PWM 和 PPM 协议,SBUS 具有单线传输多通道、抗干扰能力强、延迟低等优势。详细解析了 SBUS 的物理层参数、电平逻辑转换方案(如 SN74LVC1G240、74HC14)、波特率配置(100kbps, 8E2)及 25 字节帧结构。通过 STM32 代码示例展示了如何初始化 UART 接收中断与 DMA,并提供了完整的通道数据位解析逻辑,帮助开发者实现稳定可靠的遥控信号控制。
在深入技术细节前,我们先通过对比和基础定义,快速建立对 SBUS 的认知。很多人会把 SBUS 和常见的 UART、PWM 等混淆,这里先明确其核心定位:SBUS 是基于反向电平 UART 的'应用层控制协议',专门用于遥控器与接收机、接收机与飞控/执行器之间的控制信号传输。
在 SBUS 出现之前,航模和早期无人机主要使用 PWM 或 PPM 协议传输控制信号,我们通过表格直观对比其局限性:
| 传输方案 |
|---|
| 通道数限制 |
|---|
| 布线复杂度 |
|---|
| 抗干扰能力 |
|---|
| 延迟表现 |
|---|
| 适用场景 |
|---|
| PWM(脉冲宽度调制) | 每个通道需 1 根信号线,常见 4-6 通道,多通道需大量布线 | 极高:N 个通道需 N+1 根线(含 GND),布线杂乱,易拉扯损坏 | 弱:模拟信号易受电磁干扰,导致信号漂移、控制失灵 | 中等:单通道延迟约 10ms,多通道同步性差 | 入门级航模、简单机器人,对通道数和稳定性要求低的场景 |
| PPM(脉冲位置调制) | 单线可传多通道(常见 8 通道以内),通道数仍有限制 | 低:单线传输多通道,布线简洁 | 中等:仍为模拟信号,抗干扰能力优于 PWM,但不如数字协议 | 中等:帧周期约 20ms,延迟略低于 PWM | 中端航模,对布线有要求但对通道数和抗干扰要求不极致的场景 |
| SBUS(串行数字协议) | 单线可传 16 通道(标准),SBUS 2.0 支持更多通道 + 双向传输 | 极低:仅需 1 根信号线+GND,布线极简,适合小型设备内部集成 | 强:数字信号传输,带校验机制,抗电磁干扰能力大幅提升 | 低:标准帧周期 10ms(100Hz),高速模式 4ms(250Hz),延迟远低于 PWM/PPM | 无人机、专业航模、工业机器人、无人车等对稳定性和低延迟要求高的场景 |
通过上述对比,SBUS 的核心优势已清晰,结合补充信息整理如下:
| 核心优势 | 具体说明 | 带来的价值 |
|---|---|---|
| 单线多通道传输 | 标准 SBUS 单线可传输 16 个控制通道数据,SBUS 2.0 支持更多通道 | 大幅简化布线,减少设备内部线路占用空间,降低线路拉扯损坏的风险 |
| 抗干扰能力强 | 采用数字信号传输,帧结构带校验位,且为反向电平逻辑(减少环境干扰影响) | 在无人机高空飞行、工业机器人复杂电磁环境等场景下,保证控制信号稳定不丢失 |
| 延迟低 | 标准模式帧刷新率 100Hz(10ms/帧),高速模式 250Hz(4ms/帧),远高于 PWM/PPM | 实现精准实时控制,比如无人机的姿态调整、航模的特技动作、机器人的快速响应 |
| 协议简洁易实现 | 基于 UART 协议扩展,帧结构固定(25 字节),解析逻辑简单,主流 MCU 均可支持 | 降低开发者门槛,无需复杂的协议栈,快速集成到项目中 |
| 支持故障检测 | 帧结构含标志位,可检测信号丢失、FailSafe 状态等故障 | 提升系统可靠性,故障时可触发预设保护动作(如无人机自动返航、机器人急停) |
| 宽电压兼容 | 支持 3.5V~8.4V 输入电压,适配不同设备的供电需求 | 减少额外电源转换模块的使用,简化硬件设计,提升供电兼容性 |
| 高兼容性 | 广泛兼容 Betaflight、APM、PX4 等主流飞控系统,以及各类开源控制平台 | 降低设备选型成本,适配多场景开发需求,无需担心系统兼容问题 |
SBUS 协议凭借其核心优势,广泛应用于各类需要精准控制的场景:
SBUS 的本质是'反向电平的 UART 串行协议'——这句话是理解 SBUS 工作原理的核心。简单来说,SBUS 并没有脱离 UART 的基本框架,只是在电平逻辑、波特率等参数上做了定制化调整,以适应控制信号传输的需求。
下面从物理层、电平逻辑、波特率、帧周期、工作流程五个核心维度,拆解 SBUS 的工作原理,并用表格对比标准 UART,帮助理解差异。
SBUS 的物理层非常简单,仅需要 2 根线即可完成通信:1 根信号线(用于传输串行数据)+1 根 GND(地线,保证电平参考一致)。
| 物理层参数 | 具体规格 | 设计目的 | 与标准 UART 的差异 |
|---|---|---|---|
| 传输线数量 | 1 根信号线 + 1 根 GND(共 2 根) | 极简布线,降低硬件成本和线路复杂度 | 标准 UART 通常为 TX/RX 双线(全双工),SBUS 为单线(半双工,仅接收或发送,控制场景多为单向传输) |
| 供电电平 | 3.3V 电平(部分设备兼容 5V,但主流为 3.3V) | 适配主流 MCU(如 STM32、ESP32)的 3.3V IO 口,减少电平转换成本 | 标准 UART 可支持 3.3V 或 5V,无强制要求 |
| 传输距离 | 常规场景下可达 10 米以内,优质线材可延长至 20 米 | 满足大多数控制设备的内部或短距离通信需求(如无人机内部飞控与接收机的距离通常在 0.5 米内) | 标准 UART 传输距离类似,若需长距离需加差分电路(如 RS485),SBUS 不直接支持长距离 |
这是 SBUS 与标准 UART 最核心的差异之一,也是很多开发者初次接触 SBUS 时最容易踩坑的地方——SBUS 采用'反向电平逻辑',与标准 UART 完全相反。
| 逻辑状态 | SBUS 电平(反向逻辑) | 标准 UART 电平(正向逻辑) | 注意事项 |
|---|---|---|---|
| 逻辑'1'(高电平) | 低电平(约 0V) | 高电平(3.3V/5V) | 若直接将 SBUS 信号接入标准 UART 接口,会导致无法正确解析数据,必须添加电平反向电路 |
| 逻辑'0'(低电平) | 高电平(约 3.3V) | 低电平(约 0V) |
重点提醒:SBUS 的反向电平逻辑是'硬件适配的第一道门槛'。如果跳过电平反向步骤,即使 UART 参数配置正确,也无法解析出正确的 SBUS 数据,只会得到一堆乱码。
实现 SBUS 反向电平到标准 UART 电平的转换,主流有三种方案,适配不同场景需求:
SN74LVC1G240 是一款单路总线缓冲器/线路驱动器,具备电平转换和信号缓冲功能,适合 3.3V 系统。其核心优势是静态电流小、工作电压范围宽(1.65V~5.5V),封装小巧(如 SOT-23),非常适合无人机、航模等小型设备。
电路连接说明:
| SN74LVC1G240 引脚 | 连接对象 | 作用说明 |
|---|---|---|
| A(输入端) | SBUS 接收机信号输出端 | 接收反向电平的 SBUS 原始信号 |
| Y(输出端) | MCU 的 UART 接收引脚(如 STM32 的 USART2_RX) | 输出转换后的标准 UART 电平信号 |
| G(使能端,低有效) | MCU 的 GPIO 引脚(如 STM32 的 PA0)或直接接 GND | 控制芯片使能 |
| VCC | 3.3V 电源 | 为芯片提供工作电压,需与 MCU 电平匹配 |
| GND | 电源地 | 保证电平参考一致,需与接收机、MCU 共地 |
// 定义 SN74LVC1G240 使能引脚(示例使用 PA0)
#define SN74LVC1G240_EN_GPIO_PORT GPIOA
#define SN74LVC1G240_EN_GPIO_PIN GPIO_PIN_0
#define SN74LVC1G240_EN_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
// 初始化使能引脚(低电平有效)
void SN74LVC1G240_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能 GPIO 时钟
SN74LVC1G240_EN_CLK_ENABLE();
// 配置为推挽输出
GPIO_InitStruct.Pin = SN74LVC1G240_EN_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SN74LVC1G240_EN_GPIO_PORT, &GPIO_InitStruct);
// 默认使能芯片(输出低电平)
HAL_GPIO_WritePin(SN74LVC1G240_EN_GPIO_PORT, SN74LVC1G240_EN_GPIO_PIN, GPIO_PIN_RESET);
}
// 使能芯片(输出低电平)
void SN74LVC1G240_Enable(void) {
HAL_GPIO_WritePin(SN74LVC1G240_EN_GPIO_PORT, SN74LVC1G240_EN_GPIO_PIN, GPIO_PIN_RESET);
}
// 禁用芯片(输出高电平,进入高阻态)
void SN74LVC1G240_Disable(void) {
HAL_GPIO_WritePin(SN74LVC1G240_EN_GPIO_PORT, SN74LVC1G240_EN_GPIO_PIN, GPIO_PIN_SET);
}
74HC14 是六路施密特触发反相器,具备信号整形和反向功能,成本低、易采购,适合原型开发或批量生产场景。使用时仅需其中一路反相器即可完成电平转换。
电路连接说明:
| 74HC14 引脚 | 连接对象 | 作用说明 |
|---|---|---|
| 1A(反相输入端) | SBUS 接收机信号输出端 | 接收反向电平的 SBUS 原始信号 |
| 1Y(反相输出端) | MCU 的 UART 接收引脚 | 输出转换后的标准 UART 电平信号(完成两次反向,还原为正向逻辑) |
| VCC | 3.3V/5V 电源(与 MCU 电平匹配) | 为芯片提供工作电压 |
| GND | 电源地 | 与接收机、MCU 共地,保证电平稳定 |
优势与注意事项:
STM32 适配说明(无需额外控制,仅需接线):
#define SBUS_RX_GPIO_PORT GPIOB
#define SBUS_RX_GPIO_PIN GPIO_PIN_7
#define SBUS_RX_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
// 初始化 SBUS 接收引脚(UART_RX 复用模式)
void SBUS_RX_Pin_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 启用 GPIO 时钟
SBUS_RX_CLK_ENABLE();
// 配置为复用推挽输出(UART 接收引脚)
GPIO_InitStruct.Pin = SBUS_RX_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1; // 示例:复用为 USART1
HAL_GPIO_Init(SBUS_RX_GPIO_PORT, &GPIO_InitStruct);
}
若临时开发或成本敏感,可采用 NPN 三极管搭建极简反相电路,仅需三极管、两个电阻即可实现。
电路连接说明:
优势与注意事项:
在集成度高的飞控(如 Pixhawk、Betaflight 飞控)中,SBUS 接收端口已内置电平反转电路,可直接将 SBUS 接收机的信号输出端连接到飞控的'SBUS'标注定制口,无需额外添加电平转换电路。
波特率是串口通信的核心参数之一,SBUS 采用'非标准波特率'——100kbps(100000 bit/s),且数据格式固定为 8 位数据位、偶校验、2 位停止位(8E2),这是正确配置串口的基础。
| 参数 | SBUS 规格 | 常见误区 | 影响 |
|---|---|---|---|
| 波特率 | 固定 100000 bit/s(100kbps),无其他可选值 | 将 SBUS 按 115200(标准常用波特率)配置 UART,导致数据解析错误 | 波特率不匹配会直接导致通信失败,无法解析出有效帧数据 |
| 数据格式 | 8 位数据位、偶校验(Even Parity)、2 位停止位(8E2) | 忽略校验位或停止位配置,导致帧同步失败 | 数据格式错误会出现帧丢失、数据错乱,影响控制稳定性 |
| 比特率误差容忍度 | ≤1%(优质 MCU 的晶振可满足,部分廉价 MCU 可能因晶振精度不足导致误差超标) | 使用精度低的外置晶振,导致波特率误差过大 | 误差过大会出现帧丢失、数据错乱等问题,影响控制稳定性 |
// 定义 SBUS 使用的 UART 句柄(示例使用 USART1)
UART_HandleTypeDef huart1;
/**
* @brief SBUS UART 初始化配置
* @note 参数配置为 100kbps 波特率,8 位数据位,偶校验,2 位停止位
*/
void SBUS_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 100000; // SBUS 标准波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_2;
huart1.Init.Parity = UART_PARITY_EVEN;
huart1.Init.Mode = UART_MODE_RX; // 仅配置为接收模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler(); // 初始化失败处理
}
// 启用中断接收(推荐使用 DMA 降低 CPU 负载)
HAL_UART_Receive_IT(&huart1, (uint8_t*)&sbus_rx_buf, 1);
}
/**
* @brief UART 接收中断回调函数
* @param huart: UART 句柄指针
* @note 实现单字节接收和帧同步检测
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
static uint8_t sbus_frame_buf[25]; // SBUS 帧缓存 (25 字节)
static uint8_t frame_index = 0; // 帧同步检测:0x0F 为起始字节
if (sbus_rx_buf == 0x0F) {
frame_index = 0;
}
// 存储接收数据
sbus_frame_buf[frame_index++] = sbus_rx_buf;
// 完整帧接收完成
if (frame_index >= 25) {
frame_index = 0;
SBUS_Frame_Parse(sbus_frame_buf); // 调用帧解析函数
}
// 重新启用中断接收
HAL_UART_Receive_IT(&huart1, (uint8_t*)&sbus_rx_buf, 1);
}
}
// 定义 SBUS DMA 接收缓存(采用循环模式自动覆盖旧数据)
uint8_t sbus_dma_buf[50]; // 双帧缓存防止溢出
// SBUS UART+DMA 初始化
void SBUS_UART_DMA_Init(void) {
// 1. 完成基础 UART 配置
SBUS_UART_Init();
// 2. 配置 DMA 接收
__HAL_RCC_DMA2_CLK_ENABLE(); // 使能 DMA 时钟(需根据 MCU 型号调整)
hdma_usart1_rx.Instance = DMA2_Stream2;
hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) {
Error_Handler();
}
// 3. 绑定 UART 与 DMA
__HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);
// 4. 启动 DMA 接收
HAL_UART_Receive_DMA(&huart1, sbus_dma_buf, sizeof(sbus_dma_buf));
}
SBUS 以'帧'为单位传输数据,每帧包含完整的 16 通道控制信息。帧周期(两帧数据之间的时间间隔)决定了控制信号的刷新率,直接影响控制延迟,支持三种传输模式:
| 传输模式 | 帧周期 | 刷新率 | 延迟表现 | 适用场景 |
|---|---|---|---|---|
| 标准模式(默认) | 10ms | 100Hz | 单帧延迟≤10ms,满足绝大多数控制场景需求 | 普通无人机、航模、机器人等常规控制场景 |
| 高速模式 | 4ms | 250Hz | 单帧延迟≤4ms,实时性大幅提升 | 穿越机、竞速航模等对实时性要求极高的场景(需接收机和遥控器均支持) |
| 低速模式 | 14ms | 71.4Hz | 延迟较高,但功耗更低 | 低功耗设备、长距离遥控等对功耗敏感的场景(较少见) |
补充说明:帧周期是'从接收机发送一帧数据到下一次发送的时间间隔',而单帧数据的传输时间极短(25 字节×8bit=200bit,按 100kbps 波特率计算,传输时间=200bit/100000bit/s=2ms),因此控制延迟主要由帧周期决定,而非单帧传输时间。
SBUS 的工作流程可分为'信号采集 - 编码 - 传输 - 解码 - 执行'五个步骤,全程实现数字信号的闭环流转,具体如下:
简化流程图:用户操作 → 遥控器(采集 + 编码) → 2.4GHz 无线传输 → 接收机(接收 + 解调) → SBUS 单线传输 → 飞控/执行器(解码 + 映射 + 执行)
SBUS 协议的核心是'固定 25 字节的帧结构'——每帧数据的长度、字段定义、字节顺序都是固定的,这也是其解析逻辑简单的关键原因。掌握帧结构,就掌握了 SBUS 协议的核心,下面逐一字段拆解,结合表格和实例让你彻底搞懂。
标准 SBUS 帧(1.0 版本)的总长度为 25 字节,字段从前往后依次为:起始字节、通道数据(22 字节)、标志位、结束字节。各字段的字节数、固定值、功能如下表所示:
| 字段名称 | 字节数 | 固定值/格式 | 核心功能 | 备注 |
|---|---|---|---|---|
| 起始字节(Start Byte) | 1 | 0x0F(十六进制) | 标志一帧数据的开始,用于帧同步 | 所有合法 SBUS 帧的第一个字节必须是 0x0F,是判断帧开始的唯一标识 |
| 通道数据(Channel Data) | 22 | 16×11bit 数据(共 176bit) | 存储 16 个控制通道的原始值,每个通道用 11bit 表示 | 22 字节=176bit,正好容纳 16 个 11bit 通道数据,是帧结构的核心字段 |
| 标志位(Flags Byte) | 1 | 8bit 标志位(每 bit 对应一个状态) | 故障检测、帧状态指示(如 FailSafe、帧丢失) | 不同 bit 的含义有明确规定,是实现故障保护的关键 |
| 结束字节(End Byte) | 1 | 0x00 或 0x7E(十六进制) | 标志一帧数据的结束,用于确认帧完整性 | 多数设备使用 0x00,部分设备支持 0x7E,解析时需兼容两种情况 |
关键计算:16 个通道×11bit/通道=176bit;176bit÷8bit/字节=22 字节。这就是通道数据字段长度为 22 字节的原因——精准匹配 16 个 11bit 通道数据的存储需求,无冗余也无缺失。
下面对每个字段进行详细拆解,尤其是通道数据和标志位,这两个字段是解析 SBUS 数据的核心。
起始字节的唯一作用是'帧同步'——告诉解析端(如飞控 MCU)'从这个字节开始,后面是完整的 SBUS 帧数据'。
解析逻辑:MCU 在接收 SBUS 数据时,会持续监测接收字节,当检测到某个字节为 0x0F 时,就认为后续 24 个字节(共 25 字节)是一帧完整的 SBUS 数据,开始后续的解析流程。
注意:如果在监测过程中,连续多个字节都不是 0x0F,说明当前没有有效帧,解析端会持续等待,直到检测到 0x0F 为止。
这是 SBUS 帧结构中最复杂的部分——16 个通道的控制值被'紧密打包'在 22 字节中,每个通道占用 11bit,没有字节对齐,需要按位解析。
先明确两个关键前提:
通道数据的打包规则(按位排列):
22 字节共 176bit,按从低字节到高字节、从低位到高位的顺序,依次存储 16 个通道的 11bit 数据。具体排列如下(以字节编号 B1~B22 表示通道数据字段的 22 个字节,bit0 表示最低位,bit7 表示最高位):
| 通道编号 | 占用的比特位(字节 B1~B22 的 bit 位) | 解析逻辑(以 STM32 为例,C 语言) |
|---|---|---|
| 通道 0(CH0) | B1 的 bit0~bit10(共 11bit) | `channels[0] = ((sbus_frame[1] |
| 通道 1(CH1) | B2 的 bit3 | `channels[1] = ((sbus_frame[2] >> 3 |
| 通道 2(CH2) | B3 的 bit6 | `channels[2] = ((sbus_frame[3] >> 6 |
| 通道 3(CH3) | B5 的 bit1 | `channels[3] = ((sbus_frame[5] >> 1 |
| 通道 4(CH4) | B6 的 bit4 | `channels[4] = ((sbus_frame[6] >> 4 |
| 通道 5(CH5) | B7 的 bit7 | `channels[5] = ((sbus_frame[7] >> 7 |
| 通道 6(CH6) | B9 的 bit2 | `channels[6] = ((sbus_frame[9] >> 2 |
| 通道 7(CH7) | B10 的 bit5 | `channels[7] = ((sbus_frame[10] >> 5 |
| 通道 8(CH8) | B12 的 bit0 | `channels[8] = ((sbus_frame[12] |
| 通道 9(CH9) | B13 的 bit3 | `channels[9] = ((sbus_frame[13] >> 3 |
| 通道 10(CH10) | B14 的 bit6 | `channels[10] = ((sbus_frame[14] >> 6 |
| 通道 11(CH11) | B16 的 bit1 | `channels[11] = ((sbus_frame[16] >> 1 |
| 通道 12(CH12) | B17 的 bit4 | `channels[12] = ((sbus_frame[17] >> 4 |
| 通道 13(CH13) | B18 的 bit7 | `channels[13] = ((sbus_frame[18] >> 7 |
| 通道 14(CH14) | B20 的 bit2 | `channels[14] = ((sbus_frame[20] >> 2 |
| 通道 15(CH15) | B21 的 bit5 | `channels[15] = ((sbus_frame[21] >> 5 |
// 16 通道 SBUS 数据缓冲区
uint16_t sbus_channels[16] = {0};
/**
* SBUS 帧解析函数
* @param sbus_frame 输入 25 字节 SBUS 帧数据
*/
void SBUS_Frame_Parse(uint8_t *sbus_frame) {
// 帧头校验(0x0F)和帧尾校验(0x00 或 0x7E)
if (sbus_frame[0] != 0x0F || (sbus_frame[24] != 0x00 && sbus_frame[24] != 0x7E)) {
return; // 无效帧直接返回
}
// 解析 16 个通道数据
sbus_channels[0] = ((sbus_frame[1] | sbus_frame[2] << 8) & 0x07FF);
sbus_channels[1] = ((sbus_frame[2] >> 3 | sbus_frame[3] << 5) & 0x07FF);
sbus_channels[2] = ((sbus_frame[3] >> 6 | sbus_frame[4] << 2 | sbus_frame[5] << 10) & 0x07FF);
sbus_channels[3] = ((sbus_frame[5] >> 1 | sbus_frame[6] << 7) & 0x07FF);
sbus_channels[4] = ((sbus_frame[6] >> 4 | sbus_frame[7] << 4) & 0x07FF);
sbus_channels[5] = ((sbus_frame[7] >> 7 | sbus_frame[8] << 1 | sbus_frame[9] << 9) & 0x07FF);
sbus_channels[6] = ((sbus_frame[9] >> 2 | sbus_frame[10] << 6) & 0x07FF);
sbus_channels[7] = ((sbus_frame[10] >> 5 | sbus_frame[11] << 3) & 0x07FF);
sbus_channels[8] = ((sbus_frame[12] | sbus_frame[13] << 8) & 0x07FF);
sbus_channels[9] = ((sbus_frame[13] >> 3 | sbus_frame[14] << 5) & 0x07FF);
sbus_channels[10] = ((sbus_frame[14] >> 6 | sbus_frame[15] << 2 | sbus_frame[16] << 10) & 0x07FF);
sbus_channels[11] = ((sbus_frame[16] >> 1 | sbus_frame[17] << 7) & 0x07FF);
sbus_channels[12] = ((sbus_frame[17] >> 4 | sbus_frame[18] << 4) & 0x07FF);
sbus_channels[13] = ((sbus_frame[18] >> 7 | sbus_frame[19] << 1 | sbus_frame[20] << 9) & 0x07FF);
sbus_channels[14] = ((sbus_frame[20] >> 2 | sbus_frame[21] << 6) & 0x07FF);
sbus_channels[15] = ((sbus_frame[21] >> 5 | sbus_frame[22] << 3) & 0x07FF);
// 解析状态标志位
SBUS_Flags_Parse(sbus_frame[23]);
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online