试验都通过:
- USB-TTL+蓝牙模块与手机蓝牙通讯,测试通过,能够互发数据并接收;
- STM32串口蓝牙与手机蓝牙通讯,测试通过;输入1,LED亮,输入2,LED灭,输入其它字符,LED亮;
- STM32串口蓝牙与PC蓝牙通讯,测试通过;输入1,LED亮,输入2,LED灭,输入其它字符,LED亮;
1. USB-TTL驱动安装,连接蓝牙模块
2. 蓝牙模块的调试
2.1 两种工作模式:
HC-05蓝牙串口通讯模块具有两种工作模式:命令响应工作模式和自动连接工作模式。在自动连接工作模式下模块又可分为主(Master)、从(Slave)和回环(Loopback)三种工作角色。
- 当模块处于自动连接工作模式时,将自动根据事先设定的方式连接的数据传输;
- 当模块处于命令响应工作模式时能执行AT命令,用户可向模块发送各种AT 指令,为模块设定控制参数或发布控制命令。
2.2 进入命令响应工作模式?
进入命令响应工作模式有两种方法:
- 模块上电,未配对情况下就是AT模式,波特率为模块本身的波特率,默认:9600,发送一次AT指令时需要置高一次PIO11;
- PIO11 置高电平后,再给模块上电,此时模块进入AT 模式,波特率固定为:38400,可以直接发送AT指令。
2.3 什么叫做置高一次PIO11?
在蓝牙模块中有一个小按键,按一下就置高一次PIO11。也就是说,第一种方法需要每发送一次AT指令按一次;而第二种方式是长按的过程中上电,之后就无需再管了,直接发送AT命令即可。
需要注意一下,两种进入命令响应工作模式的方式使用的波特率是不一样的,建议使用第二种方式。
2.4 怎么区分进了命令响应工作模式呢?
在蓝牙模块上有灯,当灯快闪的时候,就是自动连接工作模式;当灯慢闪的时候,就是命令响应工作模式。
2.5 串口调试助手发送AT命令格式
串口软件发送给HC-05蓝牙模块AT指令 ,必须严格按照格式发送才可以(即使看不到格式情况),否则返回错误ERROR或者没有反应,格式如下两种:
1.AT+一个回车;
2.AT命令+勾选发送新行
2.6 AT命令
进入到命令响应工作模式之后,就可以使用串口调试助手进行蓝牙调试了。
首先有一点,AT指令不区分大小写,下面介绍常用的AT指令:
指令名 | 响应 | 含义 |
AT | OK | 测试指令 |
AT+RESET | OK | 模块复位 |
AT+VERSION? | +VERSION:<Param> OK | 获得软件版本号 |
AT+ORGL | OK | 恢复默认状态 |
AT+ADDR? | +ADDR:<Param> OK | 获得蓝牙模块地址 |
AT+NAME=<Param> | OK | 设置设备名称 |
AT+NAME? | +NAME:<Param> OK | 获得设备名称 |
AT+PSWD=<Param> | OK | 设置模块密码 |
AT+PSWD? | +PSWD:<Param> OK | 获得模块密码 |
AT+UART=<Param1>,<Param2>,<Param3>,输入数据去掉尖括号 | OK | 设置串口参数 |
AT+UART? | +UART:<Param1>,<Param2>,<Param3> OK | 获得串口参数 |
2.7 AT命令之设置串口
- AT+UART?:获得串口参数,串口的参数一共有三个,波特率、停止位、检验位。其取值如下:
参数名称 | 取值 |
波特率 | 2400、4800、9600、19200、38400、5760、 115200、230400、460800、921600、1382400 |
停止位 | 0:1位 1:2位 |
校验位 | 0:NONE 1:Odd 2:Even |
设置蓝牙串口的波特率:115200。之后的内容,就会采用这个波特率来进行通讯。
3. PC蓝牙模块与手机传输数据
3.1 蓝牙模块与USB-TTL转换模块连接,再连接到电脑上,进入自动连接工作模式,打开软件野火的多功能调试助手fireTools或其它串口调试工具,在设置中选择编码为GB18030或UTF-8。
3.2 手机下载并打开“蓝牙串口APP”,连接蓝牙模块,蓝牙名HC05,配对码1234,设置编码与串口调试助手一致,在聊天界面下接收发送数据。
3.3 然后在电脑上的串口调试助手和手机的“蓝牙串口APP”之间就可以相互传输了,互相发送汉字或字符串试验。偶尔出现乱码,可能是我的USB-TTL-蓝牙模块的线太长的原因,干扰导致。
4. STM32蓝牙模块与电脑通讯
蓝牙模块上电,电脑控制面板搜索蓝牙设备,密码匹配,则电脑与透传模块将建立起连接,如果以前没有安装过蓝牙串口设备,则系统将自动安装驱动并生成虚拟串口,设备管理器打开串口设置通信格式或者使用串口调试软件进行设置。打开这个端口的时候蓝牙模块的LED会由快闪变为双闪,这时只需要把蓝牙模块当成是电脑的固定波特率的串口一样使用即可,只不过它是无线的。
5.STM32蓝牙模块与手机通讯
实现功能:手机通过蓝牙,向STM32单片机发送消息,STM32接收到消息之后原封不动的返回给手机,同时输入1、2、其它字符控制LED灯。
连线:使用USART5进行试验,也就是说STM32选取PC12(TX)、PD2(RX)来和HC-05进行连接,见下图UART5;同时手机通过蓝牙来和HC-05进行连接。
原理:手机通过蓝牙传输到HC-05上,再通过串口和STM32通信;而之前一般都是电脑上通过USB线转串口的方式,通过串口和STM32通信。本质上没有区别的。
说白了,只是个蓝牙转串口的设备,只要知道串口怎么编程使用,就可以了,实现了所谓的透明传输。蓝牙的相关一切都被封装起来了,都不需要接触到。
5. STM32控制程序
/**
******************************************************************************
* @file main.c
* @author fire
* @version V1.0
* @date 2013-xx-xx
* @brief 测试led
******************************************************************************
* @attention
*
* 实验平台:秉火 F103-霸道 STM32 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :http://firestm32.taobao.com
*
******************************************************************************
*/
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_rccclkconfig.h"
int main(void)
{
USART_Config();
LED_GPIO_Config();
HSE_SetSysClk( RCC_PLLMul_6 );
/*********************蓝牙串口输入输出、控制LED**********************************************/
printf( "蓝牙串口输入输出、控制LED测试\n" );
Usart_SendStr(DEBUG_USARTx, "请输入1、2、3,观察LED和返回值:");
// Usart_SendByte(DEBUG_USARTx,'A');
// Usart_SendHalfWord(DEBUG_USARTx, 0xff56);
// Usart_SendArray(DEBUG_USARTx, a,10);
while (1)
{
}
}
/*********************************************END OF FILE**********************/
#include "bsp_usart.h"
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_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(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/* 发送一个字节 */
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
USART_SendData(pUSARTx, data);
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
}
/* 发送两个字节的数据 */
void Usart_SendHalfWord(USART_TypeDef* pUSARTx, uint16_t data)
{
uint8_t temp_h,temp_l;
temp_h = (data&0xff00) >> 8 ;
temp_l = data&0xff;
USART_SendData(pUSARTx, temp_h);
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
USART_SendData(pUSARTx, temp_l);
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
}
/* 发送8位数据的数组 */
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num)
{
uint8_t i;
for( i=0; i<num; i++ )
{
Usart_SendByte(pUSARTx, array[i]);
}
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}
/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
uint8_t i=0;
do
{
Usart_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f10x.h"
#include <stdio.h>
#define DEBUG_USART1 0
#define DEBUG_USART2 0
#define DEBUG_USART3 0
#define DEBUG_USART4 0
#define DEBUG_USART5 1
#if DEBUG_USART1
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
#elif DEBUG_USART2
//串口2-USART2
#define DEBUG_USARTx USART2
#define DEBUG_USART_CLK RCC_APB1Periph_USART2
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
#define DEBUG_USART_IRQ USART2_IRQn
#define DEBUG_USART_IRQHandler USART2_IRQHandler
#elif DEBUG_USART3
//串口3-USART3
#define DEBUG_USARTx USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler
#elif DEBUG_USART4
//串口4-UART4
#define DEBUG_USARTx UART4
#define DEBUG_USART_CLK RCC_APB1Periph_UART4
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOC
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ UART4_IRQn
#define DEBUG_USART_IRQHandler UART4_IRQHandler
#elif DEBUG_USART5
//串口5-UART5
#define DEBUG_USARTx UART5
#define DEBUG_USART_CLK RCC_APB1Periph_UART5
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
#define DEBUG_USART_RX_GPIO_PORT GPIOD
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_IRQ UART5_IRQn
#define DEBUG_USART_IRQHandler UART5_IRQHandler
#endif
void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* pUSARTx, uint16_t data);
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str);
#endif /* __BSP_USART_H */
//晶振8M改为12M
#include "bsp_rccclkconfig.h"
void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
{
ErrorStatus HSEStatus;
// 把RCC 寄存器复位成复位值
RCC_DeInit();
// 使能 HSE
RCC_HSEConfig(RCC_HSE_ON);
HSEStatus = RCC_WaitForHSEStartUp();
if( HSEStatus == SUCCESS )
{
// 使能预取指
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
// 配置 PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
// 使能PLL
RCC_PLLCmd(ENABLE);
// 等待PLL稳定
while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
// 选择系统时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
/* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
}
}
void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
{
__IO uint32_t HSIStatus = 0;
// 把RCC 寄存器复位成复位值
RCC_DeInit();
// 使能 HSI
RCC_HSICmd(ENABLE);
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
if( HSIStatus == RCC_CR_HSIRDY )
{
// 使能预取指
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
// 配置 PLLCLK = HSE * RCC_PLLMul_x
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
// 使能PLL
RCC_PLLCmd(ENABLE);
// 等待PLL稳定
while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
// 选择系统时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
/* 如果HSI 启动失败,用户可以在这里添加处理错误的代码 */
}
}
void MCO_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 开启GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 选择GPIO8引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
//设置为复用功能推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
//设置IO的翻转速率为50M
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// 初始化GPIOA8
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
#ifndef __BSP_RCCCLKCONFIG_H
#define __BSP_RCCCLKCONFIG_H
#include "stm32f10x.h"
void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
void MCO_GPIO_Config(void);
void HSI_SetSysClk( uint32_t RCC_PLLMul_x );
#endif /*__BSP_RCCCLKCONFIG_H */
#include "stm32f10x_it.h"
#include "bsp_usart.h"
#include "bsp_led.h"
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
{
ucTemp = USART_ReceiveData(DEBUG_USARTx);//只能使用中断作为输入,不能使用ch = getchar(),蓝牙串口手机软件不支持。
switch(ucTemp)
{
case '1': LED1(ON);
break;
case '2': LED1(OFF);
break;
default: LED1(ON);
break;
}
USART_SendData(DEBUG_USARTx,ucTemp);
}
}
6. 蓝牙其它知识
6.1产品特性:
1、核心模块使用HC-05从模块,引出接口包括VCC,GND,TXD,RXD,EN引脚、蓝牙连接状态引出脚(STATE),未连接输出低,连接后输出高(应该是指通信后输出高);
2、led指示蓝牙连接状态,快闪表示没有蓝牙连接,慢闪表示进入AT模式,双闪表示蓝牙已连接并打开了端口
3、底板设置防反接二极管,带3.3V LDO,输入电压3.6~6V,未配对时电流约30mA,配对后约10mA,输入电压禁止超过7V!
4、接口电平3.3V,可以直接连接各种单片机(51,AVR,PIC,ARM,MSP430等),5V单片机也可直接连接,无需MAX232也不能经过MAX232!
5、空旷地有效距离10米(功率等级为CLASS 2),超过10米也是可能的,但不对此距离的连接质量做保证
6、配对以后当全双工串口使用,无需了解任何蓝牙协议,支持8位数据位、1位停止位、可设置奇偶校验的通信格式,这也是最常用的通信格式,不支持其他格式。
7、可以通过拉高34脚进入AT命令模式设置参数和查询信息
8、体积小巧(3.57cm*1.52cm),工厂贴片生产,保证贴片质量。并套透明热缩管,防尘美观,且有一定的防静电能力。
9、可通过AT命令切换为主机或者从机模式,可通过AT命令连接指定设备
10、支持从4800bps~1382400bps间的标准波特率
6.2 蓝牙三种角色:
AT+ROLE:该指令用于选择HC05蓝牙模块的角色,总共有三种角色:master,slave,loop-slave.
AT+ROLE=0\r\n 将蓝牙模块设置成从角色,只能被动连接
AT+ROLE=1\r\n 将蓝牙模块设置成主角色,可以查询周围SPP蓝牙从设备,并发送连接
AT+ROLE=2\r\n 将蓝牙模块设置成回环角色,被动连接,接收远程蓝牙模块主设备数据并将数据原样返回给远程蓝牙设备
这几个指令用在不同的场合,当设置蓝牙模块为从设备的时候,可以用手机的相关蓝牙装串口软件连接该设备,进行通讯;当设置成主角色的时候,可以搜索周遭的蓝牙从设备,并连接,这种模式在应用中很常用;回环角色很多时候都是用来做测试用的。
设置为主模块的步骤:
1、PIO11 置高。
2、上电,模块进入AT 命令响应状态。
3、超级终端或其他串口工具,设置波特率38400,数据位8 位,停止位1 位,无校验位,无流控制。
4、串口发送字符“AT+ROLE=1\r\n”,成功返回“OK\r\n”,其中\r\n 为回车换行。
5、PIO 置低,重新上电,模块为主模块,自动搜索从模块,建立连接。
6.3 蓝牙测试软件
USB-TTL连接蓝牙模块HC-05后,可一键获取和设置模块信息