4. HC05模块

4.1. HC05 简介

YH-HC05是野火科技推出的蓝牙串口模块,它采用蓝牙2.0协议,可与任何版本的蓝牙兼容通讯, 包括与具有蓝牙功能的电脑、蓝牙主机、手机、PDA、PSP等终端配对,可实现串口透传功能。 驱动HC05模块时只需要使用TTL电平标准的串口即可(5V/3.3V电压均可),支持的波特率范围为4800~1382400,非常适合用于单片机系统扩展蓝牙特性。

详细HC05模块资料请参考:https://doc.embedfire.com/products/link/zh/latest/module/bluetooth/hc05.html

4.2. AT指令

AT指令是应用于终端设备与PC应用之间的连接与通信的指令,每条AT命令中只能包含一条AT指令。

AT指令用法:

1、测试命令(Test Command)

在AT指令后面加上“=?”即构成测试命令。例如“AT+MODE=?”,会列举出所有支持的模式。

2、读取命令(Read Command)

在AT指令后面加上“=?”即构成测试命令。例如“AT+MODE?”,会列举当前是什么模式。

3、执行命令(Execute Command)

在AT指令后面加上“=”再接上相应的参数即可,例如“AT+MODE=NORMAL”,将当前模式设置为正常模式。对于一些没有参数的指令则不需要加参数, 比如”AT+RESET”。

4.3. 主从模式

主从设备模式也叫主仆模式,行为通常为一问一答,可以一个主机一个从机,也可以一个主机多个从机。

4.4. 透传

透传即透明传输,是指在传输中不管传输的内容是什么,只关心传输时的源地址和目标地址,对数据内容不做任何改变。

4.5. 连接方式

图4 - 1为ESP8266模块引脚图,

HC05

以指南者的开发板为例,下面是 HC05 与指南者开发板的连接方式,其他开发板GPIO连接方式请参考对应开发板模块例程。

HC05接口

HC05 IO

STM32 IO

VCC

接3.3V或5V

GND

GND

TXD

PA3(注意跳帽)

RXD

PA2(注意跳帽)

KEY

PB14

INT

PB13

注意

我们所提供的HC05模块资料里所包含的配套例程仅适用于我们的 YH-HC05 模块,对于其他市面上的HC05模块,可能不适用、无法兼容。

4.6. HC05 AT指令测试程序例程介绍及实验现象

4.6.1. 实验现象

首先根据“HC05接线说明”文件夹里的说明连接好HC05蓝牙模块,如果板子上面有 EBF-Module 模块接口,可以直接插到上面去,注意下电源正负极模块不要插反了。

然后连接好下载器和USB转串口,给开发板上电并下载好程序之后,打开串口调试助手,按一下复位开发板,会收到程序运行的提示信息, HC05模块准备好后,发送“AT”,测试 HC05 是否准备好,如果正常会收到回应“OK”。如下图所示。

HC05_AT指令测试串口助手

更多AT指令请参考模块资料。

注意

使用本例程,发送的AT指令都要大写,不需要加回车换行。

4.6.2. 例程介绍

在编写 HC05 模块驱动时,要考虑更改硬件环境的情况,我们可以用宏来定义连接到 HC05 模块的引脚,在更改或移植的时候只用改宏定义就可以。 以霸道开发板为例,我们把控制 HC05 模块引脚的宏定义到”bsp_hc05.h”文件中,定义PC4引脚连接到HC05 INT引脚,定义PG8引脚连接到HC05 KEY引脚。 而 IS_HC05_CONNECTED() 用于检查模块是否处于配对状态,实际上就是检查HC05 INT引脚的高低电平,若INT引脚为高电平,则表示HC05模块处于已配对连接状态。

bsp_hc05.h(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 // ... ...

 #define BLT_INT_GPIO_PORT       GPIOC                       /* GPIO端口 */
 #define BLT_INT_GPIO_CLK        RCC_APB2Periph_GPIOC        /* GPIO端口时钟 */
 #define BLT_INT_GPIO_PIN        GPIO_Pin_4                  /* 连接到HC05 INT引脚的GPIO */

 #define BLT_KEY_GPIO_PORT       GPIOG                       /* GPIO端口 */
 #define BLT_KEY_GPIO_CLK        RCC_APB2Periph_GPIOG        /* GPIO端口时钟 */
 #define BLT_KEY_GPIO_PIN        GPIO_Pin_8                  /* 连接到HC05 KEY引脚的GPIO */

 #define BLT_KEY_HIGHT           GPIO_SetBits(BLT_KEY_GPIO_PORT, BLT_KEY_GPIO_PIN);
 #define BLT_KEY_LOW             GPIO_ResetBits(BLT_KEY_GPIO_PORT, BLT_KEY_GPIO_PIN);

 //IS_HC05_CONNECTED用于检查模块是否处于配对状态
 #define IS_HC05_CONNECTED()     GPIO_ReadInputDataBit(BLT_INT_GPIO_PORT,BLT_INT_GPIO_PIN)

 // ... ...

霸道开发板的例程中是使用串口3与 HC05 通信,我们把串口3的引脚定义和相关配置定义到” bsp_usart_blt.h”头文件中,定义串口2发送引脚PB10,接收引脚为PB11,波特率为38400,等等。

bsp_usart_blt.h(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 //... ...

 #define             BLT_USART_BAUD_RATE                     38400

 #define             BLT_USARTx                              USART3
 #define             BLT_USART_APBxClock_FUN                 RCC_APB1PeriphClockCmd
 #define             BLT_USART_CLK                           RCC_APB1Periph_USART3
 #define             BLT_USART_GPIO_APBxClock_FUN            RCC_APB2PeriphClockCmd
 #define             BLT_USART_GPIO_CLK                      (RCC_APB2Periph_GPIOB)
 #define             BLT_USART_TX_PORT                       GPIOB
 #define             BLT_USART_TX_PIN                        GPIO_Pin_10
 #define             BLT_USART_RX_PORT                       GPIOB
 #define             BLT_USART_RX_PIN                        GPIO_Pin_11
 #define             BLT_USART_IRQ                           USART3_IRQn
 #define             BLT_USART_IRQHandler                    USART3_IRQHandler

 //... ...

下面是HC05用到的串口3初始化函数 BLT_USART_Config。定义GPIO、USART结构体,使能串口2及对应的管脚时钟,配置 TX 引脚,GPIO_Mode设置为复用推挽输出, GPIO_Speed设置为50MHz,初始化 TX 引脚配置。配置 RX 引脚,GPIO_Mode设置为浮空输入,GPIO_Speed保留 TX 引脚的配置,然后初始化 RX 引脚配置。

USART_BaudRate为串口波特率,这里设置为38400,USART_WordLength为数据格式长度,设置字长为8位数据格式,设置一个停止位,无奇偶校验,无硬件数据流控制, 串口模式设置为收发模式,初始化串口3,最后就是使能串口的中断。

bsp_usart_blt.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 void BLT_USART_Config(void)
 {
     GPIO_InitTypeDef GPIO_InitStructure;
     USART_InitTypeDef USART_InitStructure;

     // 打开串口GPIO的时钟
     BLT_USART_GPIO_APBxClock_FUN(BLT_USART_GPIO_CLK, ENABLE);

     // 打开串口外设的时钟
     BLT_USART_APBxClock_FUN(BLT_USART_CLK, ENABLE);

     // 将USART Tx的GPIO配置为推挽复用模式
     GPIO_InitStructure.GPIO_Pin = BLT_USART_TX_PIN;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(BLT_USART_TX_PORT, &GPIO_InitStructure);

     // 将USART Rx的GPIO配置为浮空输入模式
     GPIO_InitStructure.GPIO_Pin = BLT_USART_RX_PIN;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     GPIO_Init(BLT_USART_RX_PORT, &GPIO_InitStructure);

     // 配置串口的工作参数
     // 配置波特率
     USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
     // 配置 针数据字长
     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
     // 配置停止位
     USART_InitStructure.USART_StopBits = USART_StopBits_1;
     // 配置校验位
     USART_InitStructure.USART_Parity = USART_Parity_No ;
     // 配置硬件流控制
     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
     // 配置工作模式,收发一起
     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
     // 完成串口的初始化配置
     USART_Init(BLT_USARTx, &USART_InitStructure);

     /* 配置中断优先级 */
     BLT_NVIC_Configuration();
     /* 使能串口2接收中断 */
     USART_ITConfig(BLT_USARTx, USART_IT_RXNE, ENABLE);
     // 使能串口总线空闲中断
     USART_ITConfig (BLT_USARTx, USART_IT_IDLE, ENABLE );

     USART_Cmd(BLT_USARTx, ENABLE);
     USART_ClearFlag(BLT_USARTx, USART_FLAG_TC);
 }

在来看一下发送AT指令的函数HC05_Send_CMD实现。定义变量retry为3,表示发送AT指令的操作最多尝试3次, 在 while 循环里,首先使用宏 BLT_KEY_HIGHT 拉高KEY引脚,再用串口3发送AT命令到HC05,然后延时 10 ms等待HC05返回的数据接收完毕, 定义 len 为 HC05 反馈回来的数据长度,用于判断是否有数据,从串口3缓冲区中获取数据,判断到有数据之后就进行简单分析,即判断接收到的数据当中是否包含”OK”的字符,如果包含则表明AT命令发送成功。

bsp_hc05.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 /**
 * @brief  向HC05模块发送命令并检查OK。只适用于具有OK应答的命令,最长等待5s直到收到OK
 * @param  cmd:命令的完整字符串,需要加\r\n。
 * @param    clean 命令结束后是否清除接收缓冲区,1 清除,0 不清除
 * @template  复位命令:  HC05_Send_CMD("AT+RESET\r\n",1);
 * @retval 0,设置成功;其他,设置失败.
 */
 uint8_t HC05_Send_CMD(char* cmd,uint8_t clean)
 {
     uint8_t retry=3;
     uint32_t i;
     uint16_t len;
     char * redata;

     while(retry--)
     {
         BLT_KEY_HIGHT;
         Usart_SendString(HC05_USART,(uint8_t *)cmd);
         i=500;              //初始化i,最长等待5秒
         hc05_delay_ms(10);  //

         do
         {
             redata = get_rebuff(&len);
             if(len>0)
             {
                 if(strstr(redata,"OK"))
                 {
                     HC05_DEBUG("send CMD: %s",cmd); //打印发送的蓝牙指令和返回信息

                     HC05_DEBUG("recv back: %s",redata);

                     if(clean==1)
                         clean_rebuff();
                     //BLT_KEY_LOW;

                     return 0; //AT指令成功
                 }
             }

             hc05_delay_ms(10);

         }while( --i ); //继续等待

         HC05_DEBUG("send CMD: %s",cmd); //打印发送的蓝牙指令和返回信息
         HC05_DEBUG("recv back: %s",redata);
         HC05_DEBUG("HC05 send CMD fail %d times", retry); //提示失败重试

     }

     //BLT_KEY_LOW;
     HC05_DEBUG("HC05 send CMD fail ");

     if(clean==1)
         clean_rebuff();

     return 1; //AT指令失败
 }

我们来看看主函数,主函数里面主要是初始化和配置,然后进入主循环。 首先初始化开发板上的一些硬件,比如调试串口、灯、按键等,还有调用 HC05_Init 函数初始化蓝牙模块(包括了GPIO和蓝牙串口)。 接着重复调用 HC05_Send_CMD 函数、传入不同命令参数来配置蓝牙模块,比如将HC05设置为从模式、蓝牙名字为”HC05_SLAVE”等。

main.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 /*各种命令测试演示,默认不显示。
  *在bsp_hc05.h文件把HC05_DEBUG_ON 宏设置为1,
  *即可通过串口调试助手接收调试信息*/

 HC05_Send_CMD("AT+VERSION?\r\n",1);

 HC05_Send_CMD("AT+ADDR?\r\n",1);

 HC05_Send_CMD("AT+UART?\r\n",1);

 HC05_Send_CMD("AT+CMODE?\r\n",1);

 HC05_Send_CMD("AT+STATE?\r\n",1);

 HC05_Send_CMD("AT+ROLE=0\r\n",1);

 /*初始化SPP规范*/
 HC05_Send_CMD("AT+INIT\r\n",1);
 HC05_Send_CMD("AT+CLASS=0\r\n",1);
 HC05_Send_CMD("AT+INQM=1,9,48\r\n",1);

 /*设置模块名字*/
 sprintf(hc05_nameCMD,"AT+NAME=%s\r\n",hc05_name);
 HC05_Send_CMD(hc05_nameCMD,1);

 HC05_INFO("本模块名字为:%s ,模块已准备就绪。",hc05_name);

最后进入主循环,在主循环里调用 ATCMD_Test 测试函数,这个函数主要就是处理用户输入到串口调试助手发送给开发板的数据、并且将有效的AT命令数据转发到HC05蓝牙模块, 然后接收到HC05蓝牙模块返回的信息之后再发送该信息到串口调试助手以便用户查看。详细代码请看例程。

注意

注:1. 取消注释 bsp_hc05.h 文件里面 ENABLE_LCD_DISPLAY 宏,可以切换到带LCD液晶显示的模式。2. 将 bsp_hc05.h 文件里面 HC05_DEBUG_ON 宏定义设置为 1,可以让程序输出详细的调试信息,方便了解程序底层和调试。

4.7. HC05透传控制LED灯例程介绍及实验现象

4.7.1. 实验现象

首先根据“HC05接线说明”文件夹里的说明连接好HC05蓝牙模块,如果板子上面有 EBF-Module 模块接口,可以直接插到上面去,注意下电源正负极模块不要插反了。

然后连接好下载器和USB转串口,给开发板上电并下载好程序之后,打开串口调试助手,按一下复位开发板,会收到程序运行的提示信息,HC05模块准备好后,如果处于未连接状态,可以发送AT指令。 (注:使用例程,发送的AT指令都要大写,不需要回车换行。)如下图所示。

HC05_透传控制LED灯串口助手

可以看到串口调试助手界面显示 “蓝牙尚未连接。请用手机打开蓝牙调试助手搜索连接蓝牙” 的提示,如果没有连接该HC05的话程序会每隔一段时间就打印这个提示。 只有在这个未连接的状态下才能够向该HC05模块发送AT指令,若是已连接之后便不能发送AT指令了,除非断开连接。

我们可以自行在应用市场搜索“蓝牙调试助手”,在安卓手机上安装好,打开它,然后搜索 HC05_SLAVE 连接HC05蓝牙模块。

连接成功后,会定时收到蓝牙连接的提示信息。 连接成功之后就不可以发送AT指令了,只可以透传发送数据,要发送AT指令需要先断开蓝牙连接。

模块准备好后,在电脑串口调试助手或是手机蓝牙调试助手(需要连接好HC05)发送“RED_LED”字符串,都会翻转一次板载LED灯。

4.7.2. 例程介绍

我们还是以霸道开发板为例,引脚定义、调试串口和蓝牙串口配置等、还有main函数里的初始化部分与前面的实验里的基本上是一样的, 与本例程不一样的地方主要在于主函数里还多了一个步骤,就是调用 SysTick_Init 函数来初始化SysTick每10ms产生一次中断。 而在SysTick中断服务函数 SysTick_Handler 里面程序每5秒钟执行任务0,任务0的内容就是将需要检测蓝牙是否连接的标志位 hc05_inquery_connect 置1, 置1后使得程序在主循环里面会检测一次蓝牙是否已连接。另外,任务0的执行周期,是可以通过 TASK_DELAY_0 宏定义进行更改的,也就是说可以更改检测蓝牙是否已连接的检测间隔。

本例程我们主要讲解主循环里的内容。 在 while(1) 循环里面,我们每 5s 检查一次蓝牙连接,并且通过调试串口来打印一条相应的提示信息。 我们还调用 TransData_CtrlLED_Test 测试函数,来处理调试串口和蓝牙串口的发送或者接收到的数据,该函数的内容如下。

main.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 /**
 * @brief  处理串口数据控制LED灯
 * @param  无
 * @retval 无
 */
 void TransData_CtrlLED_Test(void)
 {
     /* 处理调试串口接收到的串口助手数据 */
     if(DEBUG_USART_ReceiveData.receive_data_flag == 1)
     {
         DEBUG_USART_ReceiveData.uart_buff[DEBUG_USART_ReceiveData.datanum] = 0;
         //在这里可以自己定义想要接收的字符串然后处理
         //这里接收到串口调试助手发来的 “RED_LED”就会把板子上面的红灯取反一次
         if( strstr((char *)DEBUG_USART_ReceiveData.uart_buff,"RED_LED") )
         {
             LED1_TOGGLE;
         }

         //如果手机蓝牙连接了模块,则发送到手机端显示数据
         if( IS_HC05_CONNECTED() )
         {
             BLT_KEY_LOW;
             Usart_SendStr_length(BLT_USARTx, DEBUG_USART_ReceiveData.uart_buff, DEBUG_USART_ReceiveData.datanum);
         }
         //如果蓝牙没有被连接,如果数据是以AT开头的,就把KEY置高,设置蓝牙模块
         else if( strstr((char *)DEBUG_USART_ReceiveData.uart_buff,"AT") == (char *)DEBUG_USART_ReceiveData.uart_buff )
         {
             BLT_KEY_HIGHT;
             Usart_SendStr_length(BLT_USARTx, DEBUG_USART_ReceiveData.uart_buff, DEBUG_USART_ReceiveData.datanum);
             Usart_SendStr_length(BLT_USARTx,"\r\n",2);
             BLT_KEY_LOW;
         }

         //串口助手显示接收到的数据
         Usart_SendString( DEBUG_USARTx, "\r\nrecv USART1 data:\r\n" );
         Usart_SendString( DEBUG_USARTx, DEBUG_USART_ReceiveData.uart_buff );
         Usart_SendString( DEBUG_USARTx, "\r\n" );
         //LCD显示接收到的数据
         #ifdef ENABLE_LCD_DISPLAY
         LCD_ClearLine(LINE(5));
         LCD_ClearLine(LINE(6));
         LCD_ClearLine(LINE(7));
         LCD_ClearLine(LINE(8));
         ILI9341_DispStringLine_EN ( (LINE(5)), (char *)DEBUG_USART_ReceiveData.uart_buff );
         #endif

         //清零调试串口数据缓存
         DEBUG_USART_ReceiveData.receive_data_flag = 0;              //接收数据标志清零
         DEBUG_USART_ReceiveData.datanum = 0;
     }


     /* 处理蓝牙串口接收到的蓝牙数据 */
     if(BLT_USART_ReceiveData.receive_data_flag == 1)
     {
         BLT_USART_ReceiveData.uart_buff[BLT_USART_ReceiveData.datanum] = 0;
         //在这里可以自己定义想要接收的字符串然后处理
         //这里接收到手机蓝牙发来的 “RED_LED”就会把板子上面的红灯取反一次
         if(strstr((char *)BLT_USART_ReceiveData.uart_buff,"RED_LED"))
         {
             LED1_TOGGLE;
         }

         //串口助手显示接收到的数据
         Usart_SendString( DEBUG_USARTx, "\r\nrecv HC-05 data:\r\n" );
         Usart_SendString( DEBUG_USARTx, BLT_USART_ReceiveData.uart_buff );
         Usart_SendString( DEBUG_USARTx, "\r\n" );

         //LCD显示接收到的数据
         #ifdef ENABLE_LCD_DISPLAY
         LCD_ClearLine(LINE(10));
         LCD_ClearLine(LINE(11));
         LCD_ClearLine(LINE(12));
         LCD_ClearLine(LINE(13));
         ILI9341_DispStringLine_EN ( (LINE(10)), (char *)BLT_USART_ReceiveData.uart_buff );
         #endif

         //清零蓝牙串口数据缓存
         BLT_USART_ReceiveData.receive_data_flag = 0;                //接收数据标志清零
         BLT_USART_ReceiveData.datanum = 0;
     }
 }

在这个函数里,DEBUG_USART_ReceiveData.receive_data_flag 和 BLT_USART_ReceiveData.receive_data_flag 是最关键的, 前者是调试串口数据接收完成标志位,后者是蓝牙串口数据接收完成标志位,它们都在各自的串口中断里判断 USART_IT_IDLE 空闲标志被置位后才被置1的。

当在 TransData_CtrlLED_Test函数里判断 DEBUG_USART_ReceiveData.receive_data_flag 和 BLT_USART_ReceiveData.receive_data_flag 被置1后, 就从 DEBUG_USART_ReceiveData.uart_buff[] 或者 BLT_USART_ReceiveData.uart_buff[] 这两个数据缓冲区里面读取和处理串口接收到的数据。

注意

注:1. 取消注释 bsp_hc05.h 文件里面 ENABLE_LCD_DISPLAY 宏,可以切换到带LCD液晶显示的模式。2. 将 bsp_hc05.h 文件里面 HC05_DEBUG_ON 宏定义设置为 1,可以让程序输出详细的调试信息,方便了解程序底层和调试。

4.8. HC05综合测试程序例程介绍及实验现象

4.8.1. 实验现象

首先根据“HC05接线说明”文件夹里的说明连接好HC05蓝牙模块,如果板子上面有 EBF-Module 模块接口,可以直接插到上面去,注意下电源正负极模块不要插反了。

然后连接好下载器和USB转串口,给开发板上电并下载好程序之后,打开串口调试助手,按一下复位开发板,稍等一段时间后,会收到程序运行的提示信息。如下图所示。

HC05_综合测试程序串口助手

本例程程序有四个功能:

  1. 每隔一段时间检查蓝牙连接。若蓝牙尚未连接,如果是从模式,提示用户搜索连接蓝牙;如果是主模式,则输出HC05模块扫描到的其他蓝牙设备信息,并自动连接名字含有 “HC05” 字符的蓝牙设备。

  2. 如果蓝牙已经连接上,用另一端的蓝牙发送数据,程序收到数据后会自动处理,输出提示信息;如果接收到蓝牙数据含有用户自定义指令:”AT+LED1=ON”或”AT+LED1=OFF”,将会打开或关闭LED1灯

  3. 按下 KEY1,切换 Master / Slave 模式。程序刚上电是 Slave 模式。

  4. 按下 KEY2,更改蓝牙设备名字,新名字会在“HC05_MASTER/SLAVE_”后面添加一个0~255的随机数。

按下 KEY1 切换主从模式

HC05_切换为主模式

按下 KEY2 更改蓝牙设备名字

按下开发板的KEY2按键,会随机生成一个新名字。新名字会在“HC05_MASTER/SLAVE_”后面添加一个0~255的随机数。比如“HC05_MASTER_123”或“HC05_SLAVE_23”

注意不要按KEY1,因为开发板刚上电后默认设置蓝牙模块为从模式,若是按下KEY1,模块会切换为主模式,若是在主模式下程序会阻塞式地不断扫描蓝牙设备, 此时需要等待程序扫描蓝牙设备完成后才能响应按键按下,因此切换为主模式之后需要长按KEY2一小段时间才能更改蓝牙名字。

HC05_综合测试程序修改名字

连接该 HC05 蓝牙

打开手机的蓝牙调试 APP,打开手机的蓝牙设备,点击界面左下角的“连接”按钮,会弹出“查找设备中…”的窗口,稍等一下会出现名为“HC05_SLAVE”的蓝牙设备, 这就是我们的HC05模块的名字,点击该设备,APP会与HC05尝试进行连接,输入配对码“1234”,即可连接成功。APP的操作见图下图,

HC05_1

APP与模块连接上后,HC05模块会主动向APP发送类似“<Device Name> send data test, test data=<x>”的字样,其中<Device Name>为HC05模块的名字,<x>则为一个自加的字符串编号。

APP与模块连接上后,可以使用APP通过蓝牙向开发板发送数据。点击界面中的输入框,输入字符串,然后点击“send”发送按钮来发送数据,开发板接收到数据后会通过串口打印出来。

除了发送普通字符串,还可以向开发板发送命令控制板子上的LED灯。开发板配套的程序支持两条命令:“AT+LED1=ON”和“AT+LED1=OFF”, 分别用于点亮开发板上的LED1和关闭LED1,如果开发板上的是RGB灯,则点亮的应该是红灯。 开发板接收到命令后,会在串口助手上显示接收到的命令,并且控制LED灯。如果需要其它命令,用户可修改配套的STM32程序,实现自定义的功能。

注意

本实验例程需要自己从手机应用市场搜索并选择一个合适的蓝牙调试助手APP来搜索和连接 HC05 蓝牙模块。

4.8.2. 例程介绍

我们来看main主函数,初始化和配置的部分与前面两个例程的几乎是一致的,程序会把 HC05 蓝牙模块配置为从模式(Slave), 也会调用 SysTick_Init 初始化和启动 SysTick 定时器使之产生10ms的定时中断,在其中断服务函数 SysTick_Handler 里面执行任务0和任务1, 同样,更改 TASK_DELAY_0 和 TASK_DELAY_1 这两个宏可以更改这两个任务的执行间隔,本例程中默认设置的是 5s 和 500ms。 实际上,这与前一个实验例程的思路是一致的,只不过在本例程中新增加了任务1的内容,在任务1里面将标志位 hc05_check_recvbuff 置1。

stm32f10x_it.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 void SysTick_Handler(void)
 {
     int i;

     for(i=0; i<TASK_DELAY_NUM; i++)
     {
         Task_Delay_Group[i] ++;                   //任务计时,时间到后执行
     }


     /* 处理任务0 */
     if(Task_Delay_Group[0] >= TASK_DELAY_0)     //判断是否执行任务0
     {
         Task_Delay_Group[0] = 0;                  //置0重新计时

         /* 任务0:检查蓝牙是否已连接 */

         hc05_inquery_connect = 1; //如果蓝牙没有连接,标志位置1

     }

     /* 处理任务1 */
     if(Task_Delay_Group[1] >= TASK_DELAY_1)     //判断是否执行任务1
     {
         Task_Delay_Group[1] = 0;                  //置0重新计时


         /* 任务1:检查蓝牙接收缓冲区是否有数据 */
         hc05_check_recvbuff = 1;
     }
 }

我们重点来看下本例程中main函数的主循环里面的内容是什么。

main.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 /**
 * @brief  主函数
 * @param  无
 * @retval 无
 */
 int main(void)
 {
     // ......
     // ...... 省略掉了 ......


     /* SysTick 10ms中断初始化 */
     SysTick_Init();

     while(1)
     {

         //每 5s 检查一次蓝牙连接,搜索蓝牙模块,并进行连接
         if( 1 == hc05_inquery_connect )
         {
             hc05_inquery_connect = 0; //清零标志位

             CheckConnect_LinkHC05_Test();
         }

         //连接后每隔一段时间检查接收缓冲区
         if(1 == hc05_check_recvbuff)
         {
             hc05_check_recvbuff = 0; //清零标志位

             CheckRecvBltBuff_Test();
         }


         //如果KEY1被单击,切换master-slave模式
         if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  )
         {
             Switch_HC05Mode_Test();
         }

         //如果KEY2被单击,随机生成一个名字
         if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON  )
         {
             Generate_Modify_HC05Name();
         }

     }
 }

主函数的 while(1) 循环里面,我们知道由于 SysTick 中断的关系,hc05_inquery_connect 标志位每5秒会被置 1,hc05_check_recvbuff 标志位每0.5秒会被置1。 因此,当 hc05_inquery_connect 置 1 时,我们进入if语句里面执行的 CheckConnect_LinkHC05_Test 函数,该函数的作用是检查和提示蓝牙是否已连接, 若是HCO5模块工作在主模式并且处于未连接状态,则还会搜索其他蓝牙信号并进行连接; 当 hc05_check_recvbuff 置 1 时,我们执行 CheckRecvBltBuff_Test 函数来检查蓝牙接收缓冲区、并且处理HC05蓝牙模块接收到的数据。

接着检测两个按键 KEY1 和 KEY2 是否被按下,按下 KEY1 会调用 Switch_HC05Mode_Test 函数切换主从模式,按下 KEY2 会调用 Generate_Modify_HC05Name 函数随机生成并更改蓝牙设备名字。 详细代码请查看例程。

下面是蓝牙串口中断函数 BLT_USART_IRQHandler,主要功能是将接收到的蓝牙串口数据存放到 uart_buff 缓存数组中。

stm32f10x_it.c(霸道开发板例程)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 /* 蓝牙串口数据缓存最大长度 */
 #define     UART_BUFF_SIZE      1024     //在 bsp_usart_blt.h 里面定义了

 extern volatile    uint16_t uart_p;
 extern uint8_t     uart_buff[UART_BUFF_SIZE];


 void BLT_USART_IRQHandler(void)
 {
     if(uart_p<UART_BUFF_SIZE)
     {
         if(USART_GetITStatus(BLT_USARTx, USART_IT_RXNE) != RESET)
         {
             uart_buff[uart_p] = USART_ReceiveData(BLT_USARTx);
             uart_p++;
         }
     }
     else
     {
         USART_ClearITPendingBit(BLT_USARTx, USART_IT_RXNE);
         clean_rebuff();
     }
 }

注意

注:1. 取消注释 bsp_hc05.h 文件里面 ENABLE_LCD_DISPLAY 宏,可以切换到带LCD液晶显示的模式。2. 将 bsp_hc05.h 文件里面 HC05_DEBUG_ON 宏定义设置为 1,可以让程序输出详细的调试信息,方便了解程序底层和调试。