读者们,想你们的小编又回来了。
从这一章开始,小编将进行上位机与下位机通信的开发,将单片机采集到的数据传输到手机实时显示。当然,考虑到这部分还是有点难度的,并且,在调试过程中,我找到两个蓝牙软件,一个是《蓝牙串口》,一个是《蓝牙调试器》。其中《蓝牙串口》可以简单发送和接收一些字符和16进制数,《蓝牙调试器》的功能比较强大,但在接收发界面里显示不出来,不知道是软件本身问题,还是我没设置好相关参数。但这款软件里的专业调试界面可以自己布局控件,即不需要编写代码就能做出符合自己项目的上位机来,所以还是得佩服一下该开发者。
在本章中,小编将开发下位机通信程序,结合《蓝牙串口》软件,实现从手机发送控制指令,手机再接收单片机发送过来的相应数据。在这里,人为规定,发送0x01,则手机串口接收到温度数据(1字节),发送0x02,则手机串口接收到湿度数据(1字节),发送0x03,则手机串口接收到空气质量数据(若0~255,1字节,若大于255,2字节),发送0x04,则手机串口接收到距离数据(若0~255,1字节,若大于255,2字节)。
1.资源分析
蓝牙模块HC-05,是主从一体的蓝牙串口模块,简单的说,当蓝牙设备与蓝牙设备配对连接成功后,我们可以忽视蓝牙内部的通信协议,直接将将蓝牙当做串口用。当建立连接,两设备共同使用一通道也就是同一个串口,一个设备发送数据到通道中,另外一个设备便可以接收通道中的数据。
蓝牙模块,共有4个引脚,其中两个电源引脚VCC和GND,一个数据发送端TX,一个数据接收端RX。而stm32f103c8t6具有3个USART串口,USART是一个全双工通用同步/异步串行收发模块。而本次制作,由于USART1串口接口已经焊接设计好,用于与电脑串口通信的(有点尴尬,已损坏,但影响不大),所以采用USART2来通信(TX—>PA2,RX—>PA3)。
2.软件分析
(1)配置串口相关的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为复用推挽输出*/
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为复用浮空输入*/
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端口设置成复用推挽输出,RX端口设置成浮空输入,在开启相关GPIOA时钟的同时,开启串口时钟和复用时钟。
(2) 配置相应串口模式
void usart_para_config(void)
{
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 115200;//设置波特率为115200
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控
USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//发送和接收模式
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);//清除发送完成标志位
USART_Cmd(USART2, ENABLE);//使能串口2
}
串口模式函数里,由于蓝牙AT指令设置的波特率为115200(不会设置的可以网上查),设置成接收模式,通信的数据结构为字长为8,无奇偶校验位,1位停止位。使用USART_Init()函数,将USART2串口初始化。接着,使能接收中断,清除发送完成标志位,最后使能串口2。
(3)配置NVIC
void usart_nvic_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置组优先级
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //设置串口2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //设置子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
}
由于stm32需要接收手机发过来的控制指令,而接收通常不是每时每刻的,因此采用中断的方式去做,所以需要设置NVIC,以及使能串口中断。中断优先级的配置已经经过多次了,如果还是不清楚的话,就上网再查查。
(4)编写串口接收中断程序
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET)
{
rev_data = USART_ReceiveData(USART2); //接收数据
usart_flag = CHAN_IN;
}
USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除接收中断标志
}
串口接收中断程序里,我们调用串口接收数据函数,暂存在变量rev_data里,然后将接收标志位置位,即可在主程序里调用数据发送语句,否则,主程序是不会发送数据给手机的。
(5)发送采集数据函数
void bluetooth(void)
{
if(usart_flag == CHAN_IN)
{
//接收到0x01:发送温度,接收到0x02:发送湿度,
//接收到0x03:发送空气质量,接收到0x04:发送距离
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;
}
}
该函数在主程序中调用,当接收标志位被置位,则说明单片机接收到手机发过来的指令数据,根据所发的不同指令,则单片机发送不同的采集数据给手机,手机接收到,则在手机界面显示出数据。但别忘了,调用完该发送函数,需要将接收标志位复位,否则单片机将不断地发送数据给手机,显得有些无意义。这里,说明一下,我们有两个宏定义#define NO_CHAN 0x00 #define CHAN_IN 0x01,这样做,可能意义会更明显。在stm32里,小编感觉像宏定义,结构体等用得比较多(可以看一下固件库函数,都是这样的),阅读程序起来也好理解。
通过上面的操作,我们将蓝牙模块接好,注意这里蓝牙的TX,RX分别接USART2的RX,TX,然后下载好程序,打开《蓝牙串口》软件,点击搜索,即可搜索到蓝牙。在对话框界面,发送和接收对话框都勾选16进制,在发送对话框发送0x01,即可在接收对话框接收到数据,此时显示的是温度的数据,为12度。此时再依次输入0x02、0x03、0x04,即可显示所有数据,此时温度为12度,湿度为69%,空气质量为104PPM,距离为26cm。界面里如果不勾选16进制,则显示乱码,因为此时显示的是字符数据。你可以在程序中发送英文字符串,即可将字符串打印出来。但这个软件不支持中文显示,所以不能打印中文。
在这里,我声明一下,本章的内容,是为了测试stm32串口配置的代码以及蓝牙模块是否正常工作(由于stm32的usart1硬件电路已损坏,不能连接电脑来调试串口通信)。在后面,我会介绍如何通过《蓝牙调试器》达到数据的实时显示和监控。