转载 https://blog.csdn.net/Brendon_Tan/article/details/89854751

STM32 Futaba SBUS协议解析
1. S.BUS
1.1 协议介绍

S.BUS是FUTABA提出的舵机控制总线,全称Serial Bus,别名S-BUS或SBUS,也称 Futaba S.BUS。
S.BUS是一个串行通信协议,也是一个数字串行通信接口(单线),适合与飞控连接。它可以连接很多设备,每个设备通过一个HUB与它相连,得到各自的控制信息。
S.BUS可以传输16个比例通道和2个数字(bool)通道。其硬件上基于RS232协议,采用TTL电平,但高位取反(负逻辑,低电平为“1”,高电平为“0”),通信波特率为100K(不兼容波特率115200)。

1.2 协议解析
通信接口:USART(TTL)
通信参数:1个起始位+8个数据位+偶校验位+2个停止位,波特率=100000bit/s,电平逻辑反转。
通信速率:每14ms(模拟模式)或7ms(高速模式)发送,即数据帧间隔为 11ms(模拟模式)或4ms(高速模式)。
数据帧格式:[1]
字节位 byte1 byte2-23 byte24 byte25
类型 开始字节 通道数据字节(含16个脉宽通道) 标志位字节(含2个数字通道) 结束字节
数据 0x0F 通道数据范围11Bits = [0,2047] 2个数字通道位+2个状态位 0x00
byte1:
startbyte = 0000 1111b (0x0F)

byte2-23:
databytes = 22bytes = 22 x 8Bits = 16 x 11Bits(CH1-16)
通道数据低位在前,高位在后,每个数据取11位,具体协议如下:
读取的databyte值:

byte 2 3 4 5 6 7 etc
内容 12345678 12345678 12345678 12345678 12345678 12345678 etc
转化后的通道值:

通道 CH01 CH02 CH03 CH04 etc
内容 67812345678 34567812345 81234567812 56781234567 etc
byte24:

Bit 7 6 5 4 3 2 1 0
含义 数字通道CH17 数字通道CH18 帧丢失位 故障保护激活位 N/A N/A N/A N/A
byte25:
endbyte = 0000 0000b (0x00)

2. 硬件设计
2.1 硬件参数
主控芯片:STM32F103VET6
接收端口:USART2(带反相电路)
S.BUS设备:walkera RX-SBUS[2](配DEVO 10遥控器)
2.2 反相电路
由于此芯片串口不带反相器,我们需要外部搭建反相电路。如果芯片串口内部带反相器,可以省略此步。反相电路设计如下图:

J1为4Pin排针,适配S.BUS接口,可5V输出为SBUS接收机供电。
J1的Pin-4接S.BUS数据发送端,连接一个由NPN三极管构成的反相器,将反相后的信号送入芯片USART2的RXD引脚。
3.程序设计
3.1 数据接收
分析一:根据 1.2 的协议解析,开始字节(0x0F)和结束字节(0x00)都是数据字节中很容易出现的字节,所以不能完全作为数据帧接收开始和结束的标志。
分析二:每个数据帧之间的间隔至少4ms,则可以利用这个空闲时间来接收数据帧。(需要设计一个系统时钟)
分析三:STM32 USART或UART有空闲中断,即检测到总线空闲(无数据传输),就产生中断。
接收程序设计:综上,利用USART2接收中断(RXNE)来接收每个字节,利用USART2空闲中断(IDLE)来判断数据帧是否接收完毕。

USART2 初始化函数代码如下:

/**
* @name SBUS_Configuration
* @brief Configure SBUS(Usart2) clock, gpio and nvic:
* SBUS_RX USART2_RX PD6
* @param None
* @retval None
*/
void SBUS_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);

GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);

// 波特率100000 8个数据位 偶校验位 2个停止位
USART_InitStructure.USART_BaudRate = 100000;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //注意这里是9个数据长度(8个数据位+偶校验位)
USART_InitStructure.USART_StopBits = USART_StopBits_2;
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx;

USART_Init(USART2, &USART_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

USART_Cmd(USART2, ENABLE);
}

USART2 中断函数代码如下:

uint8_t USART2_RX_BUF[26];

/**
* @name USART2_IRQHandler
* @brief This function handles USART2 Handler
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
uint8_t res;
uint8_t clear = 0;
static uint8_t Rx_Sta = 1;

if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
res =USART2->DR;
USART2_RX_BUF[Rx_Sta++] = res;
}
else if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
{
clear = USART2->SR;
clear = USART2->DR;
USART2_RX_BUF[0] = Rx_Sta - 1;
Rx_Sta = 1;
}
}

USART2_RX_BUF为接收缓存区,定义为26个字节,第一个字节USART2_RX_BUF[0]为接收到的字节个数,后面为接收到的数据。
USART2_RX_BUF[0]可以作为数据帧字节长度的判断。
中断服务函数具体解释请参考STM32 串口接收不定长字节数据。
3.2 数据处理
直接上代码:

uint16_t CH[18]; // 通道值
uint8_t rc_flag = 0;

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;
}
接收到的报文和解析出来的数据如下:
RX:0F E0 03 1F 58 C0 07 16 B0 80 05 2C 60 01 0B F8 C0 07 00 00 00 00 00 03 00
CH: 992 992 352 992 352 352 352 352 352 352 992 992 000 000 000 000
RX:0F 60 01 0B 58 C0 07 66 30 83 19 7C 60 06 1F F8 C0 07 00 00 00 00 00 03 00
CH: 352 352 352 992 1632 1632 1632 992 1632 992 992 992 000 000 000 000

接收的byte24数据并非和协议解析中的一样,无论断开遥控器还是连接遥控器,读取的值都是0x03。
接收机只支持12个通道,所以通道13-16没有值。
读取的通道值中间值为992,最大值为1632,最小值为352。
4. 最后
提供两个应用优化方向:

使用DMA+双缓存器+串口空闲中断读取和解析数据,提升MCU的工作效率。
将读取的通道值转化成脉宽(0.5-2.5ms)输出,用来控制模拟信号设备。
本协议解析就写到这里。

stm32 解析sbus的更多相关文章

  1. STM32 解析futaba S-bus协议

    S-bus为futaba使用的串行通信协议.实际上为串口通信.但是有几点需要注意: 在大端小端上,网上资料都说的不是很清楚: 跟TTL串口信号相比,S-bus的逻辑电平是反的,需用如下电路对电平反相, ...

  2. 1-关于单片机通信数据传输(中断发送,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)

    补充: 程序优化 为避免普通发送和中断发送造成冲突(造成死机,复位重启),printf修改为中断发送 写这篇文章的目的呢,如题目所言,我承认自己是一个程序猿.....应该说很多很多学单片机的对于... ...

  3. stm32串口之存储与解析

    最近在做一个小项目,需要用stm32串口接受Arduino发送的一个不定长的数据,并且解析数据,执行其中的命令:秉着不在中断中做过多任务的思想,我们将从串口中接受到的字符放到一个数组当中. 定义数组 ...

  4. 解析stm32的时钟

    STM32 时钟系统  http://blog.chinaunix.net/uid-24219701-id-4081961.html STM32的时钟系统 ***   http://www.cnblo ...

  5. stm32串口接收中断协议解析

    借鉴了文章:<stm32串口中断接收方式详细比较> 文章地址:http://blog.csdn.net/kevinhg/article/details/40186169 串口的配置这里不做 ...

  6. 解析 STM32 的库函数

    解析 STM32 的库函数意法半导体在推出 STM32 微控制器之初,也同时提供了一套完整细致的固件开发包,里面包含了在 STM32 开发过程中所涉及到的所有底层操作.通过在程序开发中引入这样的固件开 ...

  7. STM32 CAN总线标识符过滤器难点解析

    STM32 CAN总线标识符过滤器难点解析 原创 2016年05月31日 15:12:24 标签: stm32 / CAN 4910 CAN总线是目前应用非常多的一种总线,在汽车电子,航空航天中应用广 ...

  8. STM32启动文件深度解析

    STM32启动过程全面解析,包括启动过程的介绍.启动代码的陈列以及深入解析.相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化.ARM7/ARM9 ...

  9. 4.4 使用STM32控制MC20进行GPS帧数据解析

    需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...

随机推荐

  1. Perl 笔记

    目录 Perl 学习 常用记录 基础 1. 运行perl 2. 字符串 3. 变量 4. 条件 5. 循环 6. 运算符 7. 时间日期 8. 子程序(函数) 9. 引用 10. 格式化输出 11. ...

  2. GO第归

    Go 语言递归函数 递归,就是在运行的过程中调用自己. 语法格式如下: func recursion() {    recursion() /* 函数调用自身 */ } func main() {   ...

  3. PW数据库ER图

  4. 前缀和-Big Water Problem (牛客)

    链接:https://ac.nowcoder.com/acm/problem/15164 题目描述 给一个数列,会有多次询问,对于每一次询问,会有两种操作: 1:给定两个整数x, y, 然后在原数组的 ...

  5. MySQL高可用之MHA配置

    本文简单介绍了MySQL的高可用实现方式之一的MHA MHA:Master High Availability,对主节点进行监控,可实现自动故障转移至其它从节点:通过提升某一从节点为新的主节点,基于主 ...

  6. java窗口程序字符串时间转成时间戳

    pom.xml 文件: ?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  7. sqllab less-1

    1.访问sqllab 的less-1 按提示加入http://10.9.2.81/Less-1/?id=1 2. 后面加入单引号,发生报错http://10.9.2.81/Less-1/?id=1‘ ...

  8. Beautisoup库

    所看视频: https://www.bilibili.com/video/av9784617/?p=34 一, Beautifulsoup是一个可以从HTML或XML文件中提取数据的Python库,它 ...

  9. Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2)B(SET)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;int a[2007];set<int& ...

  10. windows下代码规范检测工具sonarqube安装与使用,含与maven的结合

    一.首先下载sonarqube   地址 : https://www.sonarqube.org/downloads/   (最新版本支持java11+,博主下载支持java8的版本7.7), 下载S ...