您的位置:首页 > 产品设计 > UI/UE

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

2018-11-12 20:16 886 查看

最近在学习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,解释可以先不看;

[code]#include <SoftwareSerial.h>
// 设置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”即可情况沛对列表。
使用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这个有时间我也会发一个解析,但问题就出在这里,有些串口助手没有设置自动添加结束符,有些串口助手获取输入是允许存在回车符的,所以需要自行检验串口助手的发送特征,并按照上述的格式进行发送。

  

 

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

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(提供两个初始化函数)

[code]#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函数,发送串口选择全局变量)

[code]#include <stdio.h>
#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

[code]//...
//放在变量定义区
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

[code]#include <stdio.h>
#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上的串口助手。

PC串口助手

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

接收情况

第三步:通讯测试

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

PC发送

 

手机串口接收与发送 STM32接收与发送

 

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: