【STM32】STM32单片机总目录

1、简介

S.BUS是一个串行通信协议,S.BUS是FUTABA提出的舵机控制总线,

S.bus使用RS232C串口的硬件协议作为自己的硬件运行基础。 使用TTL电平,即3.3V。 使用负逻辑,即低电平为“1”,高电平为“0”。 波特率:100000(100k),注意:不兼容波特率115200。

2、硬件电路

硬件取反电路如下,实际上就是一个很简单的三极管电路。Sbus的信号从基极输入,从集电极输出。基极输入 ‘0’,集电极上拉输出 ‘1’;基极输入 ‘1’,三极管导通,输出被拉低为 ‘0’,实现了反向。

或者

3、协议格式

协议帧很简洁,一帧包括25字节数据:

首部(1字节)+ 数据(22字节)+ 标志位(1字节)+ 结束符(1字节)
首部:起始字节 =0000 1111b (0x0f)
数据:22 字节的数据,分别代表16个通道的数据,也即是每个通道的值用了 11 位来表示,22x8/16 = 11这样,每个通道的取值范围为 0~2047,低位在前、高位在后
标志位:1字节,高四位从高到低依次表示:bit7:CH17数字通道bit6:CH16数字通道bit5:帧丢失(Frame lost)bit4:安全保护(Failsafe):失控保护激活位(0x10)判断飞机是否失控bit3~bit0:低四位不用
结束符:0x00

4、协议解析

4.1 解析方法

将数据解析为通道的方法

4.2 示例一

void Sbus_Data_Count(uint8_t *buf)
{CH[ 0] = ((int16_t)buf[ 2] >> 0 | ((int16_t)buf[ 3] << 8 )) & 0x07FF;CH[ 1] = ((int16_t)buf[ 3] >> 3 | ((int16_t)buf[ 4] << 5 )) & 0x07FF;CH[ 2] = ((int16_t)buf[ 4] >> 6 | ((int16_t)buf[ 5] << 2 )  | (int16_t)buf[ 6] << 10 ) & 0x07FF;CH[ 3] = ((int16_t)buf[ 6] >> 1 | ((int16_t)buf[ 7] << 7 )) & 0x07FF;CH[ 4] = ((int16_t)buf[ 7] >> 4 | ((int16_t)buf[ 8] << 4 )) & 0x07FF;CH[ 5] = ((int16_t)buf[ 8] >> 7 | ((int16_t)buf[ 9] << 1 )  | (int16_t)buf[10] <<  9 ) & 0x07FF;CH[ 6] = ((int16_t)buf[10] >> 2 | ((int16_t)buf[11] << 6 )) & 0x07FF;CH[ 7] = ((int16_t)buf[11] >> 5 | ((int16_t)buf[12] << 3 )) & 0x07FF;CH[ 8] = ((int16_t)buf[13] << 0 | ((int16_t)buf[14] << 8 )) & 0x07FF;CH[ 9] = ((int16_t)buf[14] >> 3 | ((int16_t)buf[15] << 5 )) & 0x07FF;CH[10] = ((int16_t)buf[15] >> 6 | ((int16_t)buf[16] << 2 )  | (int16_t)buf[17] << 10 ) & 0x07FF;CH[11] = ((int16_t)buf[17] >> 1 | ((int16_t)buf[18] << 7 )) & 0x07FF;CH[12] = ((int16_t)buf[18] >> 4 | ((int16_t)buf[19] << 4 )) & 0x07FF;CH[13] = ((int16_t)buf[19] >> 7 | ((int16_t)buf[20] << 1 )  | (int16_t)buf[21] <<  9 ) & 0x07FF;CH[14] = ((int16_t)buf[21] >> 2 | ((int16_t)buf[22] << 6 )) & 0x07FF;CH[15] = ((int16_t)buf[22] >> 5 | ((int16_t)buf[23] << 3 )) & 0x07FF;
}

4.3 示例二

示例二是一个完成的STM32 HAL库代码
1)头文件

// sbus.h
#ifndef SBUS_H
#define SBUS_H#include "sys.h"#define USART_BUF_SIZE      8       // HAL库USART接收Buffer大小
#define SBUS_DATA_SIZE      25      // 25字节#define SBUS_PIN        GPIO_PIN_2 | GPIO_PIN_3         // PA2--TX, PA3--RX
#define SBUS_GPIO       GPIOA
#define SBUS_ENCLK()    __HAL_RCC_GPIOA_CLK_ENABLE();   \__HAL_RCC_USART2_CLK_ENABLE();  //使能GPIOA时钟//使能USART2时钟struct SBUS_t{uint8_t head;                   // 1字节首部uint16_t ch[16];                // 16个字节数据uint8_t flag;                   // 1字节标志位uint8_t end;                    // 1字节结束
};void SBUS_Init(void);
void SbusParseTask(void *arg);#endif

2)源文件

// sbus.c
#include "sbus.h"
#include "delay.h"uint8_t usart_buf[USART_BUF_SIZE];
uint8_t sbus_rx_head = 0;               // 发现起始字节 0x0F
uint8_t sbus_rx_sta = 0;                // sbus 接收状态,0:未完成,1:已完成一帧接收
uint8_t sbus_rx_index;                  // 接收字节计数
uint8_t sbus_rx_buf[SBUS_DATA_SIZE];    // 接收sbus数据缓冲区struct SBUS_t sbus;                     // SBUS 结构体实例化UART_HandleTypeDef UART2_Handler;       // 串口2配置句柄void SBUS_Init(void)
{GPIO_InitTypeDef GPIO_Initure;// 时钟使能SBUS_ENCLK();// 串口初始化配置// 波特率100kbps,8位数据,偶校验(even),2位停止位,无流控。UART2_Handler.Instance          = USART2;UART2_Handler.Init.BaudRate     = 100000;UART2_Handler.Init.WordLength   = UART_WORDLENGTH_8B;UART2_Handler.Init.StopBits     = UART_STOPBITS_2;UART2_Handler.Init.Parity       = UART_PARITY_EVEN;UART2_Handler.Init.HwFlowCtl    = UART_HWCONTROL_NONE;UART2_Handler.Init.Mode         = UART_MODE_TX_RX;// 引脚 配置GPIO_Initure.Pin        = SBUS_PIN;         // PA2--TX, PA3--RXGPIO_Initure.Mode       = GPIO_MODE_AF_PP;GPIO_Initure.Pull       = GPIO_PULLUP;GPIO_Initure.Speed      = GPIO_SPEED_HIGH;GPIO_Initure.Alternate  = GPIO_AF7_USART2;HAL_GPIO_Init(GPIOA, &GPIO_Initure);// 中断配置HAL_NVIC_EnableIRQ(USART2_IRQn);HAL_NVIC_SetPriority(USART1_IRQn, 3, 4);HAL_UART_Init(&UART2_Handler);                                              //HAL_UART_Init()会使能UART2HAL_UART_Receive_IT(&UART2_Handler, (uint8_t *)usart_buf, USART_BUF_SIZE);  //该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}/* USART2 中断服务函数                                                            */
/* 实现对S.BUS协议缓存,头部为 0x0F,结尾为 0x00, 中间22Bytes16通道数据,1Byte标志符 */
void USART2_IRQHandler(void)                                            //中断函数
{uint8_t chr;if ((__HAL_UART_GET_FLAG(&UART2_Handler, UART_FLAG_RXNE) != RESET)) // 接收中断{HAL_UART_Receive(&UART2_Handler, &chr, 1, 1000);                // 接收一个字符if (sbus_rx_sta == 0)                                           // 接收未完成{if ((chr == 0x0F) || sbus_rx_head)                          // 找到首字节或已经找到首字节{sbus_rx_head = 1;                                       // 标明已经找到首字母if (sbus_rx_index < SBUS_DATA_SIZE)                     // 未接收到25个字符{sbus_rx_buf[sbus_rx_index] = chr;                   // 不断接收sbus_rx_index ++;}else                                                    // 接收到25个字符了{sbus_rx_sta = 1;                                    // 接收完成sbus_rx_head = 0;                                   // 清零,准备下一次接收sbus_rx_index = 0;}}}}HAL_UART_IRQHandler(&UART2_Handler);
}/* 对SBUS协议数据进行解析                                                      */
/* 实现对S.BUS协议缓存,头部为 0x0F,结尾为 0x00, 中间22Bytes16通道数据,1Byte标志符 */
void SbusParseTask(void *arg)
{while (1){if(sbus_rx_sta==1)                          // 接收完一帧{NVIC_DisableIRQ(USART2_IRQn);           // 要关闭中断,防止读写混乱sbus.head = sbus_rx_buf[0];             // 首部sbus.flag = sbus_rx_buf[23];            // 标志符sbus.end  = sbus_rx_buf[24];            // 结尾sbus.ch[0] =((sbus_rx_buf[2]<<8)  + (sbus_rx_buf[1])) & 0x07ff;          sbus.ch[1] =((sbus_rx_buf[3]<<5)  + (sbus_rx_buf[2]>>3)) & 0x07ff;sbus.ch[2] =((sbus_rx_buf[5]<<10) + (sbus_rx_buf[4]<<2) + (sbus_rx_buf[3]>>6)) & 0x07ff;sbus.ch[3] =((sbus_rx_buf[6]<<7)  + (sbus_rx_buf[5]>>1)) & 0x07ff;sbus.ch[4] =((sbus_rx_buf[7]<<4)  + (sbus_rx_buf[6]>>4)) & 0x07ff;sbus.ch[5] =((sbus_rx_buf[9]<<9)  + (sbus_rx_buf[8]<<1) + (sbus_rx_buf[7]>>7)) & 0x07ff;  sbus.ch[6] =((sbus_rx_buf[10]<<6) + (sbus_rx_buf[9]>>2)) & 0x07ff;sbus.ch[7] =((sbus_rx_buf[11]<<3) + (sbus_rx_buf[10]>>5)) & 0x07ff;sbus.ch[8] =((sbus_rx_buf[13]<<8)  + sbus_rx_buf[12]) & 0x07ff;sbus.ch[9] =((sbus_rx_buf[14]<<5)  + (sbus_rx_buf[13]>>3)) & 0x07ff;sbus.ch[10]=((sbus_rx_buf[16]<<10) + (sbus_rx_buf[15]<<2) + (sbus_rx_buf[14]>>6)) & 0x07ff;sbus.ch[11]=((sbus_rx_buf[17]<<7)  + (sbus_rx_buf[16]>>1)) & 0x07ff;sbus.ch[12]=((sbus_rx_buf[18]<<4)  + (sbus_rx_buf[17]>>4)) & 0x07ff;sbus.ch[13]=((sbus_rx_buf[20]<<9)  + (sbus_rx_buf[19]<<1) + (sbus_rx_buf[18]>>7)) & 0x07ff;sbus.ch[14]=((sbus_rx_buf[21]<<6) + (sbus_rx_buf[20]>>2)) & 0x07ff;sbus.ch[15]=((sbus_rx_buf[22]<<3) + (sbus_rx_buf[21]>>5)) & 0x07ff;printf("======================================\r\n");printf("正常: head=0x0F, flag=0x00, end=0x00\r\n\r\n");printf("head: %d\r\n", sbus.head);printf("  %d, %d, %d, %d\r\n", sbus.ch[0], sbus.ch[1], sbus.ch[2], sbus.ch[3]);printf("  %d, %d, %d, %d\r\n", sbus.ch[4], sbus.ch[5], sbus.ch[6], sbus.ch[7]);printf("  %d, %d, %d, %d\r\n", sbus.ch[8], sbus.ch[9], sbus.ch[10], sbus.ch[11]);printf("  %d, %d, %d, %d\r\n", sbus.ch[12], sbus.ch[13], sbus.ch[14], sbus.ch[15]);printf("flag: %d\r\n", sbus.flag);printf("end: %d\r\n", sbus.end);printf("======================================\r\n\r\n");delay_ms(500);                          // 先做完延时再开启中断与下一次捕获,否则延时期间中断到来,没有达到预期效果NVIC_EnableIRQ(USART2_IRQn);            // 打开串口中断sbus_rx_sta = 0;                        // 准备下一次接收   }else{delay_ms(500);                          // 免得异常时,到此处使得低优先级任务无法执行}}
}

【SBUS】一文看懂SBUS协议相关推荐

  1. MQTT协议图解,一文看懂MQTT协议数据包(真实报文数据解析解释)

    文章目录 一.MQTT协议 二.协议详解 2.1 协议结构 2.1.1 固定报头 2.1.2 可变报头 2.1.3 有效载荷 三.具体协议报文详解 3.1 连接服务器报文详解 3.2 发布消息报文详解 ...

  2. 一文看懂PPP协议——PPP协议简介

    今天给大家介绍一下PPP协议的相关内容,文章浅显易懂,特别适合0基础同学.本文主将主要从PPP概述.PPP链路建立过程和PPP认证三个角度对PPP协议进行讲解. 一.PPP概述 PPP,point-t ...

  3. 一文看懂Modbus协议

    目录 1.协议简介 2.协议格式 3.数据模型 1.协议简介 自从 1979 年出现工业串行链路的事实标准以来,Modbus使成千上万的自动化设备能够通信.Modbus 是OSI模型第 7 层上的应用 ...

  4. 信息如何实现病毒式传播?一文看懂Gossip协议

    来源 | 架构之美 责编 | 寇雪芹 头图 | 下载于视觉中国 起源 Gossip protocol 也叫 Epidemic Protocol (流行病协议).Gossip protocol在1987 ...

  5. 一文看懂单总线协议(1-wire)

    文章目录 一.什么是单总线协议? 1.单总线协议概念及特点 2.硬件结构 3.单总线协议应用 二.单总线协议时序(以DS18B20为例) 1.初始化(复位脉冲 + 存在脉冲) 2.读/写时序 (1)写 ...

  6. 海外LPWAN的王者是我,一文看懂Wi-Sun协议

    聚焦:芯产品,芯市场,芯技术 注: 欢迎加入文章底部的<物联坊间>微信 刚刚毕业的我,有参与城市照明系统的建设,包括城市公交系统,那个时候困扰我的一个问题,是这样一种线性的网络,如何才能稳 ...

  7. AMBA总线协议(三)——一文看懂AHB总线所有协议总结(AHB2 AHB-Lite AHB5 )

    AMBA AHB 总线协议介绍请点击以下链接: AMBA总线协议(一)--一文看懂APB总线协议 AMBA总线协议(二)一文看懂AMBA2 AHB2与AMBA3 AHB-Lite总线协议的区别 AMB ...

  8. AMBA总线协议(一)——一文看懂APB总线协议

    0.AMBA总线概括 AMBA AHB 总线协议介绍请点击以下链接: AMBA总线协议(二)一文看懂AMBA2 AHB2与AMBA3 AHB-Lite总线协议的区别 AMBA总线协议(三)--一文看懂 ...

  9. 无处 不在的无线智能——6g 的关键驱动与研究挑战_一文看懂什么是 6G

    原标题:一文看懂什么是 6G 2020年行将结束,随着5G网络的建设推进,以及3GPP R16版本的冻结,越来越多的人将关注焦点转移到6G身上. 7月14日,韩国三星电子发布了白皮书<下一代超连 ...

最新文章

  1. asp java 变量_ASP_用stack变量优化Java代码,  java程序包含了大量的对象 - phpStudy...
  2. java程序试岗内容_java程序员修炼之路基础篇四:继承
  3. castle 组件化开发应用配制示例
  4. 左神算法:用栈来求解限制后的汉诺塔问题(Java版)
  5. word List 12
  6. 普通二本的辛酸Android面试之路,满满干货指导
  7. 记一起因证书引发的支付宝支付异步通知接收不到的事故
  8. HTML5与Phonegap框架初步
  9. oracle手动锁表和解锁_Oracle锁表查询和解锁方法
  10. 百度的搜索好厉害,刚刚发文就能搜索到
  11. LS-DYNA系列_Mie-Gruneisen状态方程
  12. 根据收入计算个人所得税
  13. Fantom (FTM) 价格将在未来几天飙升 20%
  14. 斯坦福21秋季:实用机器学习-李沐课程笔记
  15. 看看清华人是如何学习和生活的
  16. kotlin用it还是this?
  17. OpenCV基础教程——视频的读取与写入(超详细+附代码)
  18. python matplotlib设置字体大小_python – Matplotlib表的字体大小
  19. HTML网页错误状态码
  20. 手机GPS天线设计对GPS定位有影响

热门文章

  1. java软件维护_软件维护手册
  2. 安装升级Erlang/OTP的方法
  3. Vue路由详解与映射关系 Vue-Router
  4. 科技查新报告需要注意什么?不通过的原因有哪些?
  5. 【汇正财经】国家股是什么意思?什么是国家股?
  6. linux 卸载java jdk1.6_linux下查看已经安装的jdk 并卸载jdk
  7. 结构优化软件SolidThinking Inspire的自学攻略
  8. BLOG系统设计文档
  9. Laravel使用Apidoc注解自动生成Api接口文档
  10. 《C语言从入门到精通》学习笔记001-C语言概述