关于SBUS信号在单片机中的一些个人理解

2023-05-16

最近一直在弄关于SBUS的编码与解码这方面的内容,虽然网上资料很多,但是网上资料太杂,我找的一些资料可能是我理解的问题,所以我摒弃了一些骚操作,对于一些单片机学得不精的人来说,有些地方是值得注意的。

对于SBUS的探索,首先我个人是使用51芯片的遥控器通过NRF24L01发送遥控器PWM模拟量到一块STM32F030的接收机,在接收机内进行PWM转SBUS的操作,之后通过串口发送出SBUS信号,用F4飞控来连接串口发送出来的SBUS信号,并检验信号是否正确。(虽然这样挺麻烦的,但是检验起来很方便)

1.九位数据位、偶校验

SBUS本质是一种串口通信协议,采用100K的波特率,8位数据位,两位停止位,偶效验,即8E2的串口通信。

这里对于单片机学得不精的人来说特别容易搞混,波特率100000,两位停止位没什么问题。问题在于8位数据位,偶校验,这段话在单片机中却需要这样子表达9位数据位、偶校验对没有错是9位数据位、偶校验。刚开始编码的时候我就一直卡在了这里,F4的飞控一直识别不了我编码的SBUS信号。原因如下:

/*  如果需要8位数据,无奇偶校验,则数据长度=8

        如果需要8位数据,有奇偶校验,则数据长度=9*/

所以,关于串口端的设置,代码如下: 

  USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate = 100000;                       //设定传输速率
  USART_InitStructure.USART_WordLength = USART_WordLength_9b;        //设定传输数据位数
  USART_InitStructure.USART_StopBits = USART_StopBits_2;             //设定停止位个数——2位
  USART_InitStructure.USART_Parity = USART_Parity_Even ;               //偶校验
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不用流量控制
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //使用接收和发送功能
  USART_Init(USART1, &USART_InitStructure);                          //初始化USART1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                     //使能USART1接收中断
  USART_Cmd(USART1, ENABLE);                                         //使能USART1

2.SBUS采用负逻辑

所以需要硬件取反才能识别出来,软件取反试过通过示波器观察与硬件取反并不是一致的(起始电平),具体解决方法和原因我没深查。所以需要输出SBUS信号必须硬件取反

电路如下,三极管使用8050就行https://img-blog.csdn.net/20180517193106427

3.SBUS的两种工作模式

      高速模式:每4ms发送一次

      低速模式:每14ms发送一次

   就是说每间隔4或者14ms这个串口就发送25个字节的数据,高低速模式并不影响F4飞控对于SBUS信号的识别,所以只需设置多一个定时器定时发送SBUS信号即可。

100K的波特率不是标准波特率可以用单片机读取。我用F4飞控来识别单片机发出的SBUS信号之后在电脑端通过Betaflight Configurator来观察SBUS信号情况,能很直观的反映出SBUS信号是否正常

4.SBUS编码

帧格式【参考https://mbed.org/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/ 】

每帧25个字节,关于每帧的帧格式,我的理解就是第一帧为识别帧固定为:0x0F,然后最后两帧都为0x00

编码代码如下:

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]//通道数据,即遥控器发送过来的PWM
//PWM转SBUS
    // SBUS header
    sbus_data[0] = 0x0F;
    // 16 ChValue of 11 bit data
    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);
    // flags
    sbus_data[23] = 0x00;
    // footer
sbus_data[24] = 0X00;

对于编码之后校验的方面,我是通过编码之后串口发送出去,用F4飞控来接收发送出来的SBUS信号,然后通过Betaflight Configurator来观察SBUS信号是否规范

5.SBUS解码

解码代码,经过修改并验证后,SBUS信号发出后,用硬件取反接回单片机,接收配置上面有说过,值得注意的就是接收的数组不一定是从第一位开始的,所以需要简单处理一下接收到的数据。检验的说固定遥控器发送的PWM值,然后发送过来解码验证看是否一样即可。解码代码如下:

u16 buffer[25],channels[16];
    channels[0]  = ((buffer[1]    |buffer[2]<<8)                 & 0x07FF);
    channels[1]  = ((buffer[2]>>3 |buffer[3]<<5)                 & 0x07FF);
    channels[2]  = ((buffer[3]>>6 |buffer[4]<<2 |buffer[5]<<10)  & 0x07FF);
    channels[3]  = ((buffer[5]>>1 |buffer[6]<<7)                 & 0x07FF);
    channels[4]  = ((buffer[6]>>4 |buffer[7]<<4)                 & 0x07FF);
    channels[5]  = ((buffer[7]>>7 |buffer[8]<<1 |buffer[9]<<9)   & 0x07FF);
    channels[6]  = ((buffer[9]>>2 |buffer[10]<<6)                & 0x07FF);
    channels[7]  = ((buffer[10]>>5|buffer[11]<<3)                & 0x07FF);
    channels[8]  = ((buffer[12]   |buffer[13]<<8)                & 0x07FF);
    channels[9]  = ((buffer[13]>>3|buffer[14]<<5)                & 0x07FF);
    channels[10] = ((buffer[14]>>6|buffer[15]<<2|buffer[16]<<10) & 0x07FF);
    channels[11] = ((buffer[16]>>1|buffer[17]<<7)                & 0x07FF);
    channels[12] = ((buffer[17]>>4|buffer[18]<<4)                & 0x07FF);
    channels[13] = ((buffer[18]>>7|buffer[19]<<1|buffer[20]<<9)  & 0x07FF);
    channels[14] = ((buffer[20]>>2|buffer[21]<<6)                & 0x07FF);
    channels[15] = ((buffer[21]>>5|buffer[22]<<3)                & 0x07FF);

感谢来自wsptr【https://blog.csdn.net/wsptr/article/details/53795458】

以及 Bluish White【https://blog.csdn.net/qq_31232793/article/details/80244211】

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于SBUS信号在单片机中的一些个人理解 的相关文章

  • 不要在小公司做底层软件开发

    在这里makekam对底层软件的理解就是指驱动开发 xff0c 代码移植等工作 其中也包括底层的算法 在小公司做软件不要做底层软件开发 xff0c 犹如在公司做硬件开发不要只是焊接电路板 小公司处于产业链的最末端 xff0c 没有自己的核心
  • 多旋翼飞控篇新手课堂教程(共九集)

    多旋翼飞控篇新手课堂第一课 xff0c 将你的NAZA M真正升级成NAZA V2 http www mxkong com thread 134 1 1 html 出处 模型控MxKong 多旋翼飞控篇新手课堂第二课 xff1a NAZA远
  • Java基础final详解

    final中文意思 最后的 最终的 final 可以修饰类 属性 方法和局部变量 1 当不希望类被继承时 可以用final修饰 final class A 不可被继承 2 当不希望父类的某个方法被子类覆盖 重写 override 时 可以用
  • socket编程总结

    socket编程总结 主机字节序和网络字节序 字节序分为大端字节序 xff08 big endian xff09 和小端字节序 xff08 little endian xff09 大端字节序 xff1a 一个整数的高位存在内存的底地址 xf
  • c++中的常见问题

    CSP J终于考完了啊 xff01 坐在考场 xff0c 是一种煎熬 xff1a 为什么那么多不会啊 xff01 xff01 xff01 这里 xff0c 总结一下在c 43 43 中的那些常见问题 xff08 作者亲身经历 xff09 x
  • 大陆毫米波雷达ARS408-21xx(内附毫米波雷达使用说明书)使用记录:第一期

    文章目录 前言一 硬件链接二 代码如何使用三 大陆毫米波雷达ARS408 21XX解析代码说明总结 前言 从我个人的学习成长历程来看 xff0c 从0到1确实很难 我个人在对这款毫米波雷达的学习的过程中也比较痛苦 xff0c 资料缺乏 xf

随机推荐

  • 2022年度GitHub最火的力扣算法刷题宝典,手把手教你如何刷力扣~

    前言 昨晚逛了逛GitHub xff0c 无意中看到一位P8大佬的算法刷题笔记 xff0c 感觉发现了宝藏 xff01 有些小伙伴可能已经发现了 xff0c 但咱这里还是忍不住安利一波 xff0c 怕有些小伙伴没有看到 关于算法刷题的困惑和
  • LIO-SAM学习与运行测试数据集

    文章目录 0 说明0 1 环境配置说明0 2 LIO SAM0 3 系统架构0 4 LIO SAM youtube视频演示 xff1a Rotation Dataset Walking Dataset Park Dataset Campus
  • 理解ROS:参数服务器和动态参数

    文章目录 1 程序中的getparam与param1 1 getparam xff08 无默认值 xff09 1 2 param xff08 有默认值 xff09 1 3 删除参数1 4 程序中设置参数1 5 检查参数1 6 搜索参数 2
  • ROS理解:ros中的坐标以及对tf2进行解读

    文章目录 1 ROS中的坐标2 tf到tf2的变化3 发布静态tf24 发布动态tf25 监听tf26 增加自己的frame 官网就是最好的教程 xff0c 如果阅读英文没什么压力 xff0c 强烈推荐以下链接进行全面了解 xff1a 官网
  • gtsam:从入门到使用

    文章目录 一 总览二 贝叶斯网络和因子图三 机器人运动建模3 1 使用因子图建模3 2 建立因子图3 3 因子图与变量3 4 GTSAM中的非线性优化3 5 全后验推论 四 机器人定位4 1 一元测量因子4 2 自定义因子4 3 使用自定义
  • 马尔可夫链、隐马尔科夫模型、贝叶斯网络、因子图

    文章目录 一 马尔可夫链以及隐马尔可夫模型1 1 概念1 2 举例说明隐马尔可夫模型 二 贝叶斯网络三 因子图 贝叶斯网络是很多概率模型的基础 xff0c 对于slam研究也是一项必须掌握的数学理论工具 一 马尔可夫链以及隐马尔可夫模型 1
  • 3D打印机DIY之一------Prusa i3的材料清单和总体结构组装

    自己使用铝件和亚克力板组装了一台Prusa i3 3D打印机 xff0c 现在把详细的过程记录下来 总体效果图 xff1a 一 材料清单 元件数量总价2020欧式铝方管 xff1a 4根400mm 3根340mm 1根150mm 1根130
  • 位置式PID与增量式PID的介绍和代码实现

    PID分为位置式PID与增量式PID 一 位置式PID 1 表达式为 xff1a 2 缺点 xff1a 1 xff09 由于全量输出 xff0c 所以每次输出均与过去状态有关 xff0c 计算时要对ek进行累加 xff0c 工作量大 xff
  • 常见蓝牙模块介绍和AT指令

    目录 一 HC 05主从一体蓝牙模块 二 HC 06从机蓝牙模块 三 低功耗BLE蓝牙4 0模块 cc2540或cc2541 四 JDY 10 蓝牙4 0 BLE模块 五 蓝牙模块LAYOUT注意事项 xff1a 常见的蓝牙模块为 xff1
  • PID参数调节总结

    原文链接 xff1a 点击打开链接 经验 xff1a 1 采样频率低 xff08 如500ms xff09 xff0c Kp一般是0 01级别 xff1b 采样频率高 xff08 如1ms xff09 xff0c Kp一般是1级别 2 先只
  • 为Keil添加注释的快捷键

    Keil刚装上是没有注释快捷键的 xff0c 可以自己添加 xff0c Edit Configuration xff0c 然后选择 Shortcut Keys 标签页 xff0c 下拉找到 Comment Selection xff0c 然
  • C语言__attribute__的使用

    一 介绍 GNU C 的一大特色就是 attribute 机制 attribute 可以设置函数属性 xff08 Function Attribute xff09 变量属性 xff08 Variable Attribute xff09 和类
  • ros(30):while(ros::ok()){}理解与使用示例

    while ros ok 理解 while ros ok 是ros的一种循环模式 xff0c 和ros Rate loop rate ros spinOnce 等结合可以控制程序的执行顺序 ros Rate loop rate 10 设置循
  • Jetson TX2更换软件源

    TX2的软件源为国外服务器 xff0c 网速会很慢 xff0c 需要换国内的ARM源 备份 etc lib路径下的source list文件 xff0c 然后在终端 xff08 按ctrl 43 alt 43 T打开 xff09 执行以下命
  • 使用Dockerfile创建镜像

    Dockerfile是一个文本格式的配置文件 xff0c 可以使用Dockerfile来快速创建自定义的镜像 一 基本结构 Dockerfile由一行行命令语句组成 xff0c 并且支持以 开头的注释行 一般而言 xff0c Dockerf
  • 高质量嵌入式Linux C编程 第二章 数据 学习笔记

    一 什么是数据类型 xff1f 数据类型包含两方面的内容 xff0c 数据的表示和对数据加工的操作 数据的全部可能表示构成数据类型的值的集合 xff0c 数据全部合理的操作构成数据类型的操作集合 二 什么是变量 xff1f 其值在作用域内可
  • 高质量嵌入式Linux C编程 第三章 运算符、表达式学习

    一 运算符有哪几类 xff1f xff08 1 xff09 算数运算符 xff1a 43 43 43 七种 xff08 2 xff09 关系运算符 xff1a gt lt 61 61 gt 61 lt 61 xff01 61 六种 xff0
  • 设计一种可全向移动的球形机器人

    一 前言 之前在网上看到一种球形机器人 xff0c 觉得很有趣 xff0c 而且原理也比较简单 xff0c 大概就是把一辆小车放在一个透明的亚克力球中 xff0c 控制小车使球体滚动 xff0c 姿态控制算法与平衡小车类似 xff0c 然后
  • ROS-Python

    用python来编写ros话题 服务方面常用的几个点 xff1a 话题topic 1 初始化节点 rospy init node 34 节点名字 34 举例 xff1a rospy init node 34 test 34 anonymou
  • 关于SBUS信号在单片机中的一些个人理解

    最近一直在弄关于SBUS的编码与解码这方面的内容 xff0c 虽然网上资料很多 xff0c 但是网上资料太杂 xff0c 我找的一些资料可能是我理解的问题 xff0c 所以我摒弃了一些骚操作 xff0c 对于一些单片机学得不精的人来说 xf