????????讀者們国瓮,想你們的小編又回來了细睡。
????????從這一章開始,小編將進行上位機與下位機通信的開發(fā),將單片機采集到的數(shù)據(jù)傳輸?shù)绞謾C實時顯示秘狞。當然,考慮到這部分還是有點難度的谈秫,并且惕橙,在調(diào)試過程中,我找到兩個藍牙軟件谓形,一個是《藍牙串口》灶伊,一個是《藍牙調(diào)試器》。其中《藍牙串口》可以簡單發(fā)送和接收一些字符和16進制數(shù)寒跳,《藍牙調(diào)試器》的功能比較強大聘萨,但在接收發(fā)界面里顯示不出來,不知道是軟件本身問題童太,還是我沒設(shè)置好相關(guān)參數(shù)米辐。但這款軟件里的專業(yè)調(diào)試界面可以自己布局控件,即不需要編寫代碼就能做出符合自己項目的上位機來书释,所以還是得佩服一下該開發(fā)者翘贮。
????????在本章中,小編將開發(fā)下位機通信程序爆惧,結(jié)合《藍牙串口》軟件狸页,實現(xiàn)從手機發(fā)送控制指令,手機再接收單片機發(fā)送過來的相應(yīng)數(shù)據(jù)扯再。在這里芍耘,人為規(guī)定,發(fā)送0x01熄阻,則手機串口接收到溫度數(shù)據(jù)(1字節(jié))斋竞,發(fā)送0x02,則手機串口接收到濕度數(shù)據(jù)(1字節(jié))秃殉,發(fā)送0x03坝初,則手機串口接收到空氣質(zhì)量數(shù)據(jù)(若0~255浸剩,1字節(jié),若大于255鳄袍,2字節(jié))乒省,發(fā)送0x04,則手機串口接收到距離數(shù)據(jù)(若0~255畦木,1字節(jié)袖扛,若大于255,2字節(jié))十籍。
1.資源分析
????????藍牙模塊HC-05蛆封,是主從一體的藍牙串口模塊,簡單的說勾栗,當藍牙設(shè)備與藍牙設(shè)備配對連接成功后惨篱,我們可以忽視藍牙內(nèi)部的通信協(xié)議,直接將將藍牙當做串口用围俘。當建立連接砸讳,兩設(shè)備共同使用一通道也就是同一個串口,一個設(shè)備發(fā)送數(shù)據(jù)到通道中界牡,另外一個設(shè)備便可以接收通道中的數(shù)據(jù)簿寂。
? ? ? ? 藍牙模塊,共有4個引腳宿亡,其中兩個電源引腳VCC和GND常遂,一個數(shù)據(jù)發(fā)送端TX,一個數(shù)據(jù)接收端RX挽荠。而stm32f103c8t6具有3個USART串口克胳,USART是一個全雙工通用同步/異步串行收發(fā)模塊。而本次制作圈匆,由于USART1串口接口已經(jīng)焊接設(shè)計好漠另,用于與電腦串口通信的(有點尷尬,已損壞跃赚,但影響不大)笆搓,所以采用USART2來通信(TX—>PA2,RX—>PA3)来累。
2.軟件分析
(1)配置串口相關(guān)的GPIO
void usart_release_gpio_init(void)
{
? ? GPIO_InitTypeDef GPIO_InitStruct;
? ??RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO, ENABLE);
? ? RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
? ? /*配置PA2為復(fù)用推挽輸出*/
? ? GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
? ? GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
? ? GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
? ? GPIO_Init(GPIOA, &GPIO_InitStruct);
? ? /*配置PA3為復(fù)用浮空輸入*/
? ? GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
? ? GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
? ? GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
? ? GPIO_Init(GPIOA, &GPIO_InitStruct);
}
????????將USART2的TX端口設(shè)置成復(fù)用推挽輸出砚作,RX端口設(shè)置成浮空輸入窘奏,在開啟相關(guān)GPIOA時鐘的同時嘹锁,開啟串口時鐘和復(fù)用時鐘。
(2)?配置相應(yīng)串口模式
void usart_para_config(void)
{
? ? USART_InitTypeDef USART_InitStruct;
? ? USART_InitStruct.USART_BaudRate = 115200;//設(shè)置波特率為115200
? ? USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件流控
? ? USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//發(fā)送和接收模式
? ? USART_InitStruct.USART_Parity = USART_Parity_No;//無奇偶校驗
? ? USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位1位
? ? USART_InitStruct.USART_WordLength = USART_WordLength_8b;//字長為8位
? ? USART_Init(USART2, &USART_InitStruct);//串口初始化
? ? USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能接收中斷
? ? USART_ClearFlag(USART2, USART_FLAG_TC);//清除發(fā)送完成標志位
? ? USART_Cmd(USART2, ENABLE);//使能串口2
}
????????串口模式函數(shù)里着裹,由于藍牙AT指令設(shè)置的波特率為115200(不會設(shè)置的可以網(wǎng)上查)领猾,設(shè)置成接收模式,通信的數(shù)據(jù)結(jié)構(gòu)為字長為8,無奇偶校驗位摔竿,1位停止位面粮。使用USART_Init()函數(shù),將USART2串口初始化继低。接著熬苍,使能接收中斷,清除發(fā)送完成標志位袁翁,最后使能串口2柴底。
(3)配置NVIC
void usart_nvic_init(void)
{
? ? NVIC_InitTypeDef NVIC_InitStructure;
? ? NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);? ? ? ? ? ? //設(shè)置組優(yōu)先級
? ? NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;? ? ? ? ? //設(shè)置串口2中斷
? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;? //設(shè)置搶占優(yōu)先級1
? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;? ? ? ? //設(shè)置子優(yōu)先級
? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;? ? ? ? ? ? //使能
? ? NVIC_Init(&NVIC_InitStructure);
}
????????由于stm32需要接收手機發(fā)過來的控制指令,而接收通常不是每時每刻的粱胜,因此采用中斷的方式去做柄驻,所以需要設(shè)置NVIC,以及使能串口中斷焙压。中斷優(yōu)先級的配置已經(jīng)經(jīng)過多次了鸿脓,如果還是不清楚的話,就上網(wǎng)再查查涯曲。
(4)編寫串口接收中斷程序
void USART2_IRQHandler(void)
{
? ? if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET)
? ? {
? ? ? ? rev_data = USART_ReceiveData(USART2);? ? ? ? ? ? //接收數(shù)據(jù)
? ? ? ? usart_flag = CHAN_IN;
? ? }
? ? USART_ClearITPendingBit(USART2, USART_IT_RXNE);? ? ? //清除接收中斷標志
}
????????串口接收中斷程序里野哭,我們調(diào)用串口接收數(shù)據(jù)函數(shù),暫存在變量rev_data里幻件,然后將接收標志位置位虐拓,即可在主程序里調(diào)用數(shù)據(jù)發(fā)送語句,否則傲武,主程序是不會發(fā)送數(shù)據(jù)給手機的蓉驹。
(5)發(fā)送采集數(shù)據(jù)函數(shù)
void bluetooth(void)
{
? ? if(usart_flag == CHAN_IN)
? ? {
? ? ? ? //接收到0x01:發(fā)送溫度,接收到0x02:發(fā)送濕度,
? ? ? ? //接收到0x03:發(fā)送空氣質(zhì)量,接收到0x04:發(fā)送距離
? ? ? ? switch(rev_data)
? ? ? ? {
? ? ? ? ? ? case 0x01:send_data = temperature;break;
? ? ? ? ? ? case 0x02:send_data = humidity;break;
? ? ? ? ? ? case 0x03:send_data = value;break;
? ? ? ? ? ? case 0x04:send_data = distance/100;break;
? ? ? ? ? ? default:break;
? ? ? ? }
? ? ? ? if(rev_data>=0x01&&rev_data<=0x04)
? ? ? ? {
? ? ? ? ? ? send_data = send_data/100*256+((send_data%100)/10)*16+send_data%10;
? ? ? ? ? ? if(send_data<=255&&send_data>0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? USART_SendData(USART2, send_data);
? ? ? ? ? ? ? ? while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? USART_SendData(USART2, send_data/256);
? ? ? ? ? ? ? ? while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
? ? ? ? ? ? ? ? USART_SendData(USART2, send_data%256);
? ? ? ? ? ? ? ? while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? usart_flag = NO_CHAN;
? ? }
}
????????該函數(shù)在主程序中調(diào)用,當接收標志位被置位揪利,則說明單片機接收到手機發(fā)過來的指令數(shù)據(jù)态兴,根據(jù)所發(fā)的不同指令,則單片機發(fā)送不同的采集數(shù)據(jù)給手機疟位,手機接收到瞻润,則在手機界面顯示出數(shù)據(jù)。但別忘了甜刻,調(diào)用完該發(fā)送函數(shù)绍撞,需要將接收標志位復(fù)位,否則單片機將不斷地發(fā)送數(shù)據(jù)給手機得院,顯得有些無意義傻铣。這里,說明一下祥绞,我們有兩個宏定義#define NO_CHAN 0x00 #define CHAN_IN 0x01非洲,這樣做鸭限,可能意義會更明顯。在stm32里两踏,小編感覺像宏定義败京,結(jié)構(gòu)體等用得比較多(可以看一下固件庫函數(shù),都是這樣的)梦染,閱讀程序起來也好理解赡麦。
????????通過上面的操作,我們將藍牙模塊接好帕识,注意這里藍牙的TX隧甚,RX分別接USART2的RX,TX渡冻,然后下載好程序戚扳,打開《藍牙串口》軟件,點擊搜索族吻,即可搜索到藍牙帽借。在對話框界面,發(fā)送和接收對話框都勾選16進制超歌,在發(fā)送對話框發(fā)送0x01砍艾,即可在接收對話框接收到數(shù)據(jù),此時顯示的是溫度的數(shù)據(jù)巍举,為12度脆荷。此時再依次輸入0x02、0x03懊悯、0x04蜓谋,即可顯示所有數(shù)據(jù),此時溫度為12度炭分,濕度為69%桃焕,空氣質(zhì)量為104PPM,距離為26cm捧毛。界面里如果不勾選16進制观堂,則顯示亂碼,因為此時顯示的是字符數(shù)據(jù)呀忧。你可以在程序中發(fā)送英文字符串师痕,即可將字符串打印出來。但這個軟件不支持中文顯示而账,所以不能打印中文胰坟。
????????在這里,我聲明一下福扬,本章的內(nèi)容腕铸,是為了測試stm32串口配置的代碼以及藍牙模塊是否正常工作(由于stm32的usart1硬件電路已損壞,不能連接電腦來調(diào)試串口通信)铛碑。在后面狠裹,我會介紹如何通過《藍牙調(diào)試器》達到數(shù)據(jù)的實時顯示和監(jiān)控。