【SBUS】一文看懂SBUS协议

这篇具有很好参考价值的文章主要介绍了【SBUS】一文看懂SBUS协议。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【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’,实现了反向。
sbus协议,stm32,单片机,网络,嵌入式硬件
或者
sbus协议,stm32,单片机,网络,嵌入式硬件

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 解析方法

将数据解析为通道的方法
sbus协议,stm32,单片机,网络,嵌入式硬件

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)源文件文章来源地址https://www.toymoban.com/news/detail-620184.html

// 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--RX
    GPIO_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()会使能UART2
    HAL_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协议的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SBUS协议介绍和标准例程

    SBUS全称serial-bus,是一种串口通信协议,广泛应用于航模遥控器(接收机)中。只用一根信号线就能传输多达16通道的数据,比多路PWM捕获高效且省资源。 TTL电平即3.3V。 使用负逻辑,即低电平为“1”,高电平为“0”。 波特率:100000(100k) 负逻辑必须 加硬件反相器 硬件反

    2024年02月12日
    浏览(33)
  • STM32+ESP-01s+EMQX实现单片机MQTT协议传输数据上云(二)STM32F103与ESP-01s的Usart通信,实现STM32连接上网上云

    单片机:STM32F103c8t6 WiFi模块:ESP8266-01s EMQX:自身服务器上搭载emq服务器或者借用emqx window 版本  USB TO TTL模块:CH340 因为CH340不能给ESP-01s供3.3V的电,所以测试时需要外加供电           本章中涉及到的技术原理主要为ESP01S wfi模块的AT指令通信,我在上一篇文章给大家提到了

    2024年02月16日
    浏览(56)
  • GD32单片机和STM32单片机的对比分析

    GD32单片机和STM32单片机都是基于Arm Cortex-M3/M4内核的32位通用微控制器,广泛应用于各种嵌入式系统和物联网领域。两者之间有很多相似之处,但也有一些不同之处,本文将从以下几个方面对比分析两者的特点、优势和开发成本。 GD32单片机采用的是二代的M3/M4内核,而STM32单片

    2024年02月16日
    浏览(63)
  • STM32单片机(一)STM32简介

    ❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋

    2024年02月10日
    浏览(60)
  • STM32单片机(二)STM32环境搭建

    ❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋

    2024年02月10日
    浏览(63)
  • STM32单片机开发-01 STM32介绍

    通过野火开发板学习单片机 从内核上分有Cortex-M0、M3、M4 和M7 F1 代表了基础型,基于Cortex-M3 内核,主频为72MHZ F4 代表了高性能,基于Cortex-M4 内核,主频180M。 数据手册:用于芯片选型和设计原理图 参考手册:用于编程时查阅 Icode总线 – 该总线讲M3内核的指令总线与闪存指令

    2024年01月21日
    浏览(63)
  • 【单片机】STM32单片机的各个定时器的定时中断程序,标准库,STM32F103

    高级定时器和普通定时器的区别(https://zhuanlan.zhihu.com/p/557896041): TIM1是高级定时器,使用的时钟总线是RCC_APB2Periph_TIM1,和普通定时器不一样。 timer.c timer.h 调用 timer.c timer.h 调用 timer.c timer.h 调用 timer.c timer.h 调用 timer.c timer.h 调用

    2024年02月07日
    浏览(58)
  • 【STM32】STM32单片机结构及部件原理

    STM32是目前比较常见并且多功能的单片机,要想学习STM32,首先要去了解它的基本构成部分以及各部分的原理。 单片机型号:正点原子STM32F103ZET6 目录 STM32内部结构总览图: 2.内部结构解析         1.内核 :STM32F103ZET6采用的是 ARM Cortex-M3 处理器,内核可以理解为单片机 处

    2023年04月08日
    浏览(51)
  • STM32单片机学习3--STM32控制键盘

    单片机型号:STM32F103C8T6 开发环境:Keil5 4种输入模式 上拉输入模式:在默认状态下(GPIO引脚无输入),读取得的GPIO引脚数据为1,高电平(与Vdd相连的为上拉电阻); 下拉输入模式:在默认状态下(GPIO引脚无输入),读取得的GPIO引脚数据为0,低电平(与Vss相连的为下拉电

    2024年02月10日
    浏览(60)
  • 【单片机】STM32单片机,定时器的输入捕获,基于捕获的频率计,STM32F103

    下面的定时器都具有输入捕获能力: 查看另一篇文章:https://qq742971636.blog.csdn.net/article/details/131471539 外部计数频率计的缺点:需要两个定时器配合,最高能测量的频率是否有限制我没具体尝试。 基于捕获的频率计的缺点:最高能测量的频率有限制。 TIM3_CH1 PWM PA6 10KHZ。 输入

    2024年02月14日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包