2、SBUS物理层特性:信号电平、反向逻辑与串口配置
好,咱们进入第二章。这一章讲的是SBUS最底层的物理特性。说白了,就是信号在线上怎么跑、用什么电压、什么格式。这些是基础中的基础,搞不懂的话,后面解析数据包全是白搭。
我记得刚接触SBUS那会儿,拿着逻辑分析仪一看波形,直接懵了——怎么跟我预想的完全不一样?后来才发现,SBUS这家伙,天生就是「反着来」的。嗯,咱们慢慢聊。
2.1 信号电平:3.3V还是5V?
SBUS的信号电平,其实没有你想象的那么死板。它既可以用3.3V,也可以用5V。但这里有个坑——不是所有接收机都兼容5V逻辑。
我个人的习惯是:能用3.3V就用3.3V。为什么?因为现在主流的飞控主控芯片,比如STM32F4、F7系列,IO口基本都是3.3V耐受。你直接怼5V进去,虽然很多芯片标称「5V tolerant」,但长期下来,风险还是有的。
关键点:
- SBUS信号电平:3.3V 或 5V,取决于接收机型号
- 常见接收机(如FrSky X8R、R9MM):输出3.3V逻辑
- 部分老款接收机:可能输出5V逻辑
- 飞控端:建议使用3.3V电平,或加电平转换
⚠️ 我曾经踩过的坑:
有一次我用一个5V输出的接收机直接连到STM32F405的USART引脚上。刚开始跑得好好的,飞了大概20个起落后,突然串口收不到数据了。查了半天,发现那个引脚已经烧坏了。从那以后,我所有SBUS输入都加了一颗74LVC245做电平转换,再也没出过问题。
2.2 反向电平逻辑:SBUS为什么「反着来」?
这是SBUS最让人迷惑的地方。正常的UART信号,空闲时是高电平,起始位是低电平。但SBUS恰恰相反——空闲时是低电平,起始位是高电平。
为什么会这样?其实是为了兼容性。SBUS最初设计时,为了能直接驱动某些老式的反相器电路,故意把逻辑反了。你想想看,如果接收机内部已经做了反相,那信号出来自然就是反的。
所以,你在飞控端接收SBUS数据时,必须做一件事:硬件反相或软件反相。
| 方案 | 实现方式 | 优缺点 |
|---|---|---|
| 硬件反相 | 用三极管或反相器(如74HC04) | 稳定可靠,不占CPU资源 |
| 软件反相 | 在串口中断里手动取反每一位 | 省硬件,但增加CPU负担 |
| STM32硬件反相 | 使用USART的RXINV位 | 最优雅,零成本 |
💡 我的建议:
如果你用STM32,直接开启USART的RXINV位(接收数据反转)就行。在CubeMX里勾上「RX Pin Inverted」,或者代码里写 USART1->CR2 |= USART_CR2_RXINV。这样硬件帮你反相,省心又省力。
2.3 波特率100000bps:为什么不是115200?
很多人第一次看到SBUS的波特率,都会问:为什么是100000,而不是更常见的115200?
嗯,这个问题我当年也纠结过。后来查了资料才明白:SBUS的帧长度是25字节,每字节10位(8数据位+1起始位+1停止位),总共250位。以100000bps传输,一帧正好耗时2.5ms。而SBUS的更新周期是9ms(约111Hz),2.5ms完全够用。
那为什么不用115200?因为100000是100kHz的整数倍,对某些晶振分频更友好。说白了,就是历史遗留设计选择。
波特率配置要点:
- 波特率:100000 bps(不是115200!)
- 误差容忍:±2%以内,否则丢帧
- 常见晶振:8MHz、16MHz、72MHz都能精确分频到100000
2.4 8E2串口配置:奇偶校验和停止位
SBUS的串口配置是8E2。什么意思?
- 8:8位数据位
- E:偶校验(Even Parity)
- 2:2位停止位
这和常见的8N1(无校验、1位停止位)完全不同。我刚开始做SBUS驱动时,就忘了配校验位,结果数据全是乱码。排查了半天才发现是校验位没设对。
偶校验的意思是:数据位中1的个数加上校验位,总共有偶数个1。接收端会检查这个,如果不对,就说明数据传错了。
⚠️ 注意:
很多串口库默认是8N1。如果你用Arduino的Serial.begin(),它不支持8E2。这时候你得用Serial1.begin(100000, SERIAL_8E2)这种写法。在STM32的HAL库里,要设置USART_InitStructure.Parity = USART_PARITY_EVEN和USART_InitStructure.StopBits = USART_STOPBITS_2。
2.5 知识体系总览
下面这张图,把SBUS物理层的核心要素串起来了。你可以把它当作一个快速参考。
2.6 实际配置示例
最后,给你一个Arduino和STM32的配置代码片段。直接拿去用就行。
Arduino(Teensy/STM32duino):
// SBUS串口初始化
Serial1.begin(100000, SERIAL_8E2);
// 注意:Arduino Uno/Mega不支持100000波特率,建议用Teensy或STM32
STM32 HAL库:
// USART句柄配置
huart1.Instance = USART1;
huart1.Init.BaudRate = 100000;
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.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXINVERT_INIT;
huart1.Init.AdvancedInit.RxPinLevelInvert = UART_ADVFEATURE_RXINV_ENABLE;
HAL_UART_Init(&huart1);
💡 一个小技巧:
如果你用逻辑分析仪抓SBUS波形,记得把触发条件设为「上升沿」。因为SBUS空闲是低电平,起始位是高电平,上升沿才是数据开始的标志。我第一次抓波形时设成了下降沿,结果怎么都触发不了,折腾了半小时才发现问题。
好了,这一章就到这里。物理层搞定了,下一章咱们就可以真正开始解析SBUS数据帧了。到时候你会看到,25个字节里到底藏了什么秘密。
公众号:蓝海资料掘金营,微信deep3321