你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】stm32 解析sbus

[复制链接]
STMCU小助手 发布时间:2022-1-27 22:58
1. S.BUS
; b: M0 T/ q! s/ Y, q# u& e# F1.1 协议介绍
S.BUS是FUTABA提出的舵机控制总线,全称Serial Bus,别名S-BUS或SBUS,也称 Futaba S.BUS。
6 S1 s% P7 ?/ ~. B) TS.BUS是一个串行通信协议,也是一个数字串行通信接口(单线),适合与飞控连接。它可以连接很多设备,每个设备通过一个HUB与它相连,得到各自的控制信息。4 p1 z$ U1 L" d2 i
S.BUS可以传输16个比例通道和2个数字(bool)通道。其硬件上基于RS232协议,采用TTL电平,但高位取反(负逻辑,低电平为“1”,高电平为“0”),通信波特率为100K(不兼容波特率115200)。
1.2 协议解析$ A( x) \# O+ B0 ^! r
通信接口:USART(TTL)9 x% g! M9 R( j' s$ N
通信参数:1个起始位+8个数据位+偶校验位+2个停止位,波特率=100000bit/s,电平逻辑反转。
; f6 N% u$ [3 q8 Z: ~$ `! Q通信速率:每14ms(模拟模式)或7ms(高速模式)发送,即数据帧间隔为 11ms(模拟模式)或4ms(高速模式)。
8 w" w6 i1 C9 o/ G  `: e数据帧格式:[1]" c; E% w+ n3 I4 B4 b4 `
字节位 byte1 byte2-23 byte24 byte25( f4 T5 ]2 ~/ v
类型 开始字节 通道数据字节(含16个脉宽通道) 标志位字节(含2个数字通道) 结束字节
) D% z/ w' H4 J8 v数据 0x0F 通道数据范围11Bits = [0,2047] 2个数字通道位+2个状态位 0x00/ ?2 H  }" ?% y0 D) b
byte1:
) U) n, b& R6 x" C# Rstartbyte = 0000 1111b (0x0F)
byte2-23:
4 x: L1 Q  j4 Jdatabytes = 22bytes = 22 x 8Bits = 16 x 11Bits(CH1-16)- S( y& A* g7 v3 O; t3 P
通道数据低位在前,高位在后,每个数据取11位,具体协议如下:2 f" }5 _+ a% I5 ~. {4 P
读取的databyte值:
byte 2 3 4 5 6 7 etc
+ N0 }% @) `1 d8 k( z& C7 k内容 12345678 12345678 12345678 12345678 12345678 12345678 etc$ T! A) g  U  \# p7 m+ V- n+ e
转化后的通道值:
通道 CH01 CH02 CH03 CH04 etc( T9 O5 J5 I9 K& N
内容 67812345678 34567812345 81234567812 56781234567 etc
9 ]+ o8 h4 }2 ]  e* w5 P7 e( L( jbyte24:
Bit 7 6 5 4 3 2 1 0
) h) \9 c, I7 D- V5 X含义 数字通道CH17 数字通道CH18 帧丢失位 故障保护激活位 N/A N/A N/A N/A
% a# m- g0 y- W/ J9 O# Jbyte25:
5 n' q" ]* k+ f" c+ M+ W6 Dendbyte = 0000 0000b (0x00)

3 F; A7 T1 }+ j. I  d
2. 硬件设计
$ w- L5 ?! }/ r9 k" i5 |' k2.1 硬件参数
: b% R7 R2 c1 s主控芯片:STM32F103VET6* h. p, g2 I  e9 j; H7 u! E
接收端口:USART2(带反相电路)7 X6 L9 L% E/ |4 |3 q
S.BUS设备:walkera RX-SBUS[2](配DEVO 10遥控器)

: O/ m/ C& Q, q) h" z1 C7 Z2.2 反相电路
2 k; }2 m, l; d6 J由于此芯片串口不带反相器,我们需要外部搭建反相电路。如果芯片串口内部带反相器,可以省略此步。反相电路设计如下图:
5 `; B& _, S% T: b# D
J1为4Pin排针,适配S.BUS接口,可5V输出为SBUS接收机供电。& q+ \+ ]8 R: m0 V8 @& Y
J1的Pin-4接S.BUS数据发送端,连接一个由NPN三极管构成的反相器,将反相后的信号送入芯片USART2的RXD引脚。
  s" j# Q% z/ H
3.程序设计  b& L) V& D4 i# l5 o
3.1 数据接收
# R! I9 t: T/ h$ o分析一:根据 1.2 的协议解析,开始字节(0x0F)和结束字节(0x00)都是数据字节中很容易出现的字节,所以不能完全作为数据帧接收开始和结束的标志。8 k3 |; L" F3 Z1 l& I$ Q( @: W
分析二:每个数据帧之间的间隔至少4ms,则可以利用这个空闲时间来接收数据帧。(需要设计一个系统时钟)7 O9 p1 b  J5 A
分析三:STM32 USART或UART有空闲中断,即检测到总线空闲(无数据传输),就产生中断。6 ~9 G( I. v+ |6 |6 v2 [
接收程序设计:综上,利用USART2接收中断(RXNE)来接收每个字节,利用USART2空闲中断(IDLE)来判断数据帧是否接收完毕。
USART2 初始化函数代码如下:
/**
' e  x# S: \3 ?* @name SBUS_Configuration% j" X3 h7 p! U" h
* @brief Configure SBUS(Usart2) clock, gpio and nvic:! B0 l/ h0 U0 t# s1 [5 p
* SBUS_RX USART2_RX PD6" [1 `4 Y9 b+ j+ }( [3 x& l6 {
* @param None
; \6 D* I$ S& B3 j3 @9 D' L* @retval None' b0 Q2 T* E, H  Z8 P% m
*/" M6 U2 Z) V. [' j  z
void SBUS_Configuration(void)5 h% {$ ~7 i& l/ a$ f
{% `) M* u; a  M: ]- x1 M& P5 O
GPIO_InitTypeDef GPIO_InitStructure;
, b) S0 A; X# M7 R  y7 s, e3 JUSART_InitTypeDef USART_InitStructure;
% ^  {# m  }1 y3 S: `NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
2 c6 l2 R; h3 A2 _RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
8 ]+ u4 ]6 _: J; W, }3 D9 r0 `' N2 H; l1 [1 {
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  u9 i2 }) h9 s: f3 h5 c1 o) wGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;* p9 B! S# j7 Y2 ^  p; P! G
GPIO_Init(GPIOD, &GPIO_InitStructure);2 Q0 c& v& K% `

, j: `5 ]: B- A1 W* nGPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
// 波特率100000 8个数据位 偶校验位 2个停止位9 a0 F/ z/ x/ K3 h) S9 G
USART_InitStructure.USART_BaudRate = 100000;$ t+ ^$ _" a7 q; L
USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //注意这里是9个数据长度(8个数据位+偶校验位)
6 o7 e$ k' b0 ZUSART_InitStructure.USART_StopBits = USART_StopBits_2;
# ]* z0 g7 ~1 o: T1 [) R9 G# WUSART_InitStructure.USART_Parity = USART_Parity_Even;
  ?& O* d; L5 j% d; Z5 p9 g. jUSART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
' D# u" g0 M$ f+ [( k" d  m/ H6 DUSART_InitStructure.USART_Mode = USART_Mode_Rx;
USART_Init(USART2, &USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;9 }: A* M- T- g) O! ^2 M1 `* [
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;. ^2 T: v3 Y2 ^# {" V- \7 ]
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;; |, t  w- P% m6 U' F
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;6 L' e# t7 r$ Z9 c# [' L( R  N
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);& Y9 `7 v. |2 R  [; O
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
USART_Cmd(USART2, ENABLE);
  X: W4 Q8 ]2 ~  X! u  I" F6 \}
7 y! X/ |& S6 z2 T! v$ K
2 T6 |6 ~( g' c' ?USART2 中断函数代码如下:

  o6 I  w1 ~- Y3 E* \uint8_t USART2_RX_BUF[26];
/**3 I1 m4 B: N$ B9 {# E( e
* @name USART2_IRQHandler# o) d  z8 z. Y' f
* @brief This function handles USART2 Handler& o5 e+ E1 |* {5 F0 D' F. k; I
* @param None
2 }9 A( m7 G/ n% V0 a* @retval None7 m$ b! w, k% D3 |( |2 i) a1 r
*/
8 l' |( I" [$ a1 C- {void USART2_IRQHandler(void)
: ]+ ?8 d8 y$ a- n8 z7 ^$ K{; Z! f7 }9 |' N, H& F. q/ Y5 a$ J5 i
uint8_t res;. N" \; Y- Y) X$ m
uint8_t clear = 0;3 ?- i+ M0 a! j: k3 _0 r
static uint8_t Rx_Sta = 1;
9 g# c6 ]; n9 Y& [) ]# ~
1 I' s! c+ P: _+ ~1 [& t0 nif(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
% B8 g; l7 r+ a{
( u3 P6 M6 l! `res =USART2->DR;
$ P7 {2 N; a- X6 u2 E6 wUSART2_RX_BUF[Rx_Sta++] = res;' j& ?$ O5 x% m0 e# I6 V! ~
}
/ B' O1 q7 N$ T. g& I4 Qelse if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
6 J& z2 f& n2 E1 V: B; }{
: l7 [/ o' K7 g. U' {* Mclear = USART2->SR;
/ O3 e0 e4 W" U8 O3 Lclear = USART2->DR;; i: \+ W7 m$ i4 f
USART2_RX_BUF[0] = Rx_Sta - 1;1 a3 V$ L2 Y) ~% V
Rx_Sta = 1;
  m0 a. U$ \8 ~- y+ }% e  Y1 d}" q/ x( q1 S" `
}
  ?2 N: m' g  d$ x7 P
. k8 n( s% u/ f3 fUSART2_RX_BUF为接收缓存区,定义为26个字节,第一个字节USART2_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。0 `* D' \- n3 i; q! P3 D1 V
USART2_RX_BUF[0]可以作为数据帧字节长度的判断。
1 P% L! Q& \$ _中断服务函数具体解释请参考STM32 串口接收不定长字节数据。

3 t$ U  L* S+ ~8 h3.2 数据处理
2 i- x5 Q* O/ h- z1 d$ d" B直接上代码:
uint16_t CH[18]; // 通道值$ W3 z# `# D1 [4 \$ e' H, R
uint8_t rc_flag = 0;
void Sbus_Data_Count(uint8_t *sBusData)7 B1 J2 k2 Q9 e/ Q' k% c9 |
{
tempData[ 0 ] = ( (sBusData[ 2]&0x07) << 8 ) + sBusData[ 1]; //sBus[ 2] low3 + sBus[ 1] low84 ?. q% z3 H3 y" B: V
tempData[ 1 ] = ( (sBusData[ 3]&0x3F) << 5 ) + (sBusData[ 2] >> 3 ); //sBus[ 3] low6 + sBus[ 2] high58 e, G: {# b  M3 f  P1 X
tempData[ 2 ] = ( (sBusData[ 5]&0x01) << 10) + (sBusData[ 4] << 2 ) + (sBusData[ 3] >> 6); //sBus[ 5] low1 + sBus[ 4] low8 + sBus[ 3] high2
4 M  w: y. ^, m* t' c1 z7 p6 wtempData[ 3 ] = ( (sBusData[ 6]&0x0F) << 7 ) + (sBusData[ 5] >> 1 ); //sBus[ 6] low4 + sBus[ 5] high7
3 D: S3 z8 L9 r/ v" O; L* T" l3 ktempData[ 4 ] = ( (sBusData[ 7]&0x7F) << 4 ) + (sBusData[ 6] >> 4 ); //sBus[ 7] low7 + sBus[ 6] high4
& X. `7 s1 d6 B' otempData[ 5 ] = ( (sBusData[ 9]&0x03) << 9 ) + (sBusData[ 8] << 1 ) + (sBusData[ 7] >> 7); //sBus[ 9] low2 + sBus[ 8] low8 + sBus[ 7] high1
$ S4 b  {1 B# A. I% AtempData[ 6 ] = ( (sBusData[10]&0x1F) << 6 ) + (sBusData[ 9] >> 2 ); //sBus[10] low5 + sBus[ 9] high62 N0 S2 q( l( y4 O3 N! z% j% U/ L/ i
tempData[ 7 ] = ( (sBusData[11]&0xFF) << 3 ) + (sBusData[10] >> 5 ); //sBus[11] low8 + sBus[10] high38 W1 Z0 {! c. g" y& O0 {+ [

5 {1 X0 b/ [0 \- w0 F7 B1 }tempData[ 8 ] = ( (sBusData[13]&0x07) << 8 ) + sBusData[12]; //sBus[13] low3 + sBus[12] low8
, N$ D* a% F' G. TtempData[ 9 ] = ( (sBusData[14]&0x3F) << 5 ) + (sBusData[13] >> 3 ); //sBus[14] low6 + sBus[13] high54 J! ]* @# E% b$ @
tempData[ 10 ] = ( (sBusData[16]&0x01) << 10) + (sBusData[15] << 2 ) + (sBusData[14] >> 6); //sBus[16] low1 + sBus[15] low8 + sBus[14] high27 m7 n: ?$ M7 Y" A
tempData[ 11 ] = ( (sBusData[17]&0x0F) << 7 ) + (sBusData[16] >> 1 ); //sBus[17] low4 + sBus[16] high7
, ~& s, a/ L1 E% p$ h6 V4 PtempData[ 12 ] = ( (sBusData[18]&0x7F) << 4 ) + (sBusData[17] >> 4 ); //sBus[18] low7 + sBus[17] high4" A8 m3 ?, I7 x  d
tempData[ 13 ] = ( (sBusData[20]&0x03) << 9 ) + (sBusData[19] << 1 ) + (sBusData[18] >> 7); //sBus[20] low2 + sBus[19] low8 + sBus[18] high1
+ W1 P& ^. E! w( e  JtempData[ 14 ] = ( (sBusData[21]&0x1F) << 6 ) + (sBusData[20] >> 2 ); //sBus[21] low5 + sBus[20] high63 i  S" R. f- q0 H2 L6 O
tempData[ 15 ] = ( (sBusData[22]&0xFF) << 3 ) + (sBusData[21] >> 5 ); //sBus[22] low8 + sBus[21] high3

# R" \+ _6 k* C  ]3 g}
9 d4 ^9 o- t+ {8 k- p, r接收到的报文和解析出来的数据如下:
+ x% `1 h. M, HRX:0F E0 03 1F 58 C0 07 16 B0 80 05 2C 60 01 0B F8 C0 07 00 00 00 00 00 03 00
% P3 \0 [  t! ?# hCH: 992 992 352 992 352 352 352 352 352 352 992 992 000 000 000 000
5 d9 T$ Q% `' r4 I5 W0 E. kRX:0F 60 01 0B 58 C0 07 66 30 83 19 7C 60 06 1F F8 C0 07 00 00 00 00 00 03 00* I3 ~( T' d/ K! q) N
CH: 352 352 352 992 1632 1632 1632 992 1632 992 992 992 000 000 000 000
接收的byte24数据并非和协议解析中的一样,无论断开遥控器还是连接遥控器,读取的值都是0x03。8 f7 r. ?( |) M
接收机只支持12个通道,所以通道13-16没有值。
  H6 ^. A- e( P读取的通道值中间值为992,最大值为1632,最小值为352。
sbus数据转为 PWM数据
RcData = (uint16_t)(sbusData * 1.2504 + 1761.1) / 2;

$ U6 @0 I9 _% G  Y/ m& Z
4. 最后2 ^) \( \" [" z$ T' }
提供两个应用优化方向:
使用DMA+双缓存器+串口空闲中断读取和解析数据,提升MCU的工作效率。
. _, ^/ q5 b# u' U1 K3 n1 r9 [5 a) w将读取的通道值转化成脉宽(0.5-2.5ms)输出,用来控制模拟信号设备。# X! H' V# E( M' c( P
本协议解析就写到这里。

  B& M, m0 n1 G0 v# W
赞 收藏 1 评论1 发布时间:2022-1-27 22:58

举报

1个回答
cqxhhe 回答时间:2022-8-4 11:11:04
学习! n" G) O3 G1 f2 M/ E

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版