找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 15299|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

STM32手機(jī)藍(lán)牙控制實(shí)例分享

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

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

接下來(lái)需要設(shè)置stm32 的TIM 模塊
由于平臺(tái)上的處理器是STM32CBT6,定時(shí)器有4 個(gè),分別是一個(gè)高級(jí)控制定時(shí)器TIM1,和三個(gè)通用定時(shí)器。
TIMER 輸出PWM 實(shí)現(xiàn)步驟:
1. 設(shè)置RCC 時(shí)鐘;
2. 設(shè)置GPIO 時(shí)鐘;
3. 設(shè)置TIMx 定時(shí)器的相關(guān)寄存器;
4. 設(shè)置TIMx 定時(shí)器的PWM 相關(guān)寄存器。
附上源碼(以TIM2 為例:兩個(gè)通道)
/*
* 函數(shù)名:TIM2_GPIO_Config
* 描述:配置TIM3復(fù)用輸出PWM時(shí)用到的I/O
* 輸入:無(wú)
* 輸出:無(wú)
* 調(diào)用:內(nèi)部調(diào)用
*/
static void TIM2_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* TIM3 clock enable */
//PCLK1經(jīng)過(guò)2倍頻后作為TIM3的時(shí)鐘源等于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; // 復(fù)用推挽輸出
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信號(hào)電平跳變值*/
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; //當(dāng)定時(shí)器從0計(jì)數(shù)到999,即為1000
次,為一個(gè)定時(shí)周期
TIM_TimeBaseStructure.TIM_Prescaler = 144; //設(shè)置預(yù)分頻:不預(yù)分頻,即為
36MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分頻系數(shù):不分頻
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計(jì)數(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è)置跳變值,當(dāng)計(jì)數(shù)器計(jì)數(shù)到這個(gè)
值時(shí),電平發(fā)生跳變
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //當(dāng)定時(shí)器計(jì)數(shù)值小
于CCR1_Val時(shí)為高電平
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; //設(shè)置通道2的電平跳變值,輸出另外
一個(gè)占空比的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); //使能定時(shí)器2
}
/*
* 函數(shù)名:TIM2_Mode_Config
* 描述:TIM2 輸出PWM信號(hào)初始化,只要調(diào)用這個(gè)函數(shù)
* TIM2的兩個(gè)通道就會(huì)有PWM信號(hào)輸出
* 輸入:無(wú)
* 輸出:無(wú)
* 調(diào)用:外部調(diào)用
*/
void TIM2_PWM_Init(void)
{
TIM2_GPIO_Config();
TIM2_Mode_Config();
}
在配置其他兩個(gè)通用定時(shí)器時(shí),配置幾乎是相同的,但是在配置TIM1 的時(shí)候需要加這個(gè)函數(shù)以使能TIM1 的PWM 輸出
TIM_CtrlPWMOutputs(TIM1, ENABLE);

這樣這個(gè)工程的基本功能就都具備了,接下來(lái)只需要處理手機(jī)端發(fā)過(guò)來(lái)的數(shù)據(jù)進(jìn)行調(diào)節(jié)PWM 輸出即可。數(shù)據(jù)可以自定協(xié)議。這里簡(jiǎn)單的說(shuō)明一下,由于平臺(tái)上有10 個(gè)通道所以我規(guī)定手機(jī)端發(fā)送過(guò)來(lái)的數(shù)據(jù)在十個(gè)數(shù)據(jù)之間要有所區(qū)別,我設(shè)定發(fā)送格式為Aa1000B其中A 和B 是數(shù)據(jù)包的首和尾,a 代表第一通道,相應(yīng)的有b 通道、c 通道...1000 代表占空比。
這樣一個(gè)基于Handler_Bluetooth_PWM 平臺(tái)的通過(guò)手機(jī)產(chǎn)生多路PWM 控制舵機(jī)的程序就完成了。
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:319334 發(fā)表于 2018-6-13 14:46 | 只看該作者
資料不錯(cuò),值得學(xué)習(xí)
回復(fù)

使用道具 舉報(bào)

板凳
ID:351587 發(fā)表于 2018-6-14 10:49 | 只看該作者
有參考價(jià)值,謝謝
回復(fù)

使用道具 舉報(bào)

地板
ID:243748 發(fā)表于 2018-6-25 06:42 來(lái)自手機(jī) | 只看該作者
很詳細(xì)的注譯,謝謝樓主
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表