STM32解析SBUS信号例程详解
文章目錄
- 1. SBUS信號(hào)簡介
- 2. STM32F7解析SBUS信號(hào)例程
- (1) 串口配置
- (2) 串口中斷接收
- (3) 信號(hào)解析
1. SBUS信號(hào)簡介
最近在搞一個(gè)項(xiàng)目的通信和控制,用到了SBUS,記錄一下心得。
SBUS全稱serial-bus,是一種串口通信協(xié)議,廣泛應(yīng)用于航模遙控器(接收機(jī))中。只用一根信號(hào)線就能傳輸多達(dá)16通道的數(shù)據(jù),比多路PWM捕獲高效且省資源。
100k波特率,8位數(shù)據(jù)位,2位停止位,偶校驗(yàn)(EVEN),無控流,25個(gè)字節(jié)。
[startbyte] [data1][data2]…[data22][flags][endbyte]
startbyte=0x0f;
endbyte=0x00;
data1…data22: LSB(低位在前),對(duì)應(yīng)16個(gè)通道(ch1-ch16),每個(gè)通道11bit(22 × 8=16 × 11);
flag位標(biāo)志遙控器的通訊狀態(tài),我使用的樂迪AT9S在遙控器通上的時(shí)候是0x00,斷開的時(shí)候是0xC0,可以通過查詢flag位來采取失控保護(hù)。
航模遙控器輸出的PWM值是1000~2000,中值為1500,sbus輸出的會(huì)不一樣,例如樂迪AT9S的范圍為300 ~ 1700,中值1000,這個(gè)我估計(jì)跟遙控器廠家有關(guān)。
這個(gè)地方一定要萬分注意,必須加硬件反相器,因?yàn)镾BUS的信號(hào)是采用的負(fù)邏輯,也就是電平相反,不要試圖在軟件里面取反,因?yàn)檐浖锩嬷荒懿僮鲾?shù)據(jù)位(記得串口配置里面的數(shù)據(jù)位8么),你是操作不了停止位、校驗(yàn)位啥的!!
如果是自己畫板子也很簡單,如圖所示
5. 數(shù)據(jù)讀取
一般的串口調(diào)試助手可能沒有100K波特率的選項(xiàng),推薦一個(gè)串口調(diào)試助手MicroLab,可以自定義串口波特率,還有其他好功能自己探索叭。
2. STM32F7解析SBUS信號(hào)例程
清楚了通信協(xié)議,解析就很簡單了。我使用的是正點(diǎn)原子的阿波羅F7開發(fā)板,其他的板子是一樣的。
(1) 串口配置
首先一些變量聲明,串口uart.c里用到的
#define USART_REC_LEN 100 //定義最大接收字節(jié)數(shù) 200 #define RXBUFFERSIZE 1 //緩存大小u8 USART1_RX_BUF[USART_REC_LEN]; //接收緩沖,最大USART_REC_LEN個(gè)字節(jié). u16 USART1_RX_STA = 0; //接收狀態(tài)標(biāo)記 u8 aRxBuffer1[RXBUFFERSIZE]; //HAL庫使用的串口接收緩沖 UART_HandleTypeDef UART1_Handler; //UART句柄串口初始化函數(shù)
void uart1_init(u32 bound) {//UART 初始化設(shè)置UART1_Handler.Instance = USART1; //USART1UART1_Handler.Init.BaudRate = bound; //波特率UART1_Handler.Init.WordLength = UART_WORDLENGTH_9B; //字長為8位數(shù)據(jù)格式UART1_Handler.Init.StopBits = UART_STOPBITS_1; //一個(gè)停止位UART1_Handler.Init.Parity = UART_PARITY_EVEN; //無奇偶校驗(yàn)位UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; //無硬件流控UART1_Handler.Init.Mode = UART_MODE_TX_RX; //收發(fā)模式HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()會(huì)使能UART1HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer1, RXBUFFERSIZE); //該函數(shù)會(huì)開啟接收中斷:標(biāo)志位UART_IT_RXNE,并且設(shè)置接收緩沖以及接收緩沖接收最大數(shù)據(jù)量 }void HAL_UART_MspInit(UART_HandleTypeDef *huart) {//GPIO端口設(shè)置GPIO_InitTypeDef GPIO_Initure;if (huart->Instance == USART1) //如果是串口1,進(jìn)行串口1 MSP初始化{__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時(shí)鐘__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1時(shí)鐘GPIO_Initure.Pin = GPIO_PIN_9; //PA9GPIO_Initure.Mode = GPIO_MODE_AF_PP; //復(fù)用推挽輸出GPIO_Initure.Pull = GPIO_PULLUP; //上拉GPIO_Initure.Speed = GPIO_SPEED_FAST; //高速GPIO_Initure.Alternate = GPIO_AF7_USART1; //復(fù)用為USART1HAL_GPIO_Init(GPIOA, &GPIO_Initure); //初始化PA9GPIO_Initure.Pin = GPIO_PIN_10; //PA10HAL_GPIO_Init(GPIOA, &GPIO_Initure); //初始化PA10#if EN_USART1_RXHAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中斷通道HAL_NVIC_SetPriority(USART1_IRQn, 3, 2); //搶占優(yōu)先級(jí)3,子優(yōu)先級(jí)3 #endif} }這里有個(gè)詭異的地方就是stm32要設(shè)置成9個(gè)數(shù)據(jù)位,一個(gè)停止位,我一開始按照8個(gè)數(shù)據(jù)位、兩個(gè)停止位讀出來的數(shù)據(jù)是錯(cuò)的,后來改了之后才正常了。是不是和stm32內(nèi)部的串口配置有關(guān),哪位大神弄明白了告訴我哈。
(2) 串口中斷接收
串口中斷函數(shù),在中斷函數(shù)里面接收數(shù)據(jù),進(jìn)行SBUS信號(hào)解析。
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; //幀頭不對(duì),丟掉USART1_RX_STA++;if (USART1_RX_STA > USART_REC_LEN) USART1_RX_STA = 0; ///接收數(shù)據(jù)錯(cuò)誤,重新開始接收if (USART1_RX_BUF[0] == 0x0F && USART1_RX_BUF[24] == 0x00 && USART1_RX_STA == 25) //接受完一幀數(shù)據(jù){update_sbus(USART1_RX_BUF);for (i = 0; i<25; i++) //清空緩存區(qū)USART1_RX_BUF[i] = 0;USART1_RX_STA = 0;}break;} }(3) 信號(hào)解析
上面中斷函數(shù)里面有一個(gè)update_sbus函數(shù),原型為u8 update_sbus(u8 *buf),解析subs信號(hào)全靠它了!!新建一個(gè)sbus.c文件,輸入如下代碼
#include "sbus.h"SBUS_CH_Struct SBUS_CH;//將sbus信號(hào)轉(zhuǎn)化為通道值 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/1400if (pwm > 2000) pwm = 2000;if (pwm < 1000) pwm = 1000;return (u16)pwm; }上面定義了一個(gè)SBUS_CH_Struct 結(jié)構(gòu)體類型的變量SBUS_CH,該結(jié)構(gòu)體在sbus.h中定義
typedef struct {uint16_t CH1;//通道1數(shù)值uint16_t CH2;//通道2數(shù)值uint16_t CH3;//通道3數(shù)值uint16_t CH4;//通道4數(shù)值uint16_t CH5;//通道5數(shù)值uint16_t CH6;//通道6數(shù)值uint16_t CH7;//通道7數(shù)值uint16_t CH8;//通道8數(shù)值uint16_t CH9;//通道9數(shù)值uint16_t CH10;//通道10數(shù)值uint16_t CH11;//通道11數(shù)值uint16_t CH12;//通道12數(shù)值uint16_t CH13;//通道13數(shù)值uint16_t CH14;//通道14數(shù)值uint16_t CH15;//通道15數(shù)值uint16_t CH16;//通道16數(shù)值uint8_t ConnectState;//遙控器與接收器連接狀態(tài) 0=未連接,1=正常連接 }SBUS_CH_Struct;u16 sbus_to_pwm(u16 sbus_value)很好理解了,就是把sbus的值轉(zhuǎn)化為標(biāo)準(zhǔn)的1000-2000的pwm值,因?yàn)槲矣玫倪b控器sbus值是300-1700,大家用的時(shí)候具體數(shù)值到時(shí)候可以通過串口直接讀出來看看。
這樣就讀出了16個(gè)通道的數(shù)據(jù)啦。同時(shí)通過讀取ConnectState位判斷遙控器的狀態(tài),在主函數(shù)中采取失控保護(hù)。
上面這段解析數(shù)據(jù)的代碼是國際通用的,可以用在任何使用sbus協(xié)議的場合,可以很方便的移植到arduino、51、樹莓派上面。
最后main函數(shù)里面就很簡單了,只注意初始化串口設(shè)置為100K波特率。
void main() {/* 省略 */uart1_init(100000);/* 省略 */ }本文代碼已上傳至CSDN,獨(dú)樂樂不如眾樂樂,提供免費(fèi)下載,點(diǎn)擊下載,歡迎交流討論。別忘了點(diǎn)個(gè)贊哦!
總結(jié)
以上是生活随笔為你收集整理的STM32解析SBUS信号例程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TQ210 —— NandFlash
- 下一篇: Excel控制AutoCad进行坐标标注