一、引脚连接:
TX - RX
RX - TX
GND - GND(接地)
VCC - VCC(5V)
EN、STATE不用连接
二、使用的串口工具:
链接:https://pan.baidu.com/s/1zmHCT-tslNEL-3D1EEWuJQ
提取码:z786
CH340驱动:
链接:https://pan.baidu.com/s/1E-2djqB7WT3zi04l3wg45Q
提取码:ryx5
三、进入AT命令模式:
1、进入AT命令模式
HC05 进入AT命令模式需要手一直按住按键然后上电,此时模块红灯慢闪(大概2秒闪一次),模块进入AT模式,电脑串口助手波特率需要调至38400,AT命令后面要加回车换行符(电脑上直接按回车键即可)
2、需要的AT命令
测试命令(AT)
恢复默认指令(AT+ORGL)
输入命令后,蓝牙会退出AT命令模式,所以需要重新进入。
设置配对密码(AT+PSWD="0000")
配置模式(主模式或从模式 AT+ROLE)
AT+ROLE=1 (主模式)
AT+ROLE=0 (从模式)
查询地址(AT+ADDR?)
绑定地址(AT+BIND)
获取到的地址记得把:改为,
设置波特率(AT+UART=115200,0,0)
此波特率为两个蓝牙通信时的波特率,AT命令模式的波特率还是38400
3、AT命令
1, AT+ROLE设置主从模式:
AT+ROLE=1是设成主,AT+ROLE=0是设成从,AT+ROLE=2设成回环模式Slave-Loop:被动连接,接收远程蓝 牙主设备数据并将数据原样返回给远程蓝牙
AT+ROLE?:查询主从状态
2, AT+RESET:HC-05复位
3, AT+VERSION?:获取HC-05的软件版本号,只能获取,不能修改。
4, AT+ORGL:恢复出厂默认设置,当把模块设置乱了,使用此命令进行恢复默认值。
5, AT+ADDR?:获取HC-05的蓝牙地址码,只能获取,不能修改。
6, AT+NAME?:获取HC-05的名字,AT+NAME=xlg,修改模块的名字为xlg,具体名字自行修改。
7, AT+CLASS?:设置查询设备的类型,尽量不要去修改此参数。默认是1F00。
8, AT+IAC?:查询设置查询访问码,默认是9E8B33,尽量不要去修改此参数。
9, AT+PSWD?:查询设置配对密码,AT+PSWD=”0000”,密码要有双引号,密码是四位数字.
10, AT+UART:AT+UART?是查询当前模块的波特率,AT+UART=波特率,0,0。
11, AT+CMODE:AT+CMODE?是查询当前连接模式。AT+CMODE=0,1,2(0——指定蓝牙地址连接模式(指定蓝牙地址由绑定指令设置)1——任意蓝牙地址连接模式(不受绑定指令设置地址的约束)2——回环角色(Slave-Loop)默认连接模式:0)。
12, AT+BIND:AT+BIND?查询当前绑定地址,AT+BIND=NAP,UAP,LAP(用逗号隔开)。
13, AT+RMADD:从蓝牙配对列表中删除所有认证设备.
14, AT+STATE?:获取蓝牙模块工作状态.
15, AT+LINK=NAP,UAP,LAP:与远程设备建立连接。
16, AT+DISC:断开连接.
17, AT+RNAME?NAP,UAP,LAP:获取远程蓝牙设备名称.
18, AT+ADCN?:获取蓝牙配对列表中认证设备数。
19, AT+MRAD?获取最近使用过的蓝牙认证设备地址。
20, AT+INQM:设置查询模式,AT+INQM=1,9,48(1-带RSSI信号强度指示,9-超过9个蓝牙设备响应则终止查询,48-设定超时为48*1.28=61.44秒)
四、两蓝牙通信配置:
1、测试
2、复位
3、设置波特率
4、设置配对码
5、设置主从模式
6、绑定地址
从模块绑定主模块地址或主模块绑定主地址都有可以
7、测试通信
先把主从模块断电再上电(不用按按钮),两个模块会自动匹配,匹配成功两模块会按一定频率同时亮灯和灭灯。
此时选择波特率为AT命令设置时的波特率。
五、在STM32中两设备通信
接线:STM32中PTA9接RX,PTA10接TX,PTB1、PTB11为两个按钮,分别为按钮1和按钮2,PTA1、PTA2接两个LED,分别为LED1,LED2
功能:按钮1控制LED2的亮灭,按钮2控制LED1的亮灭
现象:当按钮1按下时,两STM32中LED2同时亮灭,按钮2按下时,两LED1同时亮灭
代码:
串口.c
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
#include <String.h>
#include "OLED.h"
char BUF[256];
unsigned short cnt = 0;
/**
* 函 数:串口初始化
* 参 数:无
* 返 回 值:无
*/
void Serial_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA9引脚初始化为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA10引脚初始化为上拉输入
/*USART初始化*/
USART_InitTypeDef USART_InitStructure; //定义结构体变量
USART_InitStructure.USART_BaudRate = 115200; //波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式,发送模式和接收模式均选择
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验,不需要
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位,选择1位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长,选择8位
USART_Init(USART1, &USART_InitStructure); //将结构体变量交给USART_Init,配置USART1
/*中断输出配置*/
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接收数据的中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择配置NVIC的USART1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
/*USART使能*/
USART_Cmd(USART1, ENABLE); //使能USART1,串口开始运行
}
/**
* 函 数:自己封装的prinf函数
* 参 数:format 格式化字符串
* 参 数:... 可变的参数列表
* 返 回 值:无
*/
void Serial_Printf(char *format, ...)
{
char String[100]; //定义字符数组
va_list arg; //定义可变参数列表数据类型的变量arg
va_start(arg, format); //从format开始,接收参数列表到arg变量
vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中
va_end(arg); //结束变量arg
uint8_t i =0;
//串口发送字符数组(字符串)
for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止
{
USART_SendData(USART1, String[i]); //将字节数据写入数据寄存器,写入后USART自动生成时序波形
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成
/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}
}
/**
* 函 数:获取串口接收的数据
* 参 数:无
* 返 回 值:接收的数据,范围:0~255
*/
uint8_t Serial_GetRxData(void)
{
return Serial_RxData; //返回接收的数据变量
}
void Serial_ClearFlag(void)
{
cnt = 0;
memset(BUF, 0, sizeof(BUF));
}
/**
* 函 数:USART1中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
*/
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断
{
if(cnt >= sizeof(BUF))cnt =0;
BUF[cnt++] = USART_ReceiveData(USART1);
// OLED_ShowNum(2,1,cnt,2);
// OLED_ShowString(3, 1, (char*)BUF);
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除USART1的RXNE标志位
//读取数据寄存器会自动清除此标志位 //如果已经读取了数据寄存器,也可以不执行此代码
}
}
按钮.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB1和PB11引脚初始化为上拉输入
}
/**
* 函 数:按键获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0; //定义变量,默认键码值为0
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 1; //置键码为1
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) //读PB11输入寄存器的状态,如果为0,则代表按键2按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 2; //置键码为2
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
LED.c
#include "stm32f10x.h" // Device header
/**
* 函 数:LED初始化
* 参 数:无
* 返 回 值:无
*/
void LED_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为推挽输出
/*设置GPIO初始化后的默认电平*/
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2); //设置PA1和PA2引脚为高电平
}
/**
* 函 数:LED1开启
* 参 数:无
* 返 回 值:无
*/
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为低电平
}
/**
* 函 数:LED1关闭
* 参 数:无
* 返 回 值:无
*/
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为高电平
}
/**
* 函 数:LED1状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为低电平
}
}
/**
* 函 数:LED2开启
* 参 数:无
* 返 回 值:无
*/
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为低电平
}
/**
* 函 数:LED2关闭
* 参 数:无
* 返 回 值:无
*/
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为高电平
}
/**
* 函 数:LED2状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED2_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为低电平
}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include <string.h>
#include "LED.h"
#include "Key.h"
uint8_t RxData; //定义用于接收串口数据的变量
int main(void)
{
/*模块初始化*/
LED_Init();
Key_Init();
/*串口初始化*/
Serial_Init(); //串口初始化
uint8_t Num =0;
while (1)
{
Num = Key_GetNum();
if(1 ==Num)
{
Serial_Printf("LED1");
LED1_Turn();
}
if(2 ==Num)
{
Serial_Printf("LED2");
LED2_Turn();
}
if (cnt != 0) //检查串口接收数据的标志位
{
if(strstr((const char *)BUF, "LED1") != NULL)
{
LED2_Turn();
Serial_ClearFlag();
}
}
}
}
注意事项
波特率设置为配置蓝牙时的波特率,如果波特率不一样则通信不会成功