日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于stm32和富斯遥控器的SBUS波形分析和通讯实现

發(fā)布時(shí)間:2023/12/20 编程问答 63 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于stm32和富斯遥控器的SBUS波形分析和通讯实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

基于stm32和富斯遙控器的SBUS波形分析和通訊實(shí)現(xiàn)

  • 簡介
  • 軟件環(huán)境和硬件搭建
    • 軟件環(huán)境
    • 硬件搭建
  • SBUS協(xié)議
    • SBUS協(xié)議
    • SBUS波形分析
  • 程序部分
    • 程序流程
    • 核心程序
  • 總結(jié)

簡介

最近一個小項(xiàng)目用到了富斯的遙控器(使用的SBUS協(xié)議),目的是實(shí)現(xiàn)通過遙控器的各個通道對小車進(jìn)行簡單控制(移動、燈光、不同工作模式等),一點(diǎn)小經(jīng)驗(yàn)和大家分享下。SBUS網(wǎng)上的資料很多,本篇更偏向于新人對SBUS的快速理解和直接應(yīng)用,對一些不太常用的細(xì)則不再進(jìn)行介紹。
因?yàn)槭堑谝淮问褂肧BUS協(xié)議,根據(jù)個人習(xí)慣在學(xué)習(xí)通訊協(xié)議時(shí)喜歡對照著實(shí)際波形理解,如果有朋友對硬件有簡單了解,建議接觸新的通訊協(xié)議時(shí)也用示波器配合實(shí)際波形來學(xué)習(xí),能發(fā)現(xiàn)很多細(xì)節(jié)。當(dāng)然這個不是必須的,僅是個人建議而已,實(shí)際波形我也會貼出供感興趣的朋友參考。
其他細(xì)節(jié)如有疏漏還請各位指出,共同進(jìn)步。

軟件環(huán)境和硬件搭建

軟件環(huán)境

編譯軟件:KEIL MDK
庫:STM32標(biāo)準(zhǔn)庫
單片機(jī)I/O使用:PC11(串口USART4 RX端,TX端不接即可)
單片機(jī)外設(shè)使用:USART4(接收遙控?cái)?shù)據(jù))、TIM3(定時(shí)驗(yàn)證數(shù)據(jù)正確性)

硬件搭建

發(fā)射裝置:富斯遙控器FS-I6S
接收裝置:接收機(jī)IA10B
MCU控制板:STM32F407電路板
外接電路:簡單的三極管反向電路(必須)

發(fā)射裝置和接收裝置之間只要是SBUS通訊方式,不同型號理論來說影響不大,程序可以通用。
因?yàn)橹恍枰玫絾纹瑱C(jī)的串口(為了驗(yàn)證數(shù)據(jù)的正確性筆者多用了個定時(shí)器TIM3),所以只是實(shí)現(xiàn)通訊的話電路要求比較簡單,只要能正常工作并帶有串口外設(shè)的單片機(jī)板即可,比如某寶上賣的STM32F103最小系統(tǒng)板。
由于SBUS邏輯電平和常用的串口通訊極性剛好相反,所以需要搭建一個簡單的三極管反向電路,電路參考下圖。

遙控器需要配置為SBUS輸出模式:

接收機(jī)接線如下:
綠線為信號線-----接三極管反向電路的輸入端(Single)
黃線為電源+線-----接5V電源
藍(lán)線為電源地線 -----接電源GND
總體連接如下:

SBUS協(xié)議

SBUS協(xié)議

SBUS協(xié)議其實(shí)就是串口通訊(USART)的應(yīng)用層協(xié)議,它的本質(zhì)還是USART通訊。可以粗暴理解為一幀SBUS數(shù)據(jù)是由連續(xù)發(fā)送或接收25個字節(jié)(即25次)的串口數(shù)據(jù)構(gòu)成,第一個字節(jié)固定為0x0F,最后一個字節(jié)固定為0x00,中間23個字節(jié)和起來構(gòu)成了所需數(shù)據(jù)。所以使用它在程序上還是使用串口,只不過在串口配置上必須按照以下參數(shù)配置:
串口波特率為100000,數(shù)據(jù)位為8位2個停止位,校驗(yàn),無硬件控流
Sbus的編碼方式為每11位為一個數(shù)據(jù),除去第一個字節(jié)和第25個字節(jié),需要把中間23個字節(jié)的常規(guī)8位數(shù)據(jù)合在一起,并按每11位為一組的格式進(jìn)行解析處理。具體解析方法網(wǎng)上教程較多,不再贅述。如果不想了解具體解析方法,可直接引用下文的解析函數(shù)得出解析后的結(jié)果即可。

SBUS波形分析

位長度:
SBUS的波特率固定為100K,所以每傳輸一位的時(shí)間為:1/100K=10us,
隨機(jī)用示波器抓取了一位,實(shí)測結(jié)果略微有誤差為11.7us,在接受范圍內(nèi)。

字節(jié)長度:
SBUS一幀由25次串口接收或發(fā)送構(gòu)成(25個字節(jié)),每次串口發(fā)送有12位組成:1個起始位+8個數(shù)據(jù)位+1個偶校驗(yàn)位+2個停止位。下圖為截取一幀SBUS前幾個數(shù)據(jù)字節(jié)波形。由于發(fā)送順序遵循LSB(低位優(yōu)先)原則,所以需要注意每個字節(jié)高位和低位的波形和實(shí)際結(jié)果顛倒的。如波形第一個字節(jié)為0xF0,實(shí)際數(shù)據(jù)為0x0F。

幀長度
SBUS一幀由25個字節(jié)構(gòu)成,每個字節(jié)12位,每位長度10us,總長度=10us12位25個字節(jié)=3000us(糾正:圖中3000us單位錯打成了3000ms)。
幀間隔
SBUS兩幀間間隔約4.68ms,如果要求不能漏掉任何一幀,則需要注意其他程序處理時(shí)間必須在4.68ms內(nèi),不能影響一下幀的接收。

程序部分

程序流程

程序執(zhí)行流程:上電-----配置外設(shè)(USART4、TIM3,默認(rèn)使能都為關(guān)閉狀態(tài),TIM3定時(shí)3ms)-----等待PC11出現(xiàn)持續(xù)一段時(shí)間的高電平后使能USART4,等待接收第一個字節(jié)(等待的持續(xù)高電平即為兩幀間的高電平間隔部分,確保能從第一個字節(jié)接收)-----當(dāng)串口收到數(shù)據(jù)后使能TIM3-----當(dāng)TIM3時(shí)間到后關(guān)閉TIM3和USART4判斷串口是否是剛好收到25個字節(jié)-----是則執(zhí)行解析函數(shù),不是則為接收錯誤-----重新等待持續(xù)的高電平。

Created with Rapha?l 2.2.0上電初始化USAER4、TIM3讀取PC11電平是否出現(xiàn)持續(xù)的高電平?使能USART4,等待接收第一個字節(jié)收到第一個字節(jié)則使能TIM3TIM3時(shí)間滿后(3ms)判斷是否完整收到25個字節(jié)對收到的數(shù)據(jù)進(jìn)行解析yesnoyesno

核心程序

程序是基于STM32F407的,如果是103可能在系統(tǒng)頭文件名上報(bào)錯和USART配置時(shí)會有點(diǎn)小差別。
USART4配置及其中斷函數(shù):
一定要注意因?yàn)橛幸粋€偶校驗(yàn)位,數(shù)據(jù)長度要寫為9:
USART_InitStructure.USART_WordLength = USART_WordLength_9b。
中斷內(nèi)的函數(shù)功能為:進(jìn)中斷開TIM3定時(shí)器,把收到的串口數(shù)據(jù)進(jìn)行保存。

#include "sys.h" #include "usart.h" u8 rec_buff[30]={0}; u8 rec_cnt=0; extern u32 WaitRec_cnt;void Uart4_Init(u32 bound){//GPIO端口設(shè)置 PC10 PC11GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); //使能GPIOC時(shí)鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE); //使能USART1時(shí)鐘//串口4對應(yīng)引腳復(fù)用映射GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_UART4); //GPIOC10復(fù)用為USART4GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_UART4); //GPIOA11復(fù)用為USART4//USART1端口配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //GPIOc10與GPIOc11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化C10 C11//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優(yōu)先級3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優(yōu)先級3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器//USART 初始化設(shè)置USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_9b;//字長為8位數(shù)據(jù)格式USART_InitStructure.USART_StopBits = USART_StopBits_2;//2個停止位USART_InitStructure.USART_Parity = USART_Parity_Even;//偶校驗(yàn)位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據(jù)流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式USART_Init(UART4, &USART_InitStructure); //初始化串口1USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//開啟串口接受中斷USART_Cmd(UART4, DISABLE); //使能串口1 } void UART4_IRQHandler(void) {if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET){rec_buff[rec_cnt]=UART4->DR;rec_cnt++;WaitRec_cnt=0;TIM_Cmd(TIM3, ENABLE); }USART_ClearITPendingBit(UART4, USART_IT_RXNE); }

TIM3配置及其中斷函數(shù):
TIM3時(shí)間在實(shí)際應(yīng)用時(shí)是3ms進(jìn)定時(shí)器中斷,理論上3ms能剛好把一幀SBUS(25個字節(jié))接收完畢。因?yàn)槭且呀?jīng)接收到第一個串口數(shù)據(jù)后才開的定時(shí)器,后續(xù)只會有24個字節(jié)的時(shí)間,所以實(shí)際上定時(shí)器3ms時(shí)間還留有一個字節(jié)的時(shí)間裕量。
TIM3的中斷函數(shù)功能:即為判斷串口是否正確接收了一幀SBUS(25個字節(jié))數(shù)據(jù),是則進(jìn)行數(shù)據(jù)解析函數(shù)SbusDataParsing(u8 buf[]) ;,不是則錯誤位RecErr_Flag+1。

#include "tim.h" #include "usart.h" #include "sbus.h" u8 RecErr_Flag; extern u8 rec_cnt; u32 WaitRec_cnt; extern u8 rec_buff[30]; void TIM3_Init(u16 arr,u16 psc) {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時(shí)鐘使能TIM_DeInit(TIM3);//定時(shí)器TIM3初始化TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個更新事件裝入活動的自動重裝載寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來作為TIMx時(shí)鐘頻率除數(shù)的預(yù)分頻值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設(shè)置時(shí)鐘分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據(jù)指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位TIM_ClearITPendingBit(TIM3, TIM_IT_Update);TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中斷,允許更新中斷//中斷優(yōu)先級NVIC設(shè)置NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占優(yōu)先級0級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優(yōu)先級3級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器TIM_Cmd(TIM3, DISABLE); //使能TIMx } void TIM3_IRQHandler(void) //TIM3中斷 {if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //檢查TIM3更新中斷發(fā)生與否{USART_Cmd(UART4, DISABLE); TIM_Cmd(TIM3, DISABLE);TIM3->CNT=0;if(rec_cnt==25){SbusDataParsing(rec_buff); //SBUS解析}else RecErr_Flag++;rec_cnt=0;WaitRec_cnt=0;TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx更新中斷標(biāo)志 } }

解析函數(shù):
SbusDataParsing(u8 buf[])為解析函數(shù),如果TIM3判斷正確接收了25個字節(jié)的數(shù)據(jù),則把串口接收到的25個數(shù)據(jù)放入buf[]數(shù)組內(nèi),執(zhí)行完的數(shù)組結(jié)果ch[]就是我們需要的最終結(jié)果。

#include "sbus.h"u16 ch[16]={0}; void SbusDataParsing(u8 buf[]) //S-BUS解析 {ch[0] = ((u16)buf[ 1] >> 0 | ((int16_t)buf[ 2] << 8 )) & 0x07FF;ch[1] = ((u16)buf[ 2] >> 3 | ((int16_t)buf[ 3] << 5 )) & 0x07FF;ch[2] = ((u16)buf[ 3] >> 6 | ((int16_t)buf[ 4] << 2 ) | (int16_t)buf[ 5] << 10 ) & 0x07FF;ch[3] = ((u16)buf[ 5] >> 1 | ((int16_t)buf[ 6] << 7 )) & 0x07FF;ch[4] = ((u16)buf[ 6] >> 4 | ((int16_t)buf[ 7] << 4 )) & 0x07FF;ch[5] = ((u16)buf[ 7] >> 7 | ((int16_t)buf[ 8] << 1 ) | (int16_t)buf[9] << 9 ) & 0x07FF;ch[6] = ((u16)buf[ 9] >> 2 | ((int16_t)buf[10] << 6 )) & 0x07FF;ch[7] = ((u16)buf[10] >> 5 | ((int16_t)buf[11] << 3 )) & 0x07FF;ch[8] = ((u16)buf[12] << 0 | ((int16_t)buf[13] << 8 )) & 0x07FF;ch[9] = ((u16)buf[13] >> 3 | ((int16_t)buf[14] << 5 )) & 0x07FF;ch[10] = ((u16)buf[14] >> 6 | ((int16_t)buf[15] << 2 ) | (int16_t)buf[16] << 10 ) & 0x07FF;ch[11] = ((u16)buf[16] >> 1 | ((int16_t)buf[17] << 7 )) & 0x07FF;ch[12] = ((u16)buf[17] >> 4 | ((int16_t)buf[18] << 4 )) & 0x07FF;ch[13] = ((u16)buf[18] >> 7 | ((int16_t)buf[19] << 1 ) | (int16_t)buf[20] << 9 ) & 0x07FF;ch[14] = ((u16)buf[20] >> 2 | ((int16_t)buf[21] << 6 )) & 0x07FF;ch[15] = ((u16)buf[21] >> 5 | ((int16_t)buf[22] << 3 )) & 0x07FF; }

主函數(shù):
主函數(shù)的主要功能:上電配置串口USART4和定時(shí)器TIM3,然后while循環(huán)檢查串口USART4的RX引腳PC11是否出現(xiàn)連續(xù)的高電平。每次while循環(huán)一次檢測是高則WaitRec_cnt+1,是低則清0,直到出現(xiàn)一段連續(xù)的高電平就表明進(jìn)入了兩幀SBUS中間的幀間隔中,再開啟串口確保能從第一個字節(jié)開始接收。實(shí)際的WaitRec_cnt時(shí)間不用特別精確但需要大家進(jìn)行調(diào)試,不同單片機(jī)主頻不同,執(zhí)行while的時(shí)間也不同。STM32F407主頻168M,WaitRec_cnt執(zhí)行到3000時(shí)大概700多us。同時(shí)需要自行考慮持續(xù)多久開啟串口中斷比較好,不要影響到其他程序的運(yùn)行。

#include "stm32f4xx.h" #include "usart.h" #include "tim.h" extern u32 WaitRec_cnt;int main(void) { Uart4_Init(100000); //遙控器TIM3_Init(29,8399);while(1){ if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_11)==1) //等待一段高電平,確保從第一個字節(jié)開始。{WaitRec_cnt++;}else WaitRec_cnt=0;if(WaitRec_cnt>3000) //3000時(shí)大概為幾百us,持續(xù)幾百us都為高則開啟串口{USART_Cmd(UART4, ENABLE);}} }

其他.h文件
sbus.h

#ifndef __SBUS_H #define __SBUS_H #include "sys.h" #define RightRocker_Horizontal ch[0] //left:242 center:1033 right:1804 #define RightRocker_Vertical ch[1] //up:1807 center:1024 down:240 #define LeftRocker_Vertical ch[2] //up:1805 center:1024 down:240 #define LeftRocker_Horizontal ch[3] //left:240 center:1025 right:1807 #define SWA ch[4] //up:240 down: 1807 #define SWB ch[5] //up:240 center:1024 down: 1807 #define SWC ch[6] //up:240 center:1024 down: 1807 #define SWD ch[7] //up:240 down: 1807 #define VAA ch[8] //left:240 center:1024 right:1807 #define VAB ch[9] //left:1807 center:1024 right:240 void SbusDataParsing(u8 buf[]); #endif

usart.h

#ifndef __UART_H #define __UART_H #include "stdio.h" #include "sys.h" void Uart4_Init(u32 bound); void Uart1_Init(u32 bound); #endif

tim.h

#ifndef __TIMER_H #define __TIMER_H #include "sys.h"void TIM3_Init(u16 arr,u16 psc);#endif

總結(jié)

至此,整個SBUS的通訊已經(jīng)完成,通訊的最終結(jié)果存放在CH[]數(shù)組里以方便調(diào)用。遙控器上不同的搖桿和撥動開關(guān)對應(yīng)不同的CH[]通道,sbus.h里也有進(jìn)行宏定義以便大家進(jìn)行遙控的按鈕和CH[]通道的對應(yīng):

#define RightRocker_Horizontal ch[0] //left:242 center:1033 right:1804

實(shí)際就是遙控器右邊搖桿水平撥動時(shí)對應(yīng)的是ch[0]中的值的變化。不撥動時(shí)ch[0]值是1033,右搖桿撥到最左邊時(shí)ch[0]是242,最右邊時(shí)ch[0]是1804.不同的遙控器中間值和最大最小值會有小范圍的偏差,一般不會超過幾十。其他搖桿和按鍵的對應(yīng)關(guān)系請自行體會。也可以去B站看實(shí)際控制遙控器對應(yīng)的CH[]變化,不過是16進(jìn)制的看著不是很方便:
https://www.bilibili.com/video/BV1Kv411k7fQ
最后附一張剛買的一個遙控器的初始值調(diào)試結(jié)果的截圖:

總結(jié)

以上是生活随笔為你收集整理的基于stm32和富斯遥控器的SBUS波形分析和通讯实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。