標題: STM32手機藍牙控制實例分享 [打印本頁]

作者: WSLZY787852    時間: 2017-11-3 00:01
標題: STM32手機藍牙控制實例分享
分享一份很好的資料,關于怎么樣使用手機來控制開發(fā)板的,里面有一些實例,都是漢德樂電子網(wǎng)絡工作室,開人員自行編寫的,通過這份資料相信你也能很好的將你的手機和開發(fā)板連接起來,下面不多講,直接上資料!
1、首先介紹一下什么是透明傳輸:
透明傳輸是指不管所傳數(shù)據(jù)是什么樣的比特組合,都應當能夠在鏈路上傳送。當所傳數(shù)據(jù)中的比特組合恰巧與某一個控制信息完全一樣時,就必須采取適當?shù)拇胧菇邮辗讲粫䦟⑦@樣的數(shù)據(jù)誤認為是某種控制信息。這樣才能保證數(shù)據(jù)鏈路層的傳輸是透明的。發(fā)送方和接收方數(shù)據(jù)的長度和內(nèi)容完全一致,相當于一條無形的傳輸線。
2、透傳模塊:
Handler_Bluetooth_PWM 平臺上使用的是FBT_06(嵌入式近距離主從分離/一體式藍牙串口通訊模塊)
特點:
藍牙2.0 帶EDR, 2Mbps-3Mbps 調(diào)制度
內(nèi)置2.4GHz 天線, 用戶無需調(diào)試天線
外置8Mbit FLASH
低電壓3.3V 工作(3.1V~4.2V)配對時30~40MA 波動,配對完畢通信8MA
可選PIO 控制
標準HCI 端口(UART or USB)
USB 協(xié)議: Full Speed USB1.1, Compliant With 2.0
發(fā)射功率屬于class2(約15米)
3、Handler_Bluetooth_PWM 平臺(引用)
該平臺由Handler_Studio 設計,初始目的是專門為四軸飛行器等陸地、空中機器人提供處理核心,而后被大家將其擴展到了各個領域,進行了五花八門的設計應用。
該平臺基于stm32 進行研發(fā)設計,接口人性化,相比市面上的常見的multiwill 平臺的mega328、mega2560 等飛控具有主頻高、處理速度快、性能穩(wěn)定等顯著優(yōu)點。
該平臺有多達10 通道的硬件PWM 輸出,足以應付10 軸飛行器、機器人、機器手臂、蛇形機器人等涉及舵機、直流電機、步進電機、無刷電機等的控制工作。

亮點1:平臺具有配套的安卓控制軟件,并開源平臺源碼,方便二次開發(fā)!
亮點2:平臺引出了常用的通信接口:如串口、SPI、IIC 等,這樣極大地擴展了平臺的適應性,方便我們的DIY。
亮點3:平臺不僅可以和手機、電腦進行通信,兩平臺之間也可通信:典型應用:無線串口!無線串口功能可應用在例如飛思卡爾智能車的調(diào)試當中。
4、藍牙透傳實例
本文檔給大家講述如何用借助Handler_Bluetooth_PWM 平臺通過手機控制產(chǎn)生多路PWM 以控制舵機!
說明:
硬件平臺:Handler_Bluetooth_PWM 飛控板
開發(fā)環(huán)境:keilMDK
Stm 庫版本:V3.0.0
首先需要配置stm32 的串口:
1、使能時鐘
2、使能串口中斷
3、初始化串口
這里想重點說明一下串口數(shù)據(jù)的接收策略:
不怕麻煩舉四個例子說明,如果很了解就跳過,初學者還是有作用的(歡迎拍磚)
實例一:
void USART1_IRQHandler(u8 GetData)
{
u8 BackData;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中斷產(chǎn)生
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中斷標志.
GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR;
USART1_SendByte(GetData); //發(fā)送數(shù)據(jù)
GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED閃爍,接收成功發(fā)送完成
delay(1000);
GPIO_ResetBits(GPIOE, GPIO_Pin_8 );
}
}
這是最基本的,將數(shù)據(jù)接收完成后又發(fā)送出去,接收和發(fā)送在中斷函數(shù)里執(zhí)行,main 函數(shù)里無其他要處理的。
優(yōu)點:簡單,適合很少量數(shù)據(jù)傳輸。
缺點:無緩存區(qū),并且對數(shù)據(jù)的正確性沒有判斷,數(shù)據(jù)量稍大可能導致數(shù)據(jù)丟失。
實例二:
void USART2_IRQHandler()
{
if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中斷產(chǎn)生
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中斷標志
Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2);
Uart2_Rx_Num++;
}
if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) //判斷最
后接收的數(shù)據(jù)是否為設定值,確定數(shù)據(jù)正確性
Uart2_Sta=1;
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
{
USART_ClearFlag(USART2,USART_FLAG_ORE); //讀SR
USART_ReceiveData(USART2); //讀DR
}
}
if( Uart2_Sta )
{
for(Uart2_Tx_Num=0;Uart2_Tx_Num < Uart2_Rx_Num;Uart2_Tx_Num++)
USART2_SendByte(Uart2_Buffer[Uart2_Tx_Num]); //發(fā)送數(shù)據(jù)
Uart2_Rx_Num = 0; //初始化
Uart2_Tx_Num = 0;
Uart2_Sta = 0;
}
這是加了數(shù)據(jù)頭和數(shù)據(jù)尾的接收方式,數(shù)據(jù)頭和尾的個數(shù)可增加,此處只用于調(diào)試之用。中斷函數(shù)用于接收數(shù)據(jù)以及判斷數(shù)據(jù)的頭尾,第二個函數(shù)在main 函數(shù)里按照查詢方式執(zhí)行。
優(yōu)點:較簡單,采用緩存區(qū)接收,對提高數(shù)據(jù)的正確行有一定的改善。
缺點:要是第一次數(shù)據(jù)接收錯誤,回不到初始化狀態(tài),必須復位操作。
實例三:
void USART2_IRQHandler()
{
if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中斷產(chǎn)生
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中斷標志.
Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
Uart2_Rx++;
Uart2_Rx &= 0x3F; //判斷是否計數(shù)到最大
}
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
{
USART_ClearFlag(USART2,USART_FLAG_ORE); //讀SR
USART_ReceiveData(USART2); //讀DR
}
}
if( Uart2_Tx != Uart2_Rx )
{
USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //發(fā)送數(shù)據(jù)
Uart2_Tx++;
Uart2_Tx &= 0x3F; //判斷是否計數(shù)到最大
}
采用FIFO 方式接收數(shù)據(jù),由0x3F 可知此處最大接收量為64 個,可變,中斷函數(shù)只負責收,
另一函數(shù)在main 函數(shù)里執(zhí)行,F(xiàn)IFO 方式發(fā)送。
優(yōu)點:發(fā)送和接收都很自由,中斷占用時間少,有利于MCU 處理其它。
缺點:對數(shù)據(jù)的正確性沒有判斷,一概全部接收。
實例四:
void USART2_IRQHandler()
{
if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中斷產(chǎn)生
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中斷標志
Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
Uart2_Rx++;
Uart2_Rx &= 0xFF;
}
if(Uart2_Buffer[Uart2_Rx-1] == 0x5A) //頭
Uart2_Tx = Uart2_Rx-1;
if((Uart2_Buffer[Uart2_Tx] == 0x5A)&&(Uart2_Buffer[Uart2_Rx-1] == 0xA5)) //
檢測到頭的情況下檢測到尾
{
Uart2_Len = Uart2_Rx-1- Uart2_Tx; //長度
Uart2_Sta=1; //標志位
}
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
{
USART_ClearFlag(USART2,USART_FLAG_ORE); //讀SR
USART_ReceiveData(USART2); //讀DR
}
}
if( Uart2_Sta )
{
for(tx2=0;tx2 <= Uart2_Len;tx2++,Uart2_Tx++)
USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //發(fā)送數(shù)據(jù)
Uart2_Rx = 0; //初始化
Uart2_Tx = 0;
Uart2_Sta = 0;
}
數(shù)據(jù)采用數(shù)據(jù)包的形式接收,接收后存放于緩存區(qū),通過判斷數(shù)據(jù)頭和數(shù)據(jù)尾(可變)來判
斷數(shù)據(jù)的“包”及有效性,中斷函數(shù)用于接收數(shù)據(jù)和判斷頭尾以及數(shù)據(jù)包長度,另一函數(shù)在
main 函數(shù)里執(zhí)行,負責發(fā)送該段數(shù)據(jù)。
優(yōu)點:適合打包傳輸,穩(wěn)定性和可靠性很有保證,可隨意發(fā)送,自動挑選有效數(shù)據(jù)。
缺點:緩存區(qū)數(shù)據(jù)長度要根據(jù)“包裹”長度設定, 要是多次接收后無頭無尾,到有頭有尾
的那一段數(shù)據(jù)恰好跨越緩存區(qū)最前和最后位置時,可能導致本次數(shù)據(jù)丟失,不過這種情況幾
乎沒有可能。
不論使用哪種方法,都是可以實現(xiàn)簡單的功能的,一般來說中斷里面只負責接收數(shù)據(jù),而
不要在其進行數(shù)據(jù)的處理。

接下來需要設置stm32 的TIM 模塊
由于平臺上的處理器是STM32CBT6,定時器有4 個,分別是一個高級控制定時器TIM1,和三個通用定時器。
TIMER 輸出PWM 實現(xiàn)步驟:
1. 設置RCC 時鐘;
2. 設置GPIO 時鐘;
3. 設置TIMx 定時器的相關寄存器;
4. 設置TIMx 定時器的PWM 相關寄存器。
附上源碼(以TIM2 為例:兩個通道)
/*
* 函數(shù)名:TIM2_GPIO_Config
* 描述:配置TIM3復用輸出PWM時用到的I/O
* 輸入:無
* 輸出:無
* 調(diào)用:內(nèi)部調(diào)用
*/
static void TIM2_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* TIM3 clock enable */
//PCLK1經(jīng)過2倍頻后作為TIM3的時鐘源等于36MHz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
/*GPIOA Configuration: TIM3 channel 1 and 2 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static void TIM2_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM信號電平跳變值*/
u16 CCR1_Val = 251;
u16 CCR2_Val = 251;
/* -----------------------------------------------------------------------
TIM2 Configuration: generate 4 PWM signals with 4 different duty cycles:
TIM2CLK = 36 MHz, Prescaler = 0x0, TIM3 counter clock = 36 MHz
TIM2 ARR Register = 999 => TIM2 Frequency = TIM2 counter clock/(ARR + 1)
TIM2 Frequency = 36 KHz.
----------------------------------------------------------------------- */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 9999; //當定時器從0計數(shù)到999,即為1000
次,為一個定時周期
TIM_TimeBaseStructure.TIM_Prescaler = 144; //設置預分頻:不預分頻,即為
36MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分頻系數(shù):不分頻
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數(shù)模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置為PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //設置跳變值,當計數(shù)器計數(shù)到這個
值時,電平發(fā)生跳變
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //當定時器計數(shù)值小
于CCR1_Val時為高電平
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //使能通道1
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val; //設置通道2的電平跳變值,輸出另外
一個占空比的PWM
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //使能通道2
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能TIM2重載寄存器ARR
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE); //使能定時器2
}
/*
* 函數(shù)名:TIM2_Mode_Config
* 描述:TIM2 輸出PWM信號初始化,只要調(diào)用這個函數(shù)
* TIM2的兩個通道就會有PWM信號輸出
* 輸入:無
* 輸出:無
* 調(diào)用:外部調(diào)用
*/
void TIM2_PWM_Init(void)
{
TIM2_GPIO_Config();
TIM2_Mode_Config();
}
在配置其他兩個通用定時器時,配置幾乎是相同的,但是在配置TIM1 的時候需要加這個函數(shù)以使能TIM1 的PWM 輸出
TIM_CtrlPWMOutputs(TIM1, ENABLE);

這樣這個工程的基本功能就都具備了,接下來只需要處理手機端發(fā)過來的數(shù)據(jù)進行調(diào)節(jié)PWM 輸出即可。數(shù)據(jù)可以自定協(xié)議。這里簡單的說明一下,由于平臺上有10 個通道所以我規(guī)定手機端發(fā)送過來的數(shù)據(jù)在十個數(shù)據(jù)之間要有所區(qū)別,我設定發(fā)送格式為Aa1000B其中A 和B 是數(shù)據(jù)包的首和尾,a 代表第一通道,相應的有b 通道、c 通道...1000 代表占空比。
這樣一個基于Handler_Bluetooth_PWM 平臺的通過手機產(chǎn)生多路PWM 控制舵機的程序就完成了。

作者: 天下1314    時間: 2018-6-13 14:46
資料不錯,值得學習
作者: 見龍在田    時間: 2018-6-14 10:49
有參考價值,謝謝
作者: wuxishun    時間: 2018-6-25 06:42
很詳細的注譯,謝謝樓主




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1