Arduino实现两个HC-05蓝牙模块控制蓝牙小车

特此声明,本文所有内容是在参考以下链接的基础上整理并开发的,所有代码均验证无误。如果你想使用或者发表,请您声明出处。

一,实验目的。

本文使用两个Arduino UNO板子,两个HC-05,分别作为主站和从站,实现主站按钮控制从站小车运动。

二,蓝牙HC-05的主从站初始AT配置方法:

1,蓝牙模块介绍:

常见的蓝牙模块按型号可分为HC-05和HC-06两种,HC-05既可以作为主站使用,又可以作为从站使用。而HC-06只能作为从站使用。

主机:用来搜索从设备,不能被其他设备搜索。(有白点或者对勾标记的那个

从机:用来被搜索的设备,不能主动搜索其他设备。主从连上以后就相当于一根串口线使用,这个时候就不分主从,也就是透传模式。

这俩长相都差不多,仔细看会发现HC-05模块有一个对勾或者白点,如下图所示:

然后HC-05主从一体的蓝牙模块又分为两种,一种是有KEY脚的,一种是有EN脚的。这俩的使用区别是:

在AT模式设定的时候,有KEY的需要,在上电前将KEY脚与3.3V脚连接,INT脚不接;

有EN的需要,在上电前按住按钮不放,再上电,且除了VCC,GND,RX,TX之外的引脚都不接。

在本实验中我计划使用一个有KEY脚的HC-05作为主站(下文简称为主站),另一个有EN脚的作为从站(下文简称为从站)。

2.主站AT模式配置

首先是硬件链接,请看下图所示的示意图:

无论你用带KEY脚的作为主站还是用EN脚的作为主站,在AT配置中都没关系,电路连接方式可以参考我画的。

值得说明的是1. 尽管Arduino引脚的电压接近3.3伏,但还是出于安全考虑,我们将Arduino的11引脚(Arduino的发送端)接上2K的保护电阻,在无信号传输的时候端口是低电平状态。(实际上你不接这个保护电阻也没啥,我的就没烧,哈哈,说话还是要负责任,建议大家还是接上好)。

2. 网上有人说可以直接将HC-05的RX接Arduino的TX,将HC-05的TX接Arduino的RX,这样说确实没错,但是当你的电脑与Arduino下载或者使用串口监视器的时候,那样做就不合适,因为Arduino的TX端口被电脑和蓝牙同时占用,互相之间有扰动,尤其是波特率设置不同的时候。所以,本实验将蓝牙的TXD/RXD脚接在新的Arduino脚,避免冲突。

在硬件如上图接好后,将Arduino与电脑连接,打开Arduino IDE, 匹配好COM口。

看到蓝牙上的指示灯2秒一闪就说明进入了AT模式

将以下代码下载到Arduino中:

//HC-05分为有EN和有key两种:
//有EN的需要,在上电前按住按钮不放,再上电,且除了VCC,GND,RX,TX之外的引脚都不接
//有KEY的需要,在上电前将KEY脚与3.3V脚连接,INT脚不接
#include <SoftwareSerial.h>
//使用软件串口,能讲数字口模拟成串口
SoftwareSerial BT(10, 11);  
// Pin10为RX,接HC05的TXD
// Pin11为TX,接HC05的RXD
char val;  //存储接收的变量

void setup() {
  Serial.begin(9600);   //与电脑的串口连接,串口监视器波特率设置为9600
  Serial.println("BT is ready!");
  BT.begin(38400);  //设置蓝牙波特率为默认值
}

void loop() {
  //如果串口接收到数据,就输出到蓝牙串口
  if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
  }

  //如果接收到蓝牙模块的数据,输出到屏幕
  if (BT.available()) {
    val = BT.read();
    Serial.print(val);
  }
}
//当发现串口监视器显示BT is ready!后,输入AT点击键盘回车一次,当看到OK的时候就说明可以进行AT模式设置了。

网上有的人说,到这步有点看不见OK,常见的问题有两个,一个是RXD/TXD接反了,两一个是波特率设置错误,要知道蓝牙模块的默认波特率是38400,电脑与Arduino匹配的常用波特率为9600.别搞混。

然后打开串口监视器,你就看见如下图所示的内容:

现在我们需要在串口监视器中输入以下内容进行主站AT配置:(每次指令必须手动按键盘回车一次)

输入顺序从上到下:

AT      进入AT模式设置

AT+ORGL     恢复出厂设置
AT+NAME=HX01    设置蓝牙的名字为 'HX01'(你改成别的也行)
AT+ROLE=1    #  作为主站使用
AT+CMODE=1    #   设置该蓝牙为允许任意设备检测模式(=0是仅允许当前设备接入,多设备控制就=1,单设备就=0)
AT+PSWD=1234    # 设置密码为 1234

主站就配置完成了,暂时先将它搁置一边。当看到都OK的时候就可以断电了。

3. 从站AT模式配置

现在我们那另一个Arduino UNO板子连接一个有EN脚的HC-05模块,用他们作为从站。有EN的需要,在上电前按住按钮不放,再上电,且除了VCC,GND,RX,TX之外的引脚都不接。Pin10作为Arduino的RX端,接HC05的TXD。Pin11为TX,接HC05的RXD。(出于安全考虑HC-05的接收端RX还是像上图电路连接图那样串接一个保护电阻

 

看到蓝牙上的指示灯2秒一闪就说明进入了AT模式

软件代码还是上文那个代码,原封不动的将它下载到从站Arduino中。打开串口监视器,看到BT is ready! 后输入AT回车,看到如下图所示:

然后输入以下指令对从站进行AT配置:(输入顺序从上到下)

AT+ORGL     恢复出厂设置(有EN脚的进行配置时当输入恢复出厂设置时,它会恢复快闪,需要重新断电上电才能进行下一步)
AT+NAME=HX01    设置蓝牙名字为 'HX01'(主从站名字必须一致)
AT+ROLE=0    作为从站使用
AT+CMODE=1    设置为任何设备可检测到
AT+PSWD=1234    设置匹配密码为 1234(主从站密码必须一致)

从站就配置完成了,暂时先将它搁置一边。当看到都OK的时候就可以断电了。

我想会有人质疑为啥不输入AT+ADDR?获得地址,别急呀,放到下文再说,怕新手学不懂。

另外我不是卖东西的,就夸一句,德飞莱牌的LY-BL001,HC-05蓝牙模块太好使了,比ZS-040稳定多了。淘宝上买二还送一个转TTL模块。啧啧

4. 主站从站配置连接

我们继续,在从站的AT模式下,串口监视器输入指令“AT+ADDR?”点击回车,查询从站的地址为下图所示

我们需要记住它。

如果你用蓝牙APP扫描它,实际上它的地址是这样表示的(20:19:06:27:11:30)

下文是我直接粘贴的台湾人的介绍,他的连接在本文末尾处贴上,有兴趣的同学可以去看一下

然后我们用同样的方法获得主站的地址:2019:6:271123

主站的AT模式下的串口监视器中输入指令:AT+BIND=2019,6,271130主站绑上从站

从站的AT模式下的串口监视器中输入指令:AT+BIND=2019,6,271123从站绑上主站

等双方窗口都设置完成,就完成了最终的AT配置。以上设置会永久保存在蓝牙芯片中,直到下次恢复出厂设置,重新写入。

三,蓝牙一对一传输测试

现在我们测试一下,无线传输。我们让主站窗口手打发送0和1给从站,然后让从站检测到0和1信号后,控制LED灯亮灭。

在这之前要把有KEY引脚的那个蓝牙模块的KEY引脚悬空(啥也不接)

给主站输入如下代码:

//这是蓝牙主站代码 
#include <SoftwareSerial.h>   // 引用函数库
 
SoftwareSerial BT(10, 11); // 接收,传送
char val;  // 储存串口发送值
 
void setup() {
  Serial.begin(9600);   // 与电脑连接的波特率
  Serial.println("BT is ready!");
 
  // 蓝牙模式设置的波特率
  BT.begin(38400);
}
 
void loop() {
  // 若读到串口监视器的值,则给蓝牙
  if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
  }
 
  // 若收到蓝牙值,则给串口监视器
  if (BT.available()) {
    val = BT.read();
    Serial.print(val);
  }
}

给从站Arduino下载如下代码:

//这是从站代码,LED灯正极串联一个1K电阻,负极接Arduino的P13脚
#include <SoftwareSerial.h>   // 引用BT函数库
 
SoftwareSerial BT(10, 11); // 接收脚,传送脚
char val;  // 存储接收的值
const byte LED_PIN = 13;  // 定义LED引脚
 
void setup() {
  // 设定蓝牙模块初始波特率
  BT.begin(38400);
  pinMode(LED_PIN, OUTPUT);
}
 
void loop() {
  // 若收到值,则送到串口监视窗
  if (BT.available()) {
    val = BT.read();
    if (val == '1') {
      digitalWrite(LED_PIN, LOW);
      // 回应命令发送端,开灯
      BT.println("LED ON");
    } else if (val == '0') {
      digitalWrite(LED_PIN, HIGH);
      // 回应命令发送端,关灯
      BT.println("LED OFF");
    }
  }
}

然后回到主站的串口监视器窗口下,手打输入0或者1,你就会发现从站LED灯在你的控制下亮灭,同时主站串口监视器显示:

嗯,到目前为止,成功了。

四,主站按钮无线控制从站蓝牙小车

我用的是Arduino自带的电机驱动板(Arduino Motor Shield),它的引脚与传统的L298N配置不太一样,它是用单个引脚控制电机的前进和后退(高电平前进,低电平后退)。它的引脚配置说明请见代码。

这是蓝牙主站代码:

//这是蓝牙主站代码 
#include <SoftwareSerial.h>   // 引用函数库
 
SoftwareSerial BT(10, 11); // 接收,传送
char val;  // 储存串口发送值
const int buttonPin0 = 2;     // the number of the pushbutton pin
const int buttonPin1 = 3;     
const int buttonPin2 = 4;    
const int buttonPin3 = 5;
const int buttonPin4 = 6; 

int buttonState0 = 0; //初始化按键状态
int buttonState1= 0;
int buttonState2= 0;
int buttonState3= 0;
int buttonState4= 0;

void setup() {
  Serial.begin(9600);   // 与电脑连接的波特率
  Serial.println("BT is ready!");
 
  // 蓝牙模式设置的波特率
  BT.begin(38400);
  //设置主站按键
  pinMode(buttonPin0, INPUT);//Stop
  pinMode(buttonPin1, INPUT);//Go
  pinMode(buttonPin2, INPUT);//Back
  pinMode(buttonPin3, INPUT);//Left
  pinMode(buttonPin4, INPUT);//Right
}
 
void loop() {
  buttonState0 = digitalRead(buttonPin0);
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);
  buttonState4 = digitalRead(buttonPin4);
  Monitor();
  
}
void Button(){
  if (buttonState0 == LOW) {
    BT.print(0);//给蓝牙串口输入0
    if (BT.available()) {//如果读到从站的返回值,在串口监视器窗口输出小车运动状态
    val = BT.read();
    Serial.print(val);
    }
  } 
  else if(buttonState1 == LOW){
    BT.print(1);//给蓝牙串口输入1
    if (BT.available()) {//如果读到从站的返回值,在串口监视器窗口输出小车运动状态
    val = BT.read();
    Serial.print(val);
    }
  }
   else if(buttonState2 == LOW){
    BT.print(2);//给蓝牙串口输入2
    if (BT.available()) {//如果读到从站的返回值,在串口监视器窗口输出小车运动状态
    val = BT.read();
    Serial.print(val);
    }
   }  
   else if(buttonState3 == LOW){
    BT.print(3);//给蓝牙串口输入3
    if (BT.available()) {//如果读到从站的返回值,在串口监视器窗口输出小车运动状态
    val = BT.read();
    Serial.print(val);
    }
  }
    else if(buttonState4 == LOW){
    BT.print(4);//给蓝牙串口输入4
    if (BT.available()) {//如果读到从站的返回值,在串口监视器窗口输出小车运动状态
    val = BT.read();
    Serial.print(val);
    }
  }
  
  }
void Monitor(){
    // 若读到串口监视器的值,则给蓝牙
  if (Serial.available()) {
    val = Serial.read();
    BT.print(val);
  }
 
  // 若收到蓝牙值,则给串口监视器
  if (BT.available()) {
    val = BT.read();
    Serial.print(val);
  }
  }

下面是从站代码

//这是从站机器人
#include <SoftwareSerial.h>   // 引用BT函数库
 
SoftwareSerial BT(5, 6); // 接收脚,传送脚
char val;  // 蓝牙传输存储接收的值

int dira=13; //左电机直行高电平后退低
int dirb=12; //右电机直行高电平后退低
int pwmb=11; //右电机PWM速度控制
int bra=9; //左电机制动使能(高停低动)
int brb=8; //右电机制动使能(高停低动)
int pwma=3; //左电机PWM速度控制

 
  void setup() {
      
  BT.begin(38400); // 设定蓝牙模块初始波特率
  Serial.begin(9600); 
  
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(11,OUTPUT);

}

void loop() {
// 若收到值,则送到串口监视窗
  if (BT.available()) {
    val = BT.read();
    if (val == '1') {
      Go();// 1代表前进
      BT.println("Go");//回应主站当前状态
    } 
    else if (val == '0') {
      Stop();//0代表停车
      BT.println("Stop");//回应主站当前状态
    }
    else if (val == '2') {
      Back();//2代表后退
      BT.println("Back");//回应主站当前状态
    }
    else if (val == '3') {
      Left();//3代表左转
      delay(300);
      Stop();
      BT.println("Left");//回应主站当前状态
    }
    else if (val == '4') {
      Right();//4代表右转
      delay(300);
      Stop();
      BT.println("Right");//回应主站当前状态
    }
  }
}




void Go()   
{

    digitalWrite(12,HIGH); //双电机前进
    digitalWrite(13,HIGH);
    digitalWrite(8,LOW); //双电机制动关
    digitalWrite(9,LOW);
    
    digitalWrite(3,200);//设置PWM A占空比

    digitalWrite(11,200);//设置PWM B占空比

  }
void Back()   
{


    digitalWrite(12,LOW);//双电机后退
    digitalWrite(13,LOW);
    
    digitalWrite(8,LOW); //双电机制动关
    digitalWrite(9,LOW);
    digitalWrite(3,200);//设置PWM A占空比

    digitalWrite(11,255);//设置PWM B占空比

  }
  void Stop()   
{
    digitalWrite(8,HIGH); //双电机制动开
    digitalWrite(9,HIGH);
  }
  void Left()   
{


    digitalWrite(12,HIGH);//右前
    digitalWrite(13,LOW);//左退
    
    digitalWrite(8,LOW); //双电机制动关
    digitalWrite(9,LOW);
    
    digitalWrite(3,200);//设置PWM A占空比
    digitalWrite(11,255);//设置PWM B占空比

  }
    void Right()   
{


    digitalWrite(12,LOW);//右退
    digitalWrite(13,HIGH);//左前
    
    digitalWrite(8,LOW); //双电机制动关
    digitalWrite(9,LOW);
    
    digitalWrite(3,200);//设置PWM A占空比
    digitalWrite(11,255);//设置PWM B占空比

  }
 

主站代码没有写按键消抖功能,所以当按键按下的时候,它会给从站发射很多次信号,在这点上,大家可以通过加检测延时或者其他消抖代码进行补偿改进。主站代码也可以使用上文用过的串口进行发送,控制小车。

就完事了。

大家可以去试一下,下面连接的第三个,电位器主站控制从站伺服电机。

 

五,链接参考。

1. 自己编写手机蓝牙APP教程(本实验中没有用到,但是很有用,推荐给大家):

https://blog.csdn.net/qq_41381461/article/details/90047414

2. HC-05蓝牙AT模式配置步骤与代码意义:

https://blog.csdn.net/weixin_42994525/article/details/82622405

3. 电位器控制伺服电机的硬件链接与教学视频(外网英文版):

https://howtomechatronics.com/tutorials/arduino/how-to-configure-pair-two-hc-05-bluetooth-module-master-slave-commands/

4. 比较详细的蓝牙AT模式配置教程:

http://swf.com.tw/?p=750

5. HC-05硬件初始设置与常见问题解析:(区分了不同种类的HC-05的使用方法)

https://www.jianshu.com/p/a1781b3d3e44?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

 

 

  • 32
    点赞
  • 220
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值