SBUS介绍
SBUS是Futaba公司定义的一种串口通信协议,Futaba的产品应用越来越广泛,不论是航模,无人机,还是机器人,遥控车,总能有它的身影。SBUS是一个接收机串行总线输出,通过这根总线,可以获得遥控器上所有通道的数据。目前很多模型及无人机电子设备都支持SBUS总线的接入。使用SBUS总线获取通道数据,效率高的,而且节省硬件资源,只需要一根线即可获取所有通道的数据。
官网网址:
https://os.mbed.com/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/
硬件介绍
和TTL串口信号相比,sbus的逻辑电平是反的,并且是硬件取反,软件取反是无效的;硬件取反的电路图如下:
协议介绍
串口配置为波特率100kbps,8位数据,偶校验(even),2位停止位,无流控。
链接https://mbed.org/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/说明了S-bus帧格式。每帧25个字节,按照如下顺序排列:
[startbyte] [data1] [data2] … [data22] [flags][endbyte]
起始字节startbyte = 11110000b (0xF0),但实际上STM32(ARM核)收到的是0x0F。中间22个字节就是16个通道的数据了,为什么是16个通道?因为22x8=11x16,每个通道用11bit表示,范围是0-2047。波形图如下:
基本而言,data1为ch1的低8位,data2的低3位为ch1的高三位,data2的高5位是ch2的低5位,data3的低6位是ch2的高6位,以此类推,如下图所示:
代码介绍
sbus.c
#include "sbus.h"
==说明:我所用的遥控器通过推动摇杆得到的最小值是193、中间值是993、最大值是1793==
#define RC_CHANNEL_MIN (-800)
#define RC_CHANNEL_MAX 800
#define SBUS_MIN_OFFSET 193
#define SBUS_MID_OFFSET 993
#define SBUS_MAX_OFFSET 1793
/**
*@brief 这是一个C语言版的MAP函数(映射函数)
*@param val:实际通道值; I_Min:输入最小值; I_Max:输入最大值;O_Min:输出最小值;O_Max:输出最大值
*@retval 实际输出值;
*@note none
*/
int output[16]={0};
float map(float val, float I_Min, float I_Max, float O_Min, float O_Max)
{
return(((val-I_Min)*((O_Max-O_Min)/(I_Max-I_Min)))+O_Min);
}
/**
*@brief 协议转换
*@param none
*@retval none
*@note none
*/
void sbusPreparePacket(void)
{
uint16_t SBUS_channels[16]={0};
if(Usart6_rx_buffer[0]==0x0f&& Usart6_rx_buffer[24]==0x00) //校验收到的数据是否正确
{
SBUS_channels[0] = (( Usart6_rx_buffer[1]| Usart6_rx_buffer[2]<<8) & 0x07FF);
SBUS_channels[1] = (( Usart6_rx_buffer[2]>>3 | Usart6_rx_buffer[3]<<5) & 0x07FF);
SBUS_channels[2] = (( Usart6_rx_buffer[3]>>6 | Usart6_rx_buffer[4]<<2 | Usart6_rx_buffer[5]<<10) & 0x07FF);
SBUS_channels[3] = (( Usart6_rx_buffer[5]>>1 | Usart6_rx_buffer[6]<<7) & 0x07FF);
SBUS_channels[4] = (( Usart6_rx_buffer[6]>>4 | Usart6_rx_buffer[7]<<4) & 0x07FF);
SBUS_channels[5] = (( Usart6_rx_buffer[7]>>7 | Usart6_rx_buffer[8]<<1 | Usart6_rx_buffer[9]<<9) & 0x07FF) ;
SBUS_channels[6] = (( Usart6_rx_buffer[9]>>2 | Usart6_rx_buffer[10]<<6) & 0x07FF) ;
SBUS_channels[7] = (( Usart6_rx_buffer[10]>>5| Usart6_rx_buffer[11]<<3) & 0x07FF) ;
SBUS_channels[8] = (( Usart6_rx_buffer[12] | Usart6_rx_buffer[13]<<8) & 0x07FF) ;
SBUS_channels[9] = (( Usart6_rx_buffer[13]>>3| Usart6_rx_buffer[14]<<5) & 0x07FF) ;
SBUS_channels[10] = (( Usart6_rx_buffer[14]>>6| Usart6_rx_buffer[15]<<2| Usart6_rx_buffer[16]<<10) & 0x07FF) ;
SBUS_channels[11] = (( Usart6_rx_buffer[16]>>1| Usart6_rx_buffer[17]<<7) & 0x07FF) ;
SBUS_channels[12] = (( Usart6_rx_buffer[17]>>4| Usart6_rx_buffer[18]<<4) & 0x07FF) ;
SBUS_channels[13] = (( Usart6_rx_buffer[18]>>7| Usart6_rx_buffer[19]<<1| Usart6_rx_buffer[20]<<9) & 0x07FF) ;
SBUS_channels[14] = (( Usart6_rx_buffer[20]>>2| Usart6_rx_buffer[21]<<6) & 0x07FF) ;
SBUS_channels[15] = (( Usart6_rx_buffer[21]>>5| Usart6_rx_buffer[22]<<3) & 0x07FF) ;
}
else
{
SBUS_channels[2]=993;
SBUS_channels[3]=993;
}
for(char i=0;i<16;i++)
{
output[i]=map(SBUS_channels[i],SBUS_MIN_OFFSET,SBUS_MAX_OFFSET, RC_CHANNEL_MIN, RC_CHANNEL_MAX); //具体到通道值
}
}
/**
*@brief 输出PWM(混控)
*@param offset_y:实际通道1的值;offset_x:实际通道2的值;c:给定常数
*@retval none
*@note none
*/
//应用到具体的通道 实现pwm输出
//以通道3为y轴,通道4为x轴
int a,b, pwm1_channels[2]={0};
void PWM_Out(int offset_y,int offset_x,float c )
{
sbusPreparePacket();
if(offset_y>=0)
{
a=(c*offset_y*offset_y+800*offset_x)/(800+c*offset_y); //电机1
b=(c*offset_y*offset_y-800*offset_x)/(800+c*offset_y); //电机2
pwm1_channels[0]=map(a,0,800,1500,2000);
pwm1_channels[1]=map(b,0,800,1500,2000);
}
if(offset_y<0)
{
a=(1-2*0.25)*offset_y-0.25*(100+offset_x);
b=(1-2*0.25)*offset_y-0.25*(100-offset_x);
pwm1_channels[0]=map(a,-800,0,1000,1500);
pwm1_channels[1]=map(b,-800,0,1000,1500);
}
pwm_out1( pwm1_channels[0]);
pwm_out2( pwm1_channels[1]);
}
sbus.h
#ifndef __SBUS_H
#define __SBUS_H
#include "main.h"
#include "usart.h"
#include "tim.h"
#include <stdbool.h>
extern int output[16];
#define pwm_out1(pwm) __HAL_TIM_SET_COMPARE(&htim15,TIM_CHANNEL_1,pwm)
#define pwm_out2(pwm) __HAL_TIM_SET_COMPARE(&htim15,TIM_CHANNEL_2,pwm)
uint16_t PWM_OUT1(uint16_t pwm_channel);
uint16_t PWM_OUT2(uint16_t pwm_channel);
float map(float val, float I_Min, float I_Max, float O_Min, float O_Max);
void sbusPreparePacket(void);
void GET_SBUSDATA(void);
void sbus_control(void);
void PWM_Out(int offset_y,int offset_x,float c );
#endif