基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)

最近在学习STM32开发板,在使用HC-05蓝牙模块时遇到了很多问题,没有驱动,串口通讯异常等等,在此期间借鉴了大量CSDN博主的文章,作为回报,我将最终可以正常运行的程序,配置方法以及可能出现的问题分享给大家。大家有问题也可以留言,尽量回复!


本文分为三个模块:

  1. Arduino与HC-05连接(与手机进行蓝牙通讯)
  2. STM32与HC-05连接(与手机进行蓝牙通讯)
  3. STM32与Arduino透过HC-05通讯

已更新

目录

1.Arduino与HC-05连接(与手机进行蓝牙通讯)

2.STM32与HC-05连接(与手机进行蓝牙通讯)

3.STM32与Arduino透过HC-05通讯



*为了能够阅读之后的模块,需要你先阅读下面文字:

研究HC-05可以不用太在意HC-05具体硬件体系和软件构成,但需要至少知道以下几点:

  • HC-05有两个工作模式,正常模式(用于蓝牙通讯)和AT模式(用于配置蓝牙模块参数),二者之间不能通过软件方法切换(不是不能实现而是实现需要通过断电上电实现),正常上电会进入正常模式,但若在上电前保持PIO11为高则会进入AT模式(一般HC-05上会有一个按钮,按住按钮上电相当于上电前保持PIO11为高,能进入AT模式);
  • AT模式相当于HC-05模块成为一个终端,可以与开发板进行串口通信,所有AT指令从开发板发向HC-05,HC-05反馈操作结果给开发板,AT指令可以设置蓝牙模块名称,配对密码,通讯频率等;
  • 正常模式HC-05相当于一根串口通信线缆,将与之配对的设备和开发板的通信串口相连接。

1.Arduino与HC-05连接(与手机进行蓝牙通讯)

此模块目的是将Arduino作为一个收发中继,将HC-05发来的信息原封不动的发给电脑,并将电脑发来的信息原封不动的发给Arduino,主要有两个步骤:

第一步:配置Arduino模块

将以下程序烧录进Arduino,解释可以先不看;

#include   
// 设置Arduino软件串口,10-RX,11-TX     
// Pin10为RX,接HC05的TXD 
// Pin11为TX,接HC05的RXD 
SoftwareSerial BT(10, 11);  
char val;  
void setup() {   
   Serial.begin(38400); 
   //初始化Arduino串口,波特率自定,这里选38400   
   Serial.println("BT is ready!");   
   //测试与PC之间串口是否正常,正常则显示上述文字,异常则显示乱码  
   BT.begin(38400);
   // HC-05的AT模式默认通信波特率为38400    
   pinMode(13,OUTPUT);   
   pinMode(8,INPUT);
   //用来使能HC-05并读取HC-05状态,这里没用到
}  
void loop() {   
   if (Serial.available()) {     
     val = Serial.read();     
     BT.print(val);
     //将PC发来的数据存在val内,并发送给HC-05模块   
   }   
  if (BT.available()) {     
     val = BT.read();     
     Serial.print(val); 
     //将HC-05模块发来的数据存在val内,并发送给PC   
   }   
}

连接HC-05和Arduino开发板:

接线表
HC-05 Arduino
TXD Pin10
RXD Pin11
VCC VCC
GND GND
可选(这里没有用到)
STATE Pin8
EN-M Pin13

接完线,烧好程序,将Arduino断电,按住HC-05模块上的按钮或者将PIO11接在VCC上,将Arduino与PC连接,发现HC-05模块指示灯2秒周期慢闪,即进入AT模式。

打开PC机上的串口助手,设置波特率为38400,结束符选择Both NL & CR,若显示“BT is ready”则证明串口通信可用,若无显示则按下Arduino上的Reset键,否则请检查线路和程序。

串口通信成功后,通过串口助手发送“AT”,如果一切正常将收到“OK”。若无反馈,请检查HC-05指示灯情况,并重新连接,若仍然无反馈,则可能因为串口助手不支持自动结束符,需要输入“AT\r\n”或在结尾按下回车,并在接下来所有AT指令后都加上“\r\n”或按下回车。若反馈为“ERROR:(0)”,那就再发一次,并检查输入的是否是"AT",其前后是否有包括回车符在内的其他符号。

常用的AT指令有

  • AT+NAME(咨询修改蓝牙名称),若发送“AT+NAME”,则会反馈蓝牙名称(部分品牌不会反馈),大多数默认叫做HC-05,如果想更改名称,则需要发送“AT+NAME=XXX”(XXX代表你想要的名称);
  • AT+ROLE(咨询修改主从状态),若发送“AT+ROLE”,则会反馈蓝牙模块的主从状态,若返回为“+ROLE:1”则为主机,若返回为“+ROLE:0”则为从机,可以使用“AT+ROLE=1”修改蓝牙模块为主机状态,亦可以使用“AT+ROLE=0”修改蓝牙模块为从机状态;
  • AT+CMODE(咨询修改连接模式),若发送“AT+CMODE”,则会反馈蓝牙模块的连接模式,若返回为“+CMODE:1”则不进行地址绑定,若返回为“+CMODE:0”则需要地址绑定,修改类似AT+ROLE,格式为“AT+CMODE=1/0”;
  • AT+PSWD(咨询修改配对密码),若发送“AT+PSWD”,则会反馈蓝牙模块的配对密码,一般默认是1234,修改方法同AT+NAME,格式为“AT+PSWD=XXXX”(XXXX为新密码);
  • AT+ADDR(咨询蓝牙模块地址),若发送“AT+ADDR”,则会反馈蓝牙模块的地址,一般是三段用冒号分开的字符串;
  • AT+BIND(修改绑定连接地址),CMODE为0时可以使用该指令修改绑定的连接地址,即发送“AT+BIND=XX,XX,XX”,注意这里需要将地址中的冒号改为逗号;
  • AT+ORGL(复位蓝牙设置),发送“AT+ORGL”即可情况之前的设置;
  • AT+RMAAD(清空配对列表),发送“AT+RMAAD”即可情况沛对列表。
基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第1张图片 使用Arduino自带串口助手进行AT模式配置(设置为主机)

根据自己的需要按照上面的AT指令修改蓝牙模块参数,一般需要修改的是蓝牙名称,配对密码,一般HC-05出厂默认为从模式、指定地址连接,所以一般不需要修改其他参数。

 

第二步:与手机的通信实验

在手机上下载一个蓝牙串口助手,各大应用商店都有,自行选择。

设置好蓝牙模块,断开串口助手,将Arduino断电,重新上电与PC连接,HC-05进入正常模式(指示灯快速连闪),打开PC上的串口助手。

打开手机上的蓝牙寻找你命名的蓝牙模块(有时候刷新不出来,只显示了MAC地址,可以试着连一下,输入配对密码后,如果是你要测试的就会显示名称并且连接成功),连接配对,配对成功后HC-05上的指示灯将进入2s周期的快速双闪。

若成功则可以打开手机上的蓝牙串口助手选择蓝牙模块,试着发送一些简单数据,观察PC上的串口助手是否能够收到数据,若不能检查HC-05状态,连线以及PC串口助手的设置。

可能出现的问题&解决方法

至此,HC-05的简单应用就完成了,Arduino封装了串口通信驱动,一般情况下不会出现问题,蓝牙模块(HC-05和手机的蓝牙)之间通信一般都会自动协商波特率,基本上也不会出现什么问题。若存在问题,则很有可能是1.AT模式配置错误或根本就没有进入AT模式,请详细阅读上面的说明,检查连线;2.串口助手设置错误,串口助手实际上非常简单,就是调用了WriteFile和ReadFile这个有时间我也会发一个解析,但问题就出在这里,有些串口助手没有设置自动添加结束符,有些串口助手获取输入是允许存在回车符的,所以需要自行检验串口助手的发送特征,并按照上述的格式进行发送。

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第2张图片

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第3张图片  

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第4张图片

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第5张图片

 

                                                       手机发送->电脑接收->电脑发送->手机接收



2.STM32与HC-05连接(与手机进行蓝牙通讯)

这里实现的功能与上一模块相同,使用STM32作为中继,将PC发来的数据发给HC-05,将HC-05接收到的数据发给PC。与Arduino不同,STM32需要自行编写串口驱动,当然也可视HC-05的相关函数为驱动,其关键在与如何编写双串口通讯的驱动。所以这里分为三个步骤,第一步,编写STM32驱动程序(这里使用了一块LCD显示收发信息,亦可不要);第二步,调试配置HC-05模块;第三步,通讯测试。

第一步:编写STM32驱动程序

为了实现中继功能需要编写两个串口驱动,串口1用于与PC通讯,串口2用于与HC-05通讯。驱动的方案有很多种,可以是双中断,也可以是非中断接收方法,输出可以是重构printf函数+额外定义u2_printf函数,或者使用带全局变量的printf函数。这里用的发送方法是重写printf函数,加入一个全局变量以控制向不同串口发送数据;接收方面二者都为中断接收,buffer区20个字节自动覆盖,主程序500ms超时,做的并不是很完善,但足够使用,大家可以根据需要自行修改。

这里使用的是一块STM32F103ZE的开发板,键盘、LED等其他驱动程序均使用样例所用的驱动。主要修改/添加的文件是usart和stm32f10x_it,其代码如下:

usart.h(提供两个初始化函数)

#ifndef __USART_H
#define __USART_H

#include "stm32f10x.h"

void USART1_Int(u16 baud);
//初始化串口1,波特率=baud
void USART2_Int(u16 baud);
//初始化串口2,波特率=baud
#endif 

usart.c(内含初始化函数,重写printf函数,发送串口选择全局变量)

#include 
#include "stm32f10x.h"
#include "usart.h"

//#include "led.h"
//调试时使用


//重写printf
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

//全局变量,用来控制发送的串口
int USART_PRINTF_FLAG = 2;

//初始化串口1
void USART1_Int(u16 baud)
{

    GPIO_InitTypeDef GPIO_InitStructure;
	  USART_InitTypeDef USART_InitStructure;
	  NVIC_InitTypeDef NVIC_InitStructure;
	 
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//
 	  USART_DeInit(USART1); 
	//USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
   
    //USART1_RX	  PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);  

    //Usart1 NVIC设置

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
	  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//中断等级3.3
	  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//激活中断
	  NVIC_Init(&NVIC_InitStructure);	
 
  /* USARTx configured as follow:
        - BaudRate = baud  
        - Word Length = 8 Bits  
        - One Stop Bit          
        - No parity             
        - Hardware flow control disabled (RTS and CTS signals) 
        - Receive and transmit enabled                         
  */
  USART_InitStructure.USART_BaudRate = baud;
  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(USART1, &USART_InitStructure);
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  USART_Cmd(USART1, ENABLE);                   
}

//初始化串口2
void USART2_Int(u16 baud)
{

   GPIO_InitTypeDef GPIO_InitStructure;
   USART_InitTypeDef USART_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;
	 
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); 
   USART_DeInit(USART2);  //¸´Î»´®¿Ú2
	//USART2_TX   PA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	
    GPIO_Init(GPIOA, &GPIO_InitStructure); 
   
    //USART2_RX	  PA.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);      
	
	  //Usart1 NVIC ÅäÖÃ

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;
	  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//中断等级2.2
	  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//激活中断
	  NVIC_Init(&NVIC_InitStructure);	
  /* USARTx configured as follow:
        - BaudRate =  baud  
        - Word Length = 8 Bits  
        - One Stop Bit          
        - No parity             
        - Hardware flow control disabled (RTS and CTS signals) 
        - Receive and transmit enabled                         
  */
  USART_InitStructure.USART_BaudRate = baud;
  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(USART2, &USART_InitStructure);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  USART_Cmd(USART2, ENABLE);                    
}


//重写printf函数
PUTCHAR_PROTOTYPE
{
 /* Place your implementation of fputc here */
 /* e.g. write a character to the USART */
    //USART_SendData(USART1, (uint8_t) ch);
    //串口2发送直至标志复位
    if (USART_PRINTF_FLAG == 2)
    {
        while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
			  //LED3_OFF;
			  //LED2_OFF;
              //测试用
        USART_SendData(USART2,(uint8_t)ch);
    }
    //串口1发送直至标志复位
    else if (USART_PRINTF_FLAG == 1)
    {
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
			  //LED3_ON;
			  //LED2_ON;
              //测试用
        USART_SendData(USART1,(uint8_t)ch);
    }
		else
		{
			//LED2_OFF;
			//LED3_ON;
            //测试用
		}
  return ch;
}

stm32f10x_it.c

//...
//放在变量定义区
uint8_t buffer1[20];
uint8_t buffer2[20];
int reccount1=0;
int reccount2=0;
//...

//...
//结束符之前插入

//串口1接收中断
void USART1_IRQHandler(void)  
  
{  
     if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)  
      {       
        buffer1[reccount1]=USART_ReceiveData(USART1);
				reccount1++;
				if(reccount1>=20)reccount1=0;            
      }
      //buffer1最大20字节,无超时,溢出则覆盖
      
}

//串口2接收中断
void USART2_IRQHandler(void)  
  
{  
     if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET)  
      {       
        buffer2[reccount2]=USART_ReceiveData(USART2);
				reccount2++;
				if(reccount2>=20)reccount2=0;          
      }
      //buffer2最大20字节,无超时,溢出则覆盖
      
}

//...

主程序中使用了一块LCD屏幕,并调用了两个按键,若不想使用可以按照注释修改。

main.c

#include 
#include "stm32f10x.h"//改成对应芯片驱动的头文件
#include "led.h"
#include "delay.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "usart.h"
#include "adc.h"
#include "lcd.h"


extern __IO uint16_t ADC_ConvertedValue;

//获取串口接收buffer和计数

extern uint8_t buffer1[20];
extern uint8_t buffer2[20];
extern int reccount1;
extern int reccount2;

//
extern int USART_PRINTF_FLAG;

		 
float ADC_ConvertedValueLocal;     

int main(void)
{
	int j;
	LED_Init();
    KEY_Init();
    SysTick_Init();
	BEEP_Init();  
    USART1_Int(9600);  //可以修改,关系到PC上串口助手的波特率
	USART2_Int(38400); //建议不修改
	LCD_Init();
    //主循环			 	
    while(1) 
	{
        //LCD显示+键盘控制方案
		POINT_COLOR=RED;	  
		LCD_ShowString(30,50,200,16,16,"buffer1=");
		LCD_ShowString(30,70,200,16,16,buffer1);//显示目前buffer1内容	
		LCD_ShowString(30,90,200,16,16,"buffer2=");
 		LCD_ShowString(30,110,200,16,16,buffer2);//显示目前buffer2内容		      					 	   
        LCD_ShowString(30,150,200,16,16,"S1= BUFFER1 TO USART2");
        //按键1功能:将buffer1内容发给串口2
		LCD_ShowString(30,170,200,16,16,"S2= CLEAR BUFFERS");	
        //按键2功能:清除两个buffer
        if(!S1)
		{
			Delay_ms(10);
			if(!S1)	
				
			{
				 while(!S1);
				 USART_PRINTF_FLAG=2;
		         printf(buffer1);	
			}
		}	
        if(!S2)
		{
			Delay_ms(10);
			if(!S2)	
				
			{
				 while(!S2);
				for(j=0;j<20;j++)
				{
			         buffer1[j]=' ';
					 buffer2[j]=' ';
				}
				
			}
		}		
        //中继(无操作方案)
        /*
        USART_PRINTF_FLAG=2;
		printf(buffer1);
        Delay_ms(500);
        USART_PRINTF_FLAG=1;
		printf(buffer2);
        */			 
		Delay_ms(500);
        reccount1=0;
	    reccount2=0;//接收超时		
	} 
}

第二步:配置调试HC-05模块

将STM32与计算机通过USB连接,将HC-05的接口与STM32开发板的usart2接口连接,与Arduino开发板相同,RXD-TXD,TXD-RXD,VCC-VCC,GND-GND。烧录好程序,断开连接,按住HC-05上的按钮上电。观察到2s周期慢闪,打开PC上的串口助手。

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第6张图片 PC串口助手

设置波特率为9600(或者修改的波特率),发送AT 回车(注意这个串口助手的输入栏是接收回车的,需要手动加回车符),LCD方案可以在STM32的LCD上看到buffer1为AT,按下S1,可以看到反馈为OK,即可开始配置HC-05模块,配置用AT指令等与Arduino相同。

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第7张图片 接收情况

第三步:通讯测试

完成配置,关闭PC上的串口助手,断电,再次上电,观察到HC-05上的LED快闪,打开PC串口助手,手机上的蓝牙串口助手。连接到该HC-05模块,观察到HC-05上的LED以2s周期双闪,即可开始发送数据。

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第8张图片 PC发送

 

基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第9张图片 手机串口接收与发送
基于STM32的HC-05蓝牙模块使用及常见问题(STM32-手机-Arduino使用HC-05进行蓝牙通讯)_第10张图片 STM32接收与发送

 

3.STM32与Arduino透过HC-05通讯

你可能感兴趣的:(STM32模块)