SBUS协议代码

文章底部附代码

一般来说,遥控器的接收机都有三根线,电源线,GND,SBUS信号线。

通过这根信号线可以获得遥控器所有通道的数据。

接收机图可以看到三根线。

另外,硬件上设计时,信号必须取反!

SBUS一般采用10000的波特率。

遥控器发给接收机的数据帧总长度25个字节:

(1)起始字节0x0F,一个字节8位

(2)24个通道Channel(每个通道11位,总共264位,占用24字节)。

数据范围:  0x000  到  0x7FF  (11位,即  0000 0000 000  到  1111 1111 111  )

数据解析:通过位运算从字节中提取通道数据,并组合成完整的11位数据。

(3)校验字节。

其中通道Channel里的帧格式如下:

• 起始位:1位

• 数据位:8位

• 校验位:1位

• 停止位:2位

所以每个通道有11位。

什么是通道Channel?

通道指的是可以独立控制的信号路径,每个通道可以传输一个独立的控制信号。

通过不同的通道,可以分别控制无人机或者小车的不同功能。

比如:

通道1,控制小车前进和后退,或者无人机的油门

通道2,控制左右原地转

通道3,控制上升下降

通道4,控制航拍摄像头的pitch轴

通道5,控制航拍摄像头的YAW轴

通道6,按一下能切换运动模式或者其它跟拍什么的模式。

所以。任何功能都可以,像SBUS协议有24个通道,你就可以根据你的需要,比如你在做无人机,那一般用几个通道就行,不需要那么多。

那你可能有疑问了

为什么一个通道可以控制左转或者右转呢?

它是通过解析SBUS数据帧中的特定通道值来控制模型的转向。

通道值较小(接近 0x000):通常表示向左转

通道值较大(接近  0x7FF):通常表示向右转

比如代码:

void Sbus_Data_Count(void)      
{
    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[0] 控制左右方向为例进行详细解释:

这行代码的目的是将buf[2]和buf[3]两个字节的数据组合成一个11位的值

1. 提取数据:

buf[2]  :第3个字节(从0开始计数),假设为0x1A,二进制表示为 0001 1010,八位即一个字节

buf[3]  :第4个字节,假设为0xB4,二进制表示为1011 0100,八位即一个字节

buf是一个数组,用作缓冲区(buffer)来临时存储通过USART接收到的数据帧,用于临时存储数据流。

我们知道在SBUS中,一个通道有11位,由于一个字节只有八位,所以需要两个字节来存储11位的数据。

你可能会有疑问。为什么从buf[2]开始呢,然后为什么buf[2]和buf[3]包含通道0的11位数据?

首先,我们知道我们操控遥控器传给接收机的数据帧,第一个字节是起始字节,所以占了buf[0]。

然后,通道数据从数据帧的第二个字节开始,即   buf[1]  。然而,由于每个通道的数据占用11位,而每个字节只有8位,因此一个通道的数据会跨越两个字节。

所以通道0,取的是buf[2]的8位和buf[3]的低3位拼成11位

2、位操作:

>> 0  :将   buf[2]   的低8位右移0位(即保持不变)。

<< 8  :将   buf[3]   左移8位。由于我们只考虑8位,所以实际上这会将原始值移到一个更高的字节位置,并在原位置补0。移动后,原始的8位值将占据高8位的位置,而低8位将被填充为0
 

|  :将两个结果进行按位或操作,组合成完整的11位数据。其中包含了   buf[2]   的低3位和   buf[3]   的高8位。

  0000 0000 0001 1010
| 1011 0100 0000 0000
-------------------
  1011 0100 0001 1010

即0xB42A

3. 掩码操作:

& 0x07FF  :通过掩码操作,确保数据范围为11位(  0x000  到  0x7FF  )

  1011 0100 0001 1010
& 0000 0111 1111 1111
-------------------
  0000 0100 0001 1010

完整代码:

c文件

#include "sbus.h"

void Usart5_Init(u32 bound)// RX PD2
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉

    GPIO_Init(GPIOD, &GPIO_InitStructure);
    //USART5 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_9b;//!字长为8位数据格式
    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(UART5, &USART_InitStructure); //初始化串口5

    //Usart5 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;//串口5中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级4
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、

    USART_Cmd(UART5, ENABLE);  //使能串口5

    USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);//接收到8位数据就中断一次
	USART_ITConfig(UART5, USART_IT_IDLE, ENABLE);
}

uint8_t buf[26];
void UART5_IRQHandler(void)
{
	uint8_t res;
	uint8_t clear = 0;
	static uint8_t Rx_Sta = 1;

if(USART_GetITStatus(UART5, USART_IT_RXNE) != RESET)
{
	res =UART5->DR;
	buf[Rx_Sta++] = res;
}
	//一包数据发送完成 准备调整一下后,去接收下一包数据 中间有4MS/14MS延迟供你来检测
	else if(USART_GetITStatus(UART5, USART_IT_IDLE) != RESET)
	{//检测到空闲线路时,该位由硬件置 1,该位由软件序列清零(读入 USART_SR 寄存器,然后读入 USART_DR 寄存器)。
		clear = UART5->SR;
		clear = UART5->DR;
		buf[0] = Rx_Sta - 1;//在Xms内接收到的数据数量
		Rx_Sta = 1;
	}

}

uint16_t CH[18]; // 通道值
uint8_t rc_flag = 0;
void Sbus_Data_Count(void)      
{
	CH[0] = ((int16_t)buf[ 2] >> 0 | ((int16_t)buf[ 3] << 8 )) & 0x07FF;//you 左右方向 0000 0111 1111 1111
	CH[1] = ((int16_t)buf[ 3] >> 3 | ((int16_t)buf[ 4] << 5 )) & 0x07FF;//you 上下方向
	CH[2] = ((int16_t)buf[ 4] >> 6 | ((int16_t)buf[ 5] << 2 ) | (int16_t)buf[ 6] << 10 ) & 0x07FF;//zou 上下方向
	CH[3] = ((int16_t)buf[ 6] >> 1 | ((int16_t)buf[ 7] << 7 )) & 0x07FF;//zou 左右方向
	CH[4] = ((int16_t)buf[ 7] >> 4 | ((int16_t)buf[ 8] << 4 )) & 0x07FF;//zou 摇杆
	CH[5] = ((int16_t)buf[ 8] >> 7 | ((int16_t)buf[ 9] << 1 ) | (int16_t)buf[10] << 9 ) & 0x07FF;//you 摇杆
	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;*/

.h文件

#ifndef _SBUS_H
#define _SBUS_H

#include "sys.h"
extern uint16_t CH[18]; 
void Usart5_Init(u32 bound);
void Sbus_Data_Count(void);
#endif

代码理解如下:

使用串口5的中断。只要接收到8位数据就进入中断

这里可以看到,这个buf数组就是用来接收遥控器传过来的数据帧的。每次发8位

先将串口5的DR数据寄存器赋给res,然后buf[Rx_Sta++]从1开始累加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值