HC-05蓝牙模块驱动学习笔记——基于STM32

目录

一.HC-05 介绍

1.1外观介绍

1.2 模块使用说明

1. 进入 AT 状态 有 2 种方法使模块进入 AT 指令状态:

2, 指令结构

3, 常用指令说明及测试

二.硬件设计

1.1模块与单片机连接

三.软件设计

3.1 模块与开发板连接

3.2代码框架及思路

3.3代码实现

总结:


一.HC-05 介绍

1.1外观介绍

        ATK-HC05 模块非常小巧(16mm*32mm),模块通过 6 个 2.54mm 间距的排针与外部连 接,模块外观如图 1所示:

                       图1 HC05 模块外观图

        图中从右到左,依次为模块引出的 PIN1~PIN6 脚,各引脚的详细描述如表 2所示:

                                                图2 HC05 模块各引脚功能描述

        另外,模块自带了一个状态指示灯:STA。该灯有 3 种状态,分别为:

        1,在模块上电的同时(也可以是之前),将 KEY 设置为高电平(接 VCC),此时 STA 慢闪(1 秒亮 1 次),模块进入 AT 状态,且此时波特率固定为 38400。

        2,在模块上电的时候,将 KEY 悬空或接 GND,此时 STA 快闪(1 秒 2 次),表示模块 进入可配对状态。如果此时将 KEY 再拉高,模块也会进入 AT 状态,但是 STA 依旧保 持快闪。

        3,模块配对成功,此时 STA 双闪(一次闪 2 下,2 秒闪一次)

1.2 模块使用说明

        ATK-HC05 蓝牙串口模块所有功能都是通过 AT 指令集控制,这里仅介绍用户常用的 几个 AT 指令,详细的指令集,可以网上搜索资料

1. 进入 AT 状态 有 2 种方法使模块进入 AT 指令状态:

        A.上电同时/上电之前将 KEY 设置为 VCC, 上电后,模块即进入 AT 指令状态。

        B.模块上电后,通过将 KEY 接 VCC,使模块进 入 AT 状态。

        注:方法 1(推荐)进入 AT 状态后,模块的波特率为:38400(8 位数据位,1 位停止 位)。方法 2 进入 AT 状态后,模块波特率和通信波特率一致。

2, 指令结构

        模块的指令结构为:AT+<=PARAM>,其中 CMD(指令)和 PARAM(参 数)都是可选的,不过切记在发送末尾添加回车符(\r\n),否则模块不响应。

比如我要查看模块的版本:

        串口发送:AT+VERSION?\r\n

        模块回应:+VERSION:2.0-20100601

3, 常用指令说明及测试

        1.修改模块主从指令 AT+ROLE=0 或 1,该指令来设置模块为从机或主机,并且可以通过 AT+ROLE?来 查看模块的主从状态,

        2.设置记忆指令 AT+CMODE=1,该指令设置模块可以对任意地址的蓝牙模块进行配对,模块默认 设置为该参数。 AT+CMODE=0,该指令设置模块为指定地址配对,

        注意,如果先设置模块为任意地址, 然后配对,接下去使用该指令,则模块会记忆最后一次配对的地址,下次上电会一直搜 索该地址的模块,直到搜索到为止

        3.修改通信波特率指令 AT+UART=<param1>,<param2><param3>, 该指令用于设置串口波特率、停止位、 校验位等。

Param1 为波特率,可选范围为:4800、9600、19200、38400、57600、115200、 230400、460800、921600、1382400;

Param2 为停止位选择,0 表示 1 位停止位,1 表 示 2 位停止位;

Param3 为校验位选择,0 表示没有校验位(None),1 表示奇校验(Odd), 2 表示偶校验(Even)。

        比如发送:AT+UART=9600,0,0,则是设置通信波特率为 9600,1 位停止位, 没有校验位,这也是模块的默认设置。

        4.修改密码指令 AT+PSWD=<password>,该指令用于设置模块的配对密码,password 必须为 4 个字 节长度。

        5,修改蓝牙模块名字 AT+NAME=<name>,该指令用于设置模块的名字,name 为你要设置的名字,必须 为 ASCII 字符,且最长不能超过 32 个字符。模块默认的名字为 ATK-HC05。比如发送: AT+NAME=GUANG ZHOU,即可设置模块名字为“GUANG ZHOU”。

二.硬件设计

1.1模块与单片机连接

        模块与单片机连接最少只需要 4 根线即可:VCC、GND、TXD、RXD,VCC 和 GND 用于给模块供电,模块 TXD 和 RXD 则连接单片机的 RXD 和 TXD 即可。该模块兼容 5V 和 3.3V 单片机系统。下图是常见的连接方式

                                        图 HC05 模块与单片机系统连接示意图

        图中虚线连接表示可有可无,这个大家根据自己的需要选择性的使用即可。

三.软件设计

3.1 模块与开发板连接

        开发板主控是stm32F407ZET6,需要用到USART3,TIM7,引脚连接对应关系如下:

KEY---------------PF6

LED---------------PC0

RXD---------------PB10

TXD---------------PB11

GND---------------GND

VCC---------------VCC

3.2代码框架及思路

        1.由于HC-05使用串口透传模式,在接收数据时,串口接收是一个字节一个字节的接收,所以在接收数据时需要判断是不是一起发送过来的。实现的方法是开启一个定时器,溢出时间是10ms,如果串口前一个字节的数据和后一个数据时间间隔超过10ms,则认为两个数据是不同批次发送过来的,则在定时器里面标记接收数据完成。

        2.在发送AT指令时,需要判断模块返回的数据是否正确。及判断模块的数据是否带有OK。

3.3代码实现

1.开启定时器

extern vu16 USART3_RX_STA;//用于标记接收完成和计数,该变量在usart3.c中定义

//定时器7中断服务程序		    
void TIM7_IRQHandler(void)
{ 	
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
	{	 			   
		USART3_RX_STA|=1<<15;	//标记接收完成
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    
		TIM_Cmd(TIM7, DISABLE);  //一次完整的数据接收完成,关闭TIM7 ,等下一次接收到数据在开启
	}	    
}

void TIM7_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
   
	TIM_Cmd(TIM7,ENABLE);//使能定时器7
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

2.串口配置

#define USART3_MAX_RECV_LEN 200
#define USART3_MAX_SEND_LEN 200

u8 USART3_RX_BUF[USART3_MAX_RECV_LEN];//接收缓冲区
u8 USART3_TX_BUF[USART3_MAX_SEND_LEN];//发送缓冲区

void USART3_init(u32 bound)
{  
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
 
	USART_DeInit(USART3);  //复位串口3
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟
	
 
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10; //GPIOB11和GPIOB10初始化
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
	GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB11,和GPIOB10
	
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3); //GPIOB11复用为USART3
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3); //GPIOB10复用为USART3	  
	
	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	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(USART3, &USART_InitStructure); //初始化串口3
	
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断  
		
	USART_Cmd(USART3, ENABLE);                    //使能串口 
	
 
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	TIM7_Int_Init(100-1,8400-1);	//10ms中断一次
	
  TIM_Cmd(TIM7, DISABLE); //关闭定时器7
	
	USART3_RX_STA=0;				//清零 
}

//串口3发送一个字节
void USART3_SendByte(u8 Byte)
{
	USART_SendData(USART1, (u8)Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

//重定义printf
int fputc(int ch,FILE *f)/*重定向*/
{
	USART3_SendByte(ch);
	return ch;
}

//接收数据中断函数
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
u16 USART3_RX_STA=0;

void USART3_IRQHandler(void)
{
	u8 res;	    
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
	{	 
 
	res =USART_ReceiveData(USART3);		
	if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
	{ 
		if(USART3_RX_STA<USART3_MAX_RECV_LEN)		//还可以接收数据
		{
			TIM_SetCounter(TIM7,0);//计数器清空        				 
			if(USART3_RX_STA==0)		
				TIM_Cmd(TIM7, ENABLE);  //使能定时器7 
			USART3_RX_BUF[USART3_RX_STA++]=res;		//记录接收到的值	 
		}else 
		{
			USART3_RX_STA|=1<<15;					//强制标记接收完成
		} 
	}  	
 }										 
}  

3. HC-05 配置

#define HC05_KEY  	PFout(6) 	//蓝牙控制KEY信号
#define HC05_LED  	PCin(0)		//蓝牙连接状态信号
//初始化ATK-HC05模块
//返回值:0,成功;1,失败.
u8 HC05_Init(void)
{
	u8 retry=10,t;	  		 
	u8 temp=1;
	
	GPIO_InitTypeDef GPIO_InitStructure;
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC,GPIOF时钟
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //LED对应引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC0
 
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//KEY对应引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOF, &GPIO_InitStructure); //根据设定参数初始化PF6

	GPIO_SetBits(GPIOF,GPIO_Pin_6);
 	
	USART3_init(9600);	//初始化串口3为:9600,波特率.
	
	while(retry--)//尝试初始化次数
	{
		HC05_KEY=1;					//KEY置高,进入AT模式
		delay_ms(10);
		printf("AT\r\n");		//发送AT测试指令
		HC05_KEY=0;					//KEY拉低,退出AT模式
		for(t=0;t<10;t++) 			//最长等待50ms,来接收HC05模块的回应
		{
			if(USART3_RX_STA&0X8000)break;
			delay_ms(5);
		}		
		if(USART3_RX_STA&0X8000)	//接收到一次数据了
		{
			temp=USART3_RX_STA&0X7FFF;	//得到数据长度
			USART3_RX_STA=0;	//清除接收完成标记,以及接收数据长度		 
			if(temp==4&&USART3_RX_BUF[0]=='O'&&USART3_RX_BUF[1]=='K')
			{
				temp=0;//接收到OK响应
				break;
			}
		}			    		
	}		    
	if(retry==0)temp=1;	//检测失败
	return temp;	 
}	 
//获取HC05模块的角色
//返回值:0,从机;1,主机;0XFF,获取失败.							  
u8 HC05_Get_Role(void)
{	 		    
	u8 retry=0X0F;
	u8 temp,t;
	while(retry--)
	{
		HC05_KEY=1;					//KEY置高,进入AT模式
		delay_ms(10);				//需要等待模块进入AT模式
		printf("AT+ROLE?\r\n");	//查询角色
		for(t=0;t<20;t++) 			//最长等待200ms,来接收HC05模块的回应
		{
			delay_ms(10);
			if(USART3_RX_STA&0X8000)break;
		}		
		HC05_KEY=0;					//KEY拉低,退出AT模式
		if(USART3_RX_STA&0X8000)	//接收到一次数据了
		{
			temp=USART3_RX_STA&0X7FFF;	//得到数据长度
			USART3_RX_STA=0;			 
			if(temp==13&&USART3_RX_BUF[0]=='+')//接收到正确的应答了
			{
				temp=USART3_RX_BUF[6]-'0';//得到主从模式值
				break;
			}
		}		
	}
	if(retry==0)temp=0XFF;//查询失败.
	return temp;
} 
//HC05发送命令函数
//此函数用于设置HC05,适用于仅返回OK应答的AT指令
//atstr:AT指令串.比如:"AT+RESET"/"AT+UART=9600,0,0"/"AT+ROLE=0"等字符串
//返回值:0,设置成功;其他,设置失败.							  
u8 HC05_Send_Cmd(u8* atstr)
{	 		    
	u8 retry=0X0F;
	u8 temp,t;
	while(retry--)
	{
		HC05_KEY=1;					//KEY置高,进入AT模式
		delay_ms(10);				//需要等待模块进入AT模式
		printf("%s\r\n",atstr);	     //发送AT字符串
		HC05_KEY=0;					//KEY拉低,退出AT模式
		for(t=0;t<20;t++) 			//最长等待100ms,来接收HC05模块的回应
		{
			if(USART3_RX_STA&0X8000)break;
			delay_ms(5);
		}		
		if(USART3_RX_STA&0X8000)	//接收到一次数据了
		{
			temp=USART3_RX_STA&0X7FFF;	//得到数据长度
			USART3_RX_STA=0;			 
			if(temp==4&&USART3_RX_BUF[0]=='O')//接收到正确的应答了
			{			
				temp=0;
				break;			 
			}
		}		
	}
	if(retry==0)temp=0XFF;//设置失败.
	return temp;
}

4.主函数

int main(void)
{
    while(HC05_Init()); 		//初始化HC05模块 ,返回0才是初始化完成。
	HC05_Set_Cmd("AT+ROLE=0");   //设置为从模式
    while(1)
    {
         printf("ALIENTEK HC05 \r\n");//发送数据到蓝牙模块
         if(USART3_RX_STA&0X8000)			//接收到一次数据了
		{
 			reclen=USART3_RX_STA&0X7FFF;	//得到数据长度
		  	USART3_RX_BUF[reclen]=0;	 	//加入结束符
			//处理接收到的数据
             //。。。。。。
         }

	}		
    
}

总结:

        本文用于学习笔记,且参考了正点原子的stm32开发指南。

  • 2
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
HC05模块是一款高性能主从一体蓝牙串口模块,可以实现蓝牙转串口的功能。它采用英国CSR公司BlueCore4系列的芯片,符合蓝牙2.0+EDR规范,可以与带有蓝牙功能的电脑、蓝牙主机和手机等智能终端配对。\[2\]在STM32单片机中使用HC05模块,可以通过手机蓝牙控制STM32单片机,发送消息给STM32单片机,然后STM32单片机可以原封不动地返回消息给手机,或者根据手机发送的消息做出相应的动作,比如点亮LED、发动电机、显示波形等等。\[1\]在使用HC05模块时,需要注意在发送末尾添加回车符(\r\n),并且可以使用一些常用指令来配置HC05模块的参数,比如重启模块、获取软件版本号、设置设备名称、查询设备名称、设置模块角色、查询模块角色、设置配对码、查询配对码、设置串口参数码等等。\[3\]至于HC05STM32上的驱动,你可以使用STM32的串口编程来实现与HC05模块的通信和控制。 #### 引用[.reference_title] - *1* [STM32驱动HC05蓝牙串口通信模块](https://blog.csdn.net/WandZ123/article/details/125982006)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [STM32控制HC-05蓝牙模块进行通信](https://blog.csdn.net/Zach_z/article/details/72784369)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值