STM32解析SBUS信号例程详解

2023-05-16

文章目录

  • 1. SBUS信号简介
  • 2. STM32F7解析SBUS信号例程
    • (1) 串口配置
    • (2) 串口中断接收
    • (3) 信号解析

1. SBUS信号简介

最近在搞一个项目的通信和控制,用到了SBUS,记录一下心得。


SBUS全称serial-bus,是一种串口通信协议,广泛应用于航模遥控器(接收机)中。只用一根信号线就能传输多达16通道的数据,比多路PWM捕获高效且省资源。

  1. 串口配置:
    100k波特率,8位数据位,2位停止位,偶校验(EVEN),无控流,25个字节。
  2. 协议格式:(8字节)
    [startbyte] [data1][data2]…[data22][flags][endbyte]
    startbyte=0x0f;
    endbyte=0x00;
    data1…data22: LSB(低位在前),对应16个通道(ch1-ch16),每个通道11bit(22 × 8=16 × 11);
    flag位标志遥控器的通讯状态,我使用的乐迪AT9S在遥控器通上的时候是0x00,断开的时候是0xC0,可以通过查询flag位来采取失控保护。
  3. 数据范围
    航模遥控器输出的PWM值是1000~2000,中值为1500,sbus输出的会不一样,例如乐迪AT9S的范围为300 ~ 1700,中值1000,这个我估计跟遥控器厂家有关。
  4. sbus的负逻辑
    这个地方一定要万分注意,必须加硬件反相器,因为SBUS的信号是采用的负逻辑,也就是电平相反,不要试图在软件里面取反,因为软件里面只能操作数据位(记得串口配置里面的数据位8么),你是操作不了停止位、校验位啥的!!
    如果是自己画板子也很简单,如图所示
    在这里插入图片描述5. 数据读取
    一般的串口调试助手可能没有100K波特率的选项,推荐一个串口调试助手MicroLab,可以自定义串口波特率,还有其他好功能自己探索叭。

2. STM32F7解析SBUS信号例程

清楚了通信协议,解析就很简单了。我使用的是正点原子的阿波罗F7开发板,其他的板子是一样的。

(1) 串口配置

首先一些变量声明,串口uart.c里用到的

#define USART_REC_LEN  			100  	//定义最大接收字节数 200
#define RXBUFFERSIZE   			1 		//缓存大小

u8 USART1_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
u16 USART1_RX_STA = 0; //接收状态标记
u8 aRxBuffer1[RXBUFFERSIZE];		  //HAL库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; //UART句柄

串口初始化函数

void uart1_init(u32 bound)
{
	//UART 初始化设置
	UART1_Handler.Instance = USART1;					//USART1
	UART1_Handler.Init.BaudRate = bound;				//波特率
	UART1_Handler.Init.WordLength = UART_WORDLENGTH_9B; //字长为8位数据格式
	UART1_Handler.Init.StopBits = UART_STOPBITS_1;		//一个停止位
	UART1_Handler.Init.Parity = UART_PARITY_EVEN;		//无奇偶校验位
	UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
	UART1_Handler.Init.Mode = UART_MODE_TX_RX;			//收发模式
	HAL_UART_Init(&UART1_Handler);						//HAL_UART_Init()会使能UART1

	HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer1, RXBUFFERSIZE); //该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	//GPIO端口设置
	GPIO_InitTypeDef GPIO_Initure;
	if (huart->Instance == USART1) //如果是串口1,进行串口1 MSP初始化
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();  //使能GPIOA时钟
		__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟

		GPIO_Initure.Pin = GPIO_PIN_9;			  //PA9
		GPIO_Initure.Mode = GPIO_MODE_AF_PP;	  //复用推挽输出
		GPIO_Initure.Pull = GPIO_PULLUP;		  //上拉
		GPIO_Initure.Speed = GPIO_SPEED_FAST;	  //高速
		GPIO_Initure.Alternate = GPIO_AF7_USART1; //复用为USART1
		HAL_GPIO_Init(GPIOA, &GPIO_Initure);	  //初始化PA9

		GPIO_Initure.Pin = GPIO_PIN_10;		 //PA10
		HAL_GPIO_Init(GPIOA, &GPIO_Initure); //初始化PA10

#if EN_USART1_RX
		HAL_NVIC_EnableIRQ(USART1_IRQn);		 //使能USART1中断通道
		HAL_NVIC_SetPriority(USART1_IRQn, 3, 2); //抢占优先级3,子优先级3
#endif
	}
}

这里有个诡异的地方就是stm32要设置成9个数据位,一个停止位,我一开始按照8个数据位、两个停止位读出来的数据是错的,后来改了之后才正常了。是不是和stm32内部的串口配置有关,哪位大神弄明白了告诉我哈。

(2) 串口中断接收

串口中断函数,在中断函数里面接收数据,进行SBUS信号解析。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	int i;
	while (huart->Instance == USART1) //如果是串口1
	{
		USART1_RX_BUF[USART1_RX_STA] = aRxBuffer1[0];
		if (USART1_RX_STA == 0 && USART1_RX_BUF[USART1_RX_STA] != 0x0F) break; //帧头不对,丢掉
		USART1_RX_STA++;
		if (USART1_RX_STA > USART_REC_LEN) USART1_RX_STA = 0;  ///接收数据错误,重新开始接收
		if (USART1_RX_BUF[0] == 0x0F && USART1_RX_BUF[24] == 0x00 && USART1_RX_STA == 25)	//接受完一帧数据
		{
			update_sbus(USART1_RX_BUF);
			for (i = 0; i<25; i++)		//清空缓存区
				USART1_RX_BUF[i] = 0;
			USART1_RX_STA = 0;
		}
		break;
	}
}

(3) 信号解析

上面中断函数里面有一个update_sbus函数,原型为u8 update_sbus(u8 *buf),解析subs信号全靠它了!!新建一个sbus.c文件,输入如下代码

#include "sbus.h"

SBUS_CH_Struct SBUS_CH;

//将sbus信号转化为通道值
u8 update_sbus(u8 *buf)
{
    int i;
    if (buf[23] == 0)
    {
        SBUS_CH.ConnectState = 1;
        SBUS_CH.CH1 = ((int16_t)buf[ 1] >> 0 | ((int16_t)buf[ 2] << 8 )) & 0x07FF;
        SBUS_CH.CH2 = ((int16_t)buf[ 2] >> 3 | ((int16_t)buf[ 3] << 5 )) & 0x07FF;
        SBUS_CH.CH3 = ((int16_t)buf[ 3] >> 6 | ((int16_t)buf[ 4] << 2 ) | (int16_t)buf[ 5] << 10 ) & 0x07FF;
        SBUS_CH.CH4 = ((int16_t)buf[ 5] >> 1 | ((int16_t)buf[ 6] << 7 )) & 0x07FF;
        SBUS_CH.CH5 = ((int16_t)buf[ 6] >> 4 | ((int16_t)buf[ 7] << 4 )) & 0x07FF;
        SBUS_CH.CH6 = ((int16_t)buf[ 7] >> 7 | ((int16_t)buf[ 8] << 1 ) | (int16_t)buf[9] << 9 ) & 0x07FF;
        SBUS_CH.CH7 = ((int16_t)buf[ 9] >> 2 | ((int16_t)buf[10] << 6 )) & 0x07FF;
        SBUS_CH.CH8 = ((int16_t)buf[10] >> 5 | ((int16_t)buf[11] << 3 )) & 0x07FF;
        SBUS_CH.CH9 = ((int16_t)buf[12] << 0 | ((int16_t)buf[13] << 8 )) & 0x07FF;
        SBUS_CH.CH10 = ((int16_t)buf[13] >> 3 | ((int16_t)buf[14] << 5 )) & 0x07FF;
        SBUS_CH.CH11 = ((int16_t)buf[14] >> 6 | ((int16_t)buf[15] << 2 ) | (int16_t)buf[16] << 10 ) & 0x07FF;
        SBUS_CH.CH12 = ((int16_t)buf[16] >> 1 | ((int16_t)buf[17] << 7 )) & 0x07FF;
        SBUS_CH.CH13 = ((int16_t)buf[17] >> 4 | ((int16_t)buf[18] << 4 )) & 0x07FF;
        SBUS_CH.CH14 = ((int16_t)buf[18] >> 7 | ((int16_t)buf[19] << 1 ) | (int16_t)buf[20] << 9 ) & 0x07FF;
        SBUS_CH.CH15 = ((int16_t)buf[20] >> 2 | ((int16_t)buf[21] << 6 )) & 0x07FF;
        SBUS_CH.CH16 = ((int16_t)buf[21] >> 5 | ((int16_t)buf[22] << 3 )) & 0x07FF;
        return 1;
    }
    else 
    {
        SBUS_CH.ConnectState = 0;
        return 0;
    }
}

u16 sbus_to_pwm(u16 sbus_value)
{
    float pwm;
    pwm = (float)SBUS_TARGET_MIN + (float)(sbus_value - SBUS_RANGE_MIN) * SBUS_SCALE_FACTOR;
    //                1000                                   300              1000/1400
    if (pwm > 2000) pwm = 2000;
    if (pwm < 1000) pwm = 1000;
    return (u16)pwm;
}

上面定义了一个SBUS_CH_Struct 结构体类型的变量SBUS_CH,该结构体在sbus.h中定义

typedef struct
{
	uint16_t CH1;//通道1数值
	uint16_t CH2;//通道2数值
	uint16_t CH3;//通道3数值
	uint16_t CH4;//通道4数值
	uint16_t CH5;//通道5数值
	uint16_t CH6;//通道6数值
    uint16_t CH7;//通道7数值
    uint16_t CH8;//通道8数值
    uint16_t CH9;//通道9数值
    uint16_t CH10;//通道10数值
    uint16_t CH11;//通道11数值
    uint16_t CH12;//通道12数值
    uint16_t CH13;//通道13数值
    uint16_t CH14;//通道14数值
    uint16_t CH15;//通道15数值
    uint16_t CH16;//通道16数值
	uint8_t ConnectState;//遥控器与接收器连接状态 0=未连接,1=正常连接
}SBUS_CH_Struct;

u16 sbus_to_pwm(u16 sbus_value)很好理解了,就是把sbus的值转化为标准的1000-2000的pwm值,因为我用的遥控器sbus值是300-1700,大家用的时候具体数值到时候可以通过串口直接读出来看看。
这样就读出了16个通道的数据啦。同时通过读取ConnectState位判断遥控器的状态,在主函数中采取失控保护。


上面这段解析数据的代码是国际通用的,可以用在任何使用sbus协议的场合,可以很方便的移植到arduino、51、树莓派上面。

最后main函数里面就很简单了,只注意初始化串口设置为100K波特率。

void main()
{
	/* 省略 */
	uart1_init(100000);
	/* 省略 */
}

本文代码已上传至CSDN,独乐乐不如众乐乐,提供免费下载,点击下载,欢迎交流讨论。别忘了点个赞哦!

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

STM32解析SBUS信号例程详解 的相关文章

  • 如何更改闪存的起始地址?

    我正在使用 STM32F746ZG 和 FreeRTOS Flash的起始地址是0x08000000 但我想把它改成0x08040000 我通过谷歌搜索了这个问题 但没有找到解决方案 我更改了链接器脚本 如下所示 MEMORY RAM xr
  • 初始化 ST-Link 设备时出错 - 无法连接到设备

    我目前正在使用 ST Link 调试器对我的 STM32F3 Discovery 板进行编程 我使用的IDE是Atollic TrueStudio 5 5 2 现在我面临一个非常奇怪的问题 那就是我不断收到消息 初始化 ST Link 设备
  • 在地址“0xXXXXXX”处中断,没有可用的调试信息,或在程序代码之外

    配置 使用 Nucleo L476RG 使用 GNU ARM Eclipse 我从 STM32CubeMX 生成了一个极简代码 我已经在我的板载 ST Link 中刷新了 J link 驱动程序 一直在尝试为我的代码运行调试器 但我的程序计
  • 优化 ARM Cortex M3 代码

    我有一个 C 函数 它尝试将帧缓冲区复制到 FSMC RAM 这些函数将游戏循环的帧速率降低至 10FPS 我想知道如何分析反汇编的函数 我应该计算每个指令周期吗 我想知道CPU把时间花在哪里 在哪个部分 我确信该算法也是一个问题 因为它的
  • 133-基于stm32单片机停车场车位管理系统Proteus仿真+源程序

    资料编号 133 一 功能介绍 1 采用stm32单片机 4位数码管 独立按键 制作一个基于stm32单片机停车场车位管理系统Proteus仿真 2 通过按键进行模拟车辆进出 并且通过程序计算出当前的剩余车位数量 3 将剩余的车位数量显示到
  • 136-基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真+源程序

    资料编号 136 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 蜂鸣器 制作一个基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真 2 通过DHT11传感器检测当前温湿度 并且显示到L
  • rt-thread studio中新建5.0不能用

    文章目录 一 版本对比 二 文件和文件夹打斜杠 在使用RT Thread studio创建新工程5 0版本的时候 结果发现新建完成之后程序不能正常运行 但是创建4 10版本的时候却能运行 那肯定是新版本出现了BUG 一 版本对比 首先对比了
  • 物联网网关

    物联网网关是 连接物联网设备和互联网的重要桥梁 它负责将物联网设备采集到的数据进行处理 存储和转发 使其能够与云端或其它设备进行通信 物联网网关的作用是实现物联网设备与云端的无缝连接和数据交互 物联网网关功能 数据采集 物联网网关可以从物联
  • 毕业设计 江科大STM32的智能温室控制蓝牙声光报警APP系统设计

    基于STM32的智能温室控制蓝牙声光报警APP系统设计 1 项目简介 1 1 系统构成 1 2 系统功能 2 部分电路设计 2 1 stm32f103c8t6单片机最小系统电路设计 2 2 LCD1602液晶显示电路设计 2 2 风
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • STM32 暂停调试器时冻结外设

    当到达断点或用户暂停代码执行时 调试器可以停止 Cortex 中代码的执行 但是 当皮质停止在暂停状态下执行代码时 调试器是否会冻结其他外设 例如 DMA UART 和定时器 您只能保留时间 r 取决于外围设备 我在进入主函数时调用以下代码
  • STM32的HAL中实现单按、长按和双按功能

    我正在尝试实现单击 双击和长按功能来执行不同的功能 到目前为止 我已经理解了单击和长按的逻辑 但我不知道如何检测双击 至于代码 我使用计数器实现了单击和长按 但代码仅停留在第一个 if 条件上 bool single press false
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • Arm:objcopy 如何知道 elf 中的哪些部分要包含在二进制或 ihex 中?

    我正在开发一个项目 其中涉及解析arm elf 文件并从中提取部分 显然 elf 文件中有很多部分没有加载到闪存中 但我想知道 objcopy 到底如何知道要在二进制文件中包含哪些部分以直接闪存到闪存中 以arm elf文件的以下reade
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • 核心耦合内存在 STM32F4xx 上可执行吗?

    尝试从 STM32F429s CCM 运行代码 但每当我命中 CCM 中的第一条指令时 我总是会遇到硬故障 并且 IBUSERR 标志被设置 该指令有效且一致 STM32F4xx 是否可能不允许从 CCM 执行 数据访问效果良好 alios
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd

随机推荐

  • SLAM笔记五——EKF-SLAM

    上一节主要讲解了EKF的基本原理 xff0c 这一次主要关注如何将EKF算法应用在SLAM上 EKF SLAM 现在的问题就是解决下面这个概率分布的估计问题 xff1a 阴影部分为未知 这里我们需要确定均值和方差到底是什么 xff1f 假设
  • HTTP协议-报文解析

    概述 HTTP xff08 超文本传输协议 xff09 是一个基于请求与响应模式的 无状态的 应用层的协议 xff0c 常基于TCP的连接方式 HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成 请求消息和响应消息的组成 xff1
  • 站在巨人的肩膀上——Linux信号量操作

    感谢那些让我度过此学海的无名勇士 信号量简介 xff1a 在对于临界区资源管理的过程中 xff0c 多个程序同时访问一个共享资源经常容易引发一系列问题 xff1a 如死锁 xff0c 结果不唯一等等 xff0c 在1965年 xff0c 由
  • 详解常用的ROS内置消息类型

    1 std msgs 该类型是ROS内置的标准消息类型 xff0c 是最基础的消息类型 xff08 1 xff09 对于单类型 xff0c 下表是其与C 43 43 和python的对应关系 xff1a Primitive TypeSeri
  • 【Robomaster-ICRA-AI挑战赛跳坑篇】(二、TX2刷机)

    TX2刷机与程序下载 TX2安装在步兵车上作为机载计算机使用 xff0c 跑上层代码 xff0c RoboRTS代码托管在github上 xff1a https github com RoboMaster RoboRTS xff0c 目前一
  • 字符串目录判断

    tcschr tcsrchr 好处 xff1a 是可以不管是用unicode 编码还是其他 代码都不用改 C 43 43 标准库函数提供了字符和字符串的操作函数 xff0c 并提供了其UNICODE版本 xff0c 如 xff1a 1 tc
  • @Bean放入其引用Bean中初始化失败分析

    以下讨论的问题及术语均在SpringBoot框架下 xff0c 问题十分小众 xff0c 仅做整理记录 1 先说重点 Bean依赖属性的注入顺序 xff0c 与代码定义顺序无关 xff1b 最好是将 64 Bean注解配置的Bean放在 6
  • MPU6050+HMC5883+BMP180+GPS导航系统设计

    老师有个项目 xff0c 让我搞惯导这一块 虽然最后也没有用上廉价的MPU6050 xff0c 而是用了一两万的Xsens 但是本人还是想写一下MPU6050 xff0c 虽然技术含量不高 xff0c 但是写下来 xff0c 留个纪念吧 首
  • 使用BeanCopier抛出NullPointerException溯源

    问题 使用cglib提供的net sf cglib beans BeanCopier进行对象拷贝时 xff0c 抛出如下异常 xff1a Exception in thread span class token string 34 main
  • 自制Alfred/Wox插件推荐

    最近上手Alfred的使用 xff0c 日常工作中存在很多需要高频执行的连续性动作 xff0c 将这一系列动作封装成Workflow xff0c 通过命令触发 xff0c 对提升效率确有很大帮助 自己封装了一些简单的Workflow xff
  • Python删除某一目录下的空文件(夹)

    Python删除某一目录下的空文件 夹 用途 输入文件夹路径 xff0c 将此文件夹下所有的空文件夹和空文件删除 xff0c 算是文件操作的一个习作吧 我拿它做什么就不广而告之了 代码 span class hljs comment cod
  • Win10下pip的安装

    pip简介 pip 是一个安装和管理 Python 包的工具 xff0c 通过pip我们能够轻松地下载和卸载python的第三方包 原料 64位Windows10 专业版python 2 7 12 下载安装包 进入python官方网站 xf
  • Python爬虫爬取动态页面思路+实例(一)

    简介 有时候 xff0c 我们天真无邪的使用urllib库或Scrapy下载HTML网页时会发现 xff0c 我们要提取的网页元素并不在我们下载到的HTML之中 xff0c 尽管它们在浏览器里看起来唾手可得 这说明我们想要的元素是在我们的某
  • zerorpc-python官方入门

    原文地址 xff1a http www zerorpc io 一个易于使用的 xff0c 直观的 xff0c 跨语言的RPC zerorpc是一个在服务端进程上提供分布式通信的轻量级的 可靠的跨语言的库 它基于ZeroMQ和MessageP
  • Python保存json文件并格式化

    背景 最近自己搞些小东西 xff0c 需要用json文件存储些文件属性什么的 xff0c 但是发现用json包里的json dump 方法存json文件的效果好丑 xff08 其实是没仔细看方法 xff09 于是上网找了一份格式化json文
  • No module named 'django.templates'起因和解决

    当我跟着django官网上的教程写到template模板这一部分的时候 xff0c 出现了上述问题 span class hljs constant No span span class hljs class span class hljs
  • Celery ValueError: not enough values to unpack (expected 3, got 0)的解决方案

    背景 最近因项目需要 xff0c 学习任务队列Celery的用法 xff0c 跟着官网写Demo xff0c 出现如题错误 xff0c 最终在github的Issues里找到解决办法 xff0c 记录如下 场景还原 本地环境如下 xff1a
  • 震惊!Selenium分手PhantomJS

    背景 今天本地调试基于Selenium 43 PhantomJS的动态爬虫程序顺利结束后 xff0c 着手部署到服务器上 xff0c 刚买的热乎的京东云 xff0c 噼里啪啦一顿安装环境 xff0c 最后跑的时候报了这么个错误 xff1a
  • 基于labview的姿态测量系统上位机界面编写

    当时学习VB是为了写个上位机去控制LED亮灭 xff0c 相信大家学习51 stm32都是从流水灯开始的 xff0c 就像那句 hello world 一样经典 后来学习了LABVIEW xff0c 决定用它写个界面 当时主要是想用LABV
  • STM32解析SBUS信号例程详解

    文章目录 1 SBUS信号简介2 STM32F7解析SBUS信号例程 xff08 1 xff09 串口配置 xff08 2 xff09 串口中断接收 xff08 3 xff09 信号解析 1 SBUS信号简介 最近在搞一个项目的通信和控制