✅ 操作成功!

航模遥控器

发布时间:2023-06-08 作者:admin 来源:文学

航模遥控器

航模遥控器

-

2023年2月25日发(作者:小学英语教学案例)

STM32解析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,这个我估计跟遥控器⼚家有关。

的负逻辑

这个地⽅⼀定要万分注意,必须加硬件反相器,因为SBUS的信号是采⽤的负逻辑,也就是电平相反,不要试图在软件⾥⾯取反,因

为软件⾥⾯只能操作数据位(记得串⼝配置⾥⾯的数据位8么),你是操作不了停⽌位、校验位啥的!!

如果是⾃⼰画板⼦也很简单,如图所⽰

5.数据读取

⼀般的串⼝调试助⼿可能没有100K波特率的选项,推荐⼀个串⼝调试助⼿,可以⾃定义串⼝波特率,还有其他好功能⾃⼰探索叭。

32F7解析SBUS信号例程

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

(1)串⼝配置

⾸先⼀些变量声明,串⼝uart.c⾥⽤到的

#defineUSART_REC_LEN100//定义最⼤接收字节数200

#defineRXBUFFERSIZE1//缓存⼤⼩

u8USART1_RX_BUF[USART_REC_LEN];//接收缓冲,最⼤USART_REC_LEN个字节.

u16USART1_RX_STA=0;//接收状态标记

u8aRxBuffer1[RXBUFFERSIZE];//HAL库使⽤的串⼝接收缓冲

UART_HandleTypeDefUART1_Handler;//UART句柄

串⼝初始化函数

voiduart1_init(u32bound)

{

//UART初始化设置

UART1_ce=USART1;//USART1

UART1_te=bound;//波特率

UART1_ngth=UART_WORDLENGTH_9B;//字长为8位数据格式

UART1_ts=UART_STOPBITS_1;//⼀个停⽌位

UART1_=UART_PARITY_EVEN;//⽆奇偶校验位

UART1_Ctl=UART_HWCONTROL_NONE;//⽆硬件流控

UART1_=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,并且设置接收缓冲以及

接收缓冲接收最⼤数据量

}

voidHAL_UART_MspInit(UART_HandleTypeDef*huart)

{

//GPIO端⼝设置

GPIO_InitTypeDefGPIO_Initure;

if(huart->Instance==USART1)//如果是串⼝1,进⾏串⼝1MSP初始化

{

__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟

__HAL_RCC_USART1_CLK_ENABLE();//使能USART1时钟

GPIO_=GPIO_PIN_9;//PA9

GPIO_=GPIO_MODE_AF_PP;//复⽤推挽输出

GPIO_=GPIO_PULLUP;//上拉

GPIO_=GPIO_SPEED_FAST;//⾼速

GPIO_ate=GPIO_AF7_USART1;//复⽤为USART1

HAL_GPIO_Init(GPIOA,&GPIO_Initure);//初始化PA9

GPIO_=GPIO_PIN_10;//PA10

HAL_GPIO_Init(GPIOA,&GPIO_Initure);//初始化PA10

#ifEN_USART1_RX

HAL_NVIC_EnableIRQ(USART1_IRQn);//使能USART1中断通道

HAL_NVIC_SetPriority(USART1_IRQn,3,2);//抢占优先级3,⼦优先级3

#endif

}

}

这⾥有个诡异的地⽅就是stm32要设置成9个数据位,⼀个停⽌位,我⼀开始按照8个数据位、两个停⽌位读出来的数据是错的,后来改了

之后才正常了。是不是和stm32内部的串⼝配置有关,哪位⼤神弄明⽩了告诉我哈。

(2)串⼝中断接收

串⼝中断函数,在中断函数⾥⾯接收数据,进⾏SBUS信号解析。

voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)

{

inti;

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函数,原型为u8update_sbus(u8*buf),解析subs信号全靠它了!!新建⼀个sbus.c⽂件,输⼊如下

代码

#include"sbus.h"

SBUS_CH_StructSBUS_CH;

//将sbus信号转化为通道值

u8update_sbus(u8*buf)

{

inti;

if(buf[23]==0)

{

SBUS_tState=1;

SBUS_1=((int16_t)buf[1]>>0|((int16_t)buf[2]<<8))&0x07FF;

SBUS_2=((int16_t)buf[2]>>3|((int16_t)buf[3]<<5))&0x07FF;

SBUS_3=((int16_t)buf[3]>>6|((int16_t)buf[4]<<2)|(int16_t)buf[5]<<10)&0x07FF;

SBUS_4=((int16_t)buf[5]>>1|((int16_t)buf[6]<<7))&0x07FF;

SBUS_5=((int16_t)buf[6]>>4|((int16_t)buf[7]<<4))&0x07FF;

SBUS_6=((int16_t)buf[7]>>7|((int16_t)buf[8]<<1)|(int16_t)buf[9]<<9)&0x07FF;

SBUS_7=((int16_t)buf[9]>>2|((int16_t)buf[10]<<6))&0x07FF;

SBUS_8=((int16_t)buf[10]>>5|((int16_t)buf[11]<<3))&0x07FF;

SBUS_9=((int16_t)buf[12]<<0|((int16_t)buf[13]<<8))&0x07FF;

SBUS_10=((int16_t)buf[13]>>3|((int16_t)buf[14]<<5))&0x07FF;

SBUS_11=((int16_t)buf[14]>>6|((int16_t)buf[15]<<2)|(int16_t)buf[16]<<10)&0x07FF;

SBUS_12=((int16_t)buf[16]>>1|((int16_t)buf[17]<<7))&0x07FF;

SBUS_13=((int16_t)buf[17]>>4|((int16_t)buf[18]<<4))&0x07FF;

SBUS_14=((int16_t)buf[18]>>7|((int16_t)buf[19]<<1)|(int16_t)buf[20]<<9)&0x07FF;

SBUS_15=((int16_t)buf[20]>>2|((int16_t)buf[21]<<6))&0x07FF;

SBUS_16=((int16_t)buf[21]>>5|((int16_t)buf[22]<<3))&0x07FF;

return1;

}

else

{

SBUS_tState=0;

return0;

}

}

u16sbus_to_pwm(u16sbus_value)

{

floatpwm;

pwm=(float)SBUS_TARGET_MIN+(float)(sbus_value-SBUS_RANGE_MIN)*SBUS_SCALE_FACTOR;

//1/1400

if(pwm>2000)pwm=2000;

if(pwm<1000)pwm=1000;

return(u16)pwm;

}

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

typedefstruct

{

uint16_tCH1;//通道1数值

uint16_tCH2;//通道2数值

uint16_tCH3;//通道3数值

uint16_tCH4;//通道4数值

uint16_tCH5;//通道5数值

uint16_tCH6;//通道6数值

uint16_tCH7;//通道7数值

uint16_tCH8;//通道8数值

uint16_tCH9;//通道9数值

uint16_tCH10;//通道10数值

uint16_tCH11;//通道11数值

uint16_tCH12;//通道12数值

uint16_tCH13;//通道13数值

uint16_tCH14;//通道14数值

uint16_tCH15;//通道15数值

uint16_tCH16;//通道16数值

uint8_tConnectState;//遥控器与接收器连接状态0=未连接,1=正常连接

}SBUS_CH_Struct;

u16sbus_to_pwm(u16sbus_value)很好理解了,就是把sbus的值转化为标准的1000-2000的pwm值,因为我⽤的遥控器sbus值是300-

1700,⼤家⽤的时候具体数值到时候可以通过串⼝直接读出来看看。

这样就读出了16个通道的数据啦。同时通过读取ConnectState位判断遥控器的状态,在主函数中采取失控保护。

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

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

voidmain()

{

/*省略*/

uart1_init(100000);

/*省略*/

}

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

👁️ 阅读量:0