内容
本篇文章主要是S.BUS协议原理介绍,并实现了arduino输出S.BUS数据。
S.BUS简介
SBUS是一个接收机串行总线输出,通过这根总线,可以获得遥控器上所有通道的数据。目前很多模型及无人机电子设备都支持SBUS总线的接入。使用SBUS总线获取通道数据,效率高的,而且节省硬件资源,只需要一根线即可获取所有通道的数据。
SBUS总线使用的是TTL电平(3.3v)的反向电平,即标准TTL中的1取反为0,而0则取反为1,串口波特率为100000,数据位为8位,2个停止位,偶校验。
SBUS一帧数据的长度为25个字节,其中第"0"个字节为帧头:0x0f;第24个字节为帧尾:0x00;从第1个字节到第22个字节为1-16号比例通道的数据字节;第23字节中,第7位为数字开关通道17通道,第6位为数字开关通道18通道,第5位为帧状态标志为(判断是否丢帧),用于控制接收机上的LED的状态,第4位为失控保护激活标志位,此位为1时,表示接收机进入失控保护状态。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200821180453547.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDc2NTYyOQ==,size_16,color_FFFFFF,t_70#pic_center)
重要的点
SBUS本质是一种串口通信协议,采用100K的波特率,8位数据位,两位停止位,偶效验,即8E2的串口通信。
这里对于单片机学得不精的人来说特别容易搞混,波特率100000,两位停止位没什么问题。问题在于8位数据位,偶校验,这段话在单片机中却需要这样子表达9位数据位、偶校验。对没有错是9位数据位、偶校验。刚开始编码的时候我就一直卡在了这里,F4的飞控一直识别不了我编码的SBUS信号。原因如下:
如果需要8位数据,无奇偶校验,则数据长度=8
如果需要8位数据,有奇偶校验,则数据长度=9
值得注意的有三点:
1.SBUS采用负逻辑,所以无论接收还是发送都要进行硬件取反(注意,一定要硬件取反),电路如下
(用普通NPN三极管就可以,我试过可以用8050)
![三极管使用8050就可以](https://img-blog.csdnimg.cn/20200821180625939.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDc2NTYyOQ==,size_16,color_FFFFFF,t_70#pic_center)
2.SBUS有两种模式,
a.高速模式:每4ms发送一次
b.低速模式:每14ms发送一次
就是说每间隔4或者14ms这个串口就发送25个字节的数据,这25个字节的数据最多可以包含16个信息
3.100K的波特率不是标准波特率,一般串口工具都不能直接读取(所以不要直接用电脑调试,除非你的电脑写好了非标准串口),可以用单片机读取。
具体协议的格式如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200825112029621.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDc2NTYyOQ==,size_16,color_FFFFFF,t_70#pic_center)
C语言
S.BUS协议每帧数据有25字节。每字节含有12个比特,使用1个起始位“0”,8个数据位,1个奇校验位(8个数据位中1的数量为奇数则此位为“1”否则为“0”)两个终止位“1”。采用LSB first方式发送,即最低有效位(二进制数据右侧)先发。
帧头:1111 0000(二进制),帧尾:0000 0000(二进制)。
数据:从第1数据字节起,到第22字节,一共有数据位176个,(11 16=822)它们按照顺序分别是通道1至通道16的舵机控制数据,每个通道占11比特。取值范围是0~2047。
第23字节我管它叫做“功能字节”,第0比特为数字通道1的值,第1比特为数字通道2的值,第2比特为丢帧信息,第3比特为失效保护开关,第4~7比特暂时保留没用。
编码
uint8_t sbus_data[25]={0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint16_t ChValue[16]
sbus_data[0] = 0x0F;
sbus_data[1] = (unsigned char) ((ChValue[0] & 0x07FF));
sbus_data[2] = (unsigned char) ((ChValue[0] & 0x07FF)>>8 | (ChValue[1] & 0x07FF)<<3);
sbus_data[3] = (unsigned char) ((ChValue[1] & 0x07FF)>>5 | (ChValue[2] & 0x07FF)<<6);
sbus_data[4] = (unsigned char) ((ChValue[2] & 0x07FF)>>2);
sbus_data[5] = (unsigned char) ((ChValue[2] & 0x07FF)>>10 | (ChValue[3] & 0x07FF)<<1);
sbus_data[6] = (unsigned char) ((ChValue[3] & 0x07FF)>>7 | (ChValue[4] & 0x07FF)<<4);
sbus_data[7] = (unsigned char) ((ChValue[4] & 0x07FF)>>4 | (ChValue[5] & 0x07FF)<<7);
sbus_data[8] = (unsigned char) ((ChValue[5] & 0x07FF)>>1);
sbus_data[9] = (unsigned char) ((ChValue[5] & 0x07FF)>>9 | (ChValue[6] & 0x07FF)<<2);
sbus_data[10] = (unsigned char) ((ChValue[6] & 0x07FF)>>6 | (ChValue[7] & 0x07FF)<<5);
sbus_data[11] = (unsigned char) ((ChValue[7] & 0x07FF)>>3);
sbus_data[12] = (unsigned char) ((ChValue[8] & 0x07FF));
sbus_data[13] = (unsigned char) ((ChValue[8] & 0x07FF)>>8 | (ChValue[9] & 0x07FF)<<3);
sbus_data[14] = (unsigned char) ((ChValue[9] & 0x07FF)>>5 | (ChValue[10] & 0x07FF)<<6);
sbus_data[15] = (unsigned char) ((ChValue[10] & 0x07FF)>>2);
sbus_data[16] = (unsigned char) ((ChValue[10] & 0x07FF)>>10 | (ChValue[11] & 0x07FF)<<1);
sbus_data[17] = (unsigned char) ((ChValue[11] & 0x07FF)>>7 | (ChValue[12] & 0x07FF)<<4);
sbus_data[18] = (unsigned char) ((ChValue[12] & 0x07FF)>>4 | (ChValue[13] & 0x07FF)<<7);
sbus_data[19] = (unsigned char) ((ChValue[13] & 0x07FF)>>1);
sbus_data[20] = (unsigned char) ((ChValue[13] & 0x07FF)>>9 | (ChValue[14] & 0x07FF)<<2);
sbus_data[21] = (unsigned char) ((ChValue[14] & 0x07FF)>>6 | (ChValue[15] & 0x07FF)<<5);
sbus_data[22] = (unsigned char) ((ChValue[15] & 0x07FF)>>3);
sbus_data[23] = 0x00;
sbus_data[24] = 0X00;
解码
#define SIZE_BUFF (100)
int sbus_read_parse(int _fd, uint16_t *val){
uint8_t _buf[SIZE_BUFF];
int len = read(_fd, _buf, SIZE_BUFF);
if (len < 0)
{
return -1;
}
val[0] = ((buff[ind + 1] | buff[ind + 2] << 8) & 0x07FF);
val[1] = ((buff[ind + 2] >> 3 | buff[ind + 3] << 5) & 0x07FF);
val[2] = ((buff[ind + 3] >> 6 | buff[ind + 4] << 2 | buff[ind + 5] << 10) & 0x07FF);
val[3] = ((buff[ind + 5] >> 1 | buff[ind + 6] << 7) & 0x07FF);
val[4] = ((buff[ind + 6] >> 4 | buff[ind + 7] << 4) & 0x07FF);
val[5] = ((buff[ind + 7] >> 7 | buff[ind + 8] << 1 | buff[ind + 9] << 9) & 0x07FF);
val[6] = ((buff[ind + 9] >> 2 | buff[ind + 10] << 6) & 0x07FF);
val[7] = ((buff[ind + 10] >> 5 | buff[ind + 11] << 3) & 0x07FF);
val[8] = ((buff[ind + 12] | buff[ind + 13] << 8) & 0x07FF);
val[9] = ((buff[ind + 13] >> 3 | buff[ind + 14] << 5) & 0x07FF);
val[10] = ((buff[ind + 14] >> 6 | buff[ind + 15] << 2 | buff[ind + 16] << 10) & 0x07FF);
val[11] = ((buff[ind + 16] >> 1 | buff[ind + 17] << 7) & 0x07FF);
val[12] = ((buff[ind + 17] >> 4 | buff[ind + 18] << 4) & 0x07FF);
val[13] = ((buff[ind + 18] >> 7 | buff[ind + 19] << 1 | buff[ind + 20] << 9) & 0x07FF);
val[14] = ((buff[ind + 20] >> 2 | buff[ind + 21] << 6) & 0x07FF);
val[15] = ((buff[ind + 21] >> 5 | buff[ind + 22] << 3) & 0x07FF);
return 0;
}
参考:https://www.jianshu.com/p/b0b81c45280c
https://blog.csdn.net/qq1113512618/article/details/96628893?biz_id=102&utm_term=sbus&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-3-96628893&spm=1018.2118.3001.4187
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)