前言:

        在我没接触蓝牙之前,我觉得蓝牙模块应用起来应该挺麻烦,后来发觉这个蓝牙模块的应用本质无非就是一个串口

蓝牙模块:

 

        这是我从某宝上买到的蓝牙模块HC-08,价格还算可以,而且可以适用于大多数蓝牙调试软件。回到刚开始说的话,蓝牙模块的应用和单片机的串口几乎是一样的,我们可以用USB转TTL模块与HC-08模块进行通信,虽说HC-08有6个引脚,但是我们只用4个,连接方式如下对应

USB转TTL HC-08
3V3 VCC
TXD RXD
RXD TXD
GND GND

连接之后,蓝牙模块蓝色灯闪烁(没和手机连接)。串口助手选择波特率为9600,我们可以直接用串口助手发送AT指令,当蓝牙模块回馈OK的时候,说明我们的蓝牙模块没有问题。

        接下来给大家罗列一下常用的AT指令

指令 响应 说明
AT OK 检验串口是否正常工作
AT+RX Name:HC-08 >>(蓝牙名称)
Role:Slave >>>>(模块角色 主 M / 从 S)
Baud:9600,NONE (串口波特率, 校验位)
Addr:48,70,1E,24,16,27>>(蓝牙地址)
PIN :000000>>>>[ 蓝牙密码 (密码无效) ]
查询模块的基本参数
AT+DEFAULT OK 恢复出厂设置,不会清除主机已记录的从机地址!若要清除请在 未连线状态下使用 AT+CLEAR 指令进行清除。模块会自动重启,重启 200ms 后可进行新的操作
AT+RESET OK 重启模块,模块会自动重启,重启 200ms 后 可进行新的操作
AT+VERSION HC-08 V3.3,2020-10-16 获取软件版本和发布日期
AT+ROLE=x Master/Slave 设置主机/从机;默认从机,设置后模块将自动重启, 重启 200ms 后可进行新的操作

  STM32驱动HC-08例程:

        下面是我的部分代码,包括了初始化部分,和中断部分,看完这部分代码,我们就更能理解为啥我说蓝牙模块的应用和串口几乎一致。因为我的蓝牙模块连接的刚好是USART2,所以代码部分如下

void USART2_Init(unsigned int Baudrate)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//TX
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//RX
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	USART_InitStructure.USART_BaudRate = Baudrate;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //关闭硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	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(USART2, &USART_InitStructure);
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);	//允许接收中断
  USART_Cmd(USART2, ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//??1????
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//?????3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//????3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ????
	NVIC_Init(&NVIC_InitStructure);	//??????????VIC????
	
}


        中断服务函数编写

void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE) == 1)							//USART_FLAG_RXNE判断数据,== 1则有数据
	{
		if(Receive_sum > 49)													//数组能存放50个字节的数据				
		{
			USART_ReceiveString[49] = '\0';										//数据字节超过50位时,将最后一位设置为\0	
			Receive_Flag = 1;													//接收标志位置1,停止接收数据
			Receive_sum = 0;													//数组下标置0
		}
		
		if(Receive_Flag == 0)													//接收标志位等于0,开始接收数据
		{
			USART_ReceiveString[Receive_sum] = USART_ReceiveData(USART2);		//通过USART2串口接收字符
			Receive_sum++;														//数组下标++
			if(USART_ReceiveString[Receive_sum-1] == '%')
			{
				Receive_Flag = 1;
				Receive_sum = 0;
				printf("%s\r\n",USART_ReceiveString);					
				if(strcmp(USART_ReceiveString,"channel:1%") == 0)
				{
					FSM_led = LED_state1;
					FSM_hc08 = Channel_1;
					Receive_Flag = 0;
				}
				else if(strcmp(USART_ReceiveString,"channel:2%") == 0)
				{
					FSM_led = LED_state2;
					FSM_hc08 = Channel_2;
					Receive_Flag = 0;
				}
			}
		}
		
		
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);							//接收后先清空标志位
	}
}