零基础入门学用Arduino 第二部分(一)

重要的内容写在前面:

  1. 该系列是以up主太极创客的零基础入门学用Arduino教程为基础制作的学习笔记。
  2. 个人把这个教程学完之后,整体感觉是很好的,如果有条件的可以先学习一些相关课程,学起来会更加轻松,相关课程有数字电路(强烈推荐先学数电,不然可能会有一些地方理解起来很困难)、模拟电路等,然后就是C++(注意C++是必学的)
  3. 文章中的代码都是跟着老师边学边敲的,不过比起老师的版本我还把注释写得详细了些,并且个人认为重要的地方都有详细的分析。
  4. 一些函数的介绍有参考太极创客官网给出的中文翻译,为了便于现查现用,把个人认为重要的部分粘贴了过来并做了一些修改。
  5. 如有错漏欢迎指正。

视频链接:2-1 MeArm项目概述_哔哩哔哩_bilibili

太极创客官网:太极创客 – Arduino, ESP8266物联网的应用、开发和学习资料

一、伺服电机(舵机)

1、认识伺服电机

(1)伺服电机是一种根据输入PWM信号占空比来控制输出角度的装置(二者具体有什么对应关系取决于电机的型号),其硬件结构如下图所示,电位器与转轴相连,转轴每一个转动角度都分别对应电位器的一个旋转角度,控制电路负责将电位器部分传来的信号和输入的PWM信号作比对,如果当前转轴的转动角度不符合输入PWM信号占空比对应的输出角度,则控制电路将控制电机带动齿轮组旋转,直到转轴的旋转角度与输入的PWM信号相对应。

(2)舵机一般有三根引线需要连接,且引线的颜色一般有统一标准,如下所示,其中橙色线负责给电机输入PWM信号,它不一定必须连接在Arduino的9号引脚,只要带PWM输出的引脚都可以连接。

(3)通常舵机需要的供电功率比较高,如果需要控制1个以上的舵机,那么必须使用单独的电源为舵机供电,而不能使用Arduino开发板的+5V引脚为1个以上的舵机供电。另外,如果使用独立电源为舵机供电,那么独立电源与Arduino必须共地(电源GND与Arduino的GND相互连接在一起)。

2、Servo库概述

(1)通过Servo库可以用Arduino控制舵机(伺服电机)常见的Arduino舵机有两种,一种舵机轴可以旋转180度,还有一种舵机轴可以连续旋转,这种舵机的旋转速度是可以控制的

(2)Servo库允许大多数Arduino开发板(如Arduino Uno)同时控制12个舵机,对于Arduino Mega,可以用Servo库同时控制48个舵机。

(3)请注意:使用Servo库可能会影响Arduino开发板的某些引脚的PWM功能。

(4)对于除Mega开发板以外的Arduino开发板,当使用Servo库时,开发板的9号和10号引脚的PWM功能是无法使用的,也就是说,Arduino程序如果使用了Servo库,无论9号和10号引脚上是否连接了舵机,这两个引脚都不能使用analogWrite进行控制。

(5)对于Mega开发板,使用12个以下的舵机是不会影响开发板的PWM功能的,但如果使用12个以上的舵机,那么Mega开发板上的引脚11和引脚12是要受到影响的。

3、Servo库提供的函数

(1)servo.attach(pin):告知Arduino舵机的数据线连接在引脚pin上。

(2)servo.write(angle):对于标准舵机,write函数会将舵机轴旋转到角度angle相应的位置;对于连续旋转类型的舵机,write函数可以设置舵机的旋转速度(0指示舵机向着一个方向全速旋转,180指示舵机向着另一个方向全速旋转,90指示舵机静止不动,以此类推)。

(3)servo.read():获取当前舵机轴的角度(即上一次使用write()函数设置舵机轴的角度信息)。

(4)servo.attached():检查某一个舵机对象是否连接在开发板引脚上,如果某一个舵机对象的确连接在开发板上则返回true,否则返回false。

(5)servo.deattach():将舵机对象与Arduino开发板断开连接,舵机一旦与Arduino开发板断开连接,则引脚9和引脚10的PWM输出(analogWrite)功能将会恢复。

4、例——舵机自动旋转

(1)根据上图所示将电路连接好。

(2)将下面的程序下载到开发板中,会发现舵机进行重复的来回旋转。值得注意的是,C++采用面向对象的编程思想,Servo库的编写亦是如此,所以可以为Arduino控制的舵机分别创建Servo对象,通过Servo对象调用Servo类的成员函数以达到让对象(舵机)执行相应操作的效果。

#include <Servo.h>  //包含Servo库的头文件
 
Servo myservo;  //创建Servo对象用以控制伺服电机
int pos = 0;    //存储伺服电机角度信息的变量
 
void setup() 
{
  myservo.attach(9);  //Servo对象(其控制的电机)连接在9号引脚 
  Serial.begin(9600);
}
 
void loop() 
{
  for (pos = 0; pos < 180; pos += 45)  //从0度转到180度,每一步旋转45度
  {
    myservo.write(pos);              //舵机旋转轴旋转到'pos'变量的角度
    Serial.println(pos);
    delay(1500);                     //等待1.5秒以确保伺服电机可以达到目标角度
  }
  for (pos = 180; pos > 0; pos -= 45)  //从180度转到0度,每一步旋转45度
  {
    myservo.write(pos);              //舵机旋转轴旋转到'pos'变量的角度
    Serial.println(pos);
    delay(1500);                     //等待1.5秒以确保伺服电机可以达到目标角度
  }
}

二、串口通讯

1、概述

(1)串行端口用于Arduino和个人电脑或其设备进行通信(若没有特殊说明,所提及的串口通信双方均为Arduino与个人电脑),所有Arduino控制器都有至少一个串行端口(也称为UART或者USART)。

(2)个人电脑可以通过USB端口与Arduino的引脚0RX和引脚1TX进行通信,所以当Arduino的引脚0和引脚1用于串行通信功能时,Arduino的引脚0和引脚1是不能做其它工作的。引脚RX和引脚TX工作时,开发板上会有相应的两盏指示灯分别闪烁。

①开发板上的RX和TX如下图所示。

②电脑端的RX和TX如下图所示。

③Arduino和计算机的连接如下图所示,计算机可通过TX向Arduino发送以字节为单位的数据,Arduino可借助RX接收计算机发送来的数据,同理,Arduino可通过TX向计算机发送以字节为单位的数据,计算机可借助RX接收Arduino发送来的数据

(3)串口通信中有一个概念是波特率,可认为是数据传输速率,通信双方的波特率应相同,否则无法正常通信。

(4)如果想深入了解串口通信的底层原理,可以参考课程《计算机网络》,虽然该课程不会详细介绍甚至不会介绍串口通信,但是通过对通信协议的学习,也有助于理解串口通信的原理。

2、例1——串行通讯基本演示

(1)本例仅用USB线将单片机和个人电脑连接即可。

(2)begin函数:

①该函数的作用是设置电脑与Arduino进行串口通讯时的数据传输速率(每秒传输字节数,也称波特率),可使用300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600或115200,也可以根据所使用的设备而设置其它传输速率。

②使用格式为“Serial.begin(speed)”,其中参数speed为传输速率。

(3)available函数:

①当计算机给Arduino传输数据时,Arduino不一定能及时将该数据接收并处理,为了防止数据丢失,Arduino设置了串口接收缓存用于存放接收到的数据,当然,这个缓存不会很大,如果不及时将缓存中的数据读走,同样会造成数据丢失。另外,缓存中的字节数据是以ASCII码的形式存储的,比如字符’1’对应的ASCII码为49,转换为二进制就是00011001。

②available函数无函数参数,可用于检查设备是否接收到数据,该函数将会返回等待读取的数据字节数

③available函数属于Stream类,该函数可被Stream类的子类所使用(Stream类的子类继承了Stream类的函数),如Serial、WiFiClient、File等,本例使用的是Serial.available(),用于检查串口接收缓存中是否有未处理的数据。

(4)read函数:

①read函数无参数,可用于从设备接收到数据中读取一个字节的数据,设备没有接收到数据时返回值为-1,设备接收到数据时返回值为接收到的数据流中的1个字符(先接收先读取,后接收后读取)。

②本函数属于Stream类,该函数可被Stream类的子类所使用,如Serial、WiFiClient、File等,本例使用的是Serial.read(),用于读取串口接收缓存中的数据。

③一个字节数据被读取走后,其在串口接收缓存中随之被移除。

(5)print函数:

①该函数的作用是以人类可读的ASCII码形式向串口发送数据,该函数有多种格式。

[1]Serial.print(val):val是要发送的数据,可以是任意数据类型。

[2]Serial.print(val, format):val是要发送的数据,可以是任意数据类型;format是指定数字的基数(用于整型数)或者小数的位数(用于浮点数),对于整数,这个允许的值为BIN(二进制)、OCT (八进制)、DEC(十进制)或HEX(十六进制),对于浮点数,该参数可以指定小数点的位数。

②整数的每一数位将以ASCII码形式发送;浮点数同样以ASCII码形式发送,默认保留小数点后两位;字节型数据将以单个字符形式发送;字符和字符串会以其相应的形式发送。

③该函数的返回值为发送的字节数,一般来说可以摒弃,即这个返回值没什么实际用途。

(6)println函数:

①该函数的作用是以人类可读的ASCII码形式向串口发送数据,与print函数极其类似,不同的是该函数会在数据发送完毕后发送一个换行符

②该函数的返回值为发送的字节数,一般来说也可以摒弃,即这个返回值也没什么实际用途。

(7)将下面的程序下载到开发板中,然后开始人工调试。

void setup() 
{
  Serial.begin(9600);
  Serial.println("Please input serial data.");
}
 
void loop() 
{
  if (Serial.available() > 0 )    //检查串口缓存中是否有数据等待读取
  {
    Serial.println("======================");        
    char serialData = Serial.read();     //读取串口缓存中等待的一个字符
    Serial.print("Your serialData: '");
    Serial.print(serialData);            //发送刚刚读取到的字符给电脑
    Serial.println("'");
 
    Serial.print("serialData in DEC ");
    Serial.println(serialData, DEC);   //发送刚刚读取到字符的ASCII编码(十进制)
    Serial.print("serialData in BIN ");
    Serial.println(serialData, BIN);   //发送刚刚读取到字符的ASCII编码(二进制)
    Serial.print("serialData in OCT ");
    Serial.println(serialData, OCT);   //发送刚刚读取到字符的ASCII编码(八进制)
    Serial.print("serialData in HEX ");
    Serial.println(serialData, HEX);   //发送刚刚读取到字符的ASCII编码(十六进制)
    Serial.println("======================");
  }
}

①打开Arduino IDE的串口监视器,将内容“a”(结尾不带换行符)发送给Arduino,Arduino接收到数据后,Serial.available()的返回值为1,程序检测到缓存中有数据需要读取,然后进行读取操作,并将读取到的1字节数据以不同格式通过串口发送给电脑(同时附有提示信息)。

②打开Arduino IDE的串口监视器,将内容“bc”(结尾不带换行符)发送给Arduino,Arduino接收到数据后,Serial.available()的返回值为2,程序检测到缓存中有数据需要读取,然后进行读取操作,首先读取1字节数据——字符’b’并以不同格式通过串口发送给电脑(同时附有提示信息),再读取1字节数据——字符’c’并以不同格式通过串口发送给电脑(同时附有提示信息)。

3、例2——利用串行通讯控制一个舵机

(1)按照下图所示将电路连接好,其中Arduino、舵机和电源模块需要共地,电源模块选择5V的输出,另外需要注意电源模块的正负极不能短接。

(2)parseInt函数:

①parseInt函数没有参数,可用于从设备接收到的数据中寻找整数值并将其返回,返回值类型为长整型(long int),若找不到整数数据则返回0。

②本函数属于Stream类,可被Stream类的子类所使用,本例使用的是Serial.parseInt()。

(3)parseFloat函数:

①parseFloat函数没有参数,可用于从设备接收到的数据中寻找浮点数值并将其返回,返回值类型为浮点型(float)。

②本函数属于Stream类,可被Stream类的子类所使用,本例不使用该函数。

(4)将下面的程序下载到开发板中,然后开始人工调试(示例程序没有限定输入数值的取值范围,在实际应用中应用if语句对Arduino接收到的数值进行越界判断后再做处理)。

#include <Servo.h>
 
Servo myServo;         //为舵机创建Servo对象myServo
int dataIndex = 0;     //创建整数型变量,存储输入数据序列号

void setup() 
{
  myServo.attach(6);    //舵机连接在引脚6上
  Serial.begin(9600);   //启动串口通讯,配置传输波特率为9600
  Serial.println("Please input serial data.");
}
 
void loop() 
{           
  if ( Serial.available() > 0 ) // 检查串口缓存是否有数据等待传输
  {                             //处理数据序列号并通过串口监视器显示
    dataIndex++;  
    Serial.print("dataIndex = ");
    Serial.print(dataIndex);
    Serial.print(" , ");      
     
    int pos = Serial.parseInt();   //解析串口数据中的整数信息并赋值给变量pos
    Serial.print("Set servo position: ");
    Serial.println(pos);           //通过串口发送变量pos数值
    myServo.write(pos);            //使用pos变量数值设置伺服电机
    delay(15);
  }
}

①通过串口助手向Arduino发送内容“90”,程序检测到串口接收缓存有未处理数据后,调用parseInt函数对其中的数据进行处理,读取并分析出数据中的内容为整数90,接着Arduino通过串口将“90”发回给计算机,同时控制舵机旋转至90°的位置。

②通过串口助手向Arduino发送内容“*#AB45”,程序检测到串口接收缓存有未处理数据后,调用parseInt函数对其中的数据进行处理,读取并分析出数据中的内容含有整数45,接着Arduino通过串口将“45”发回给计算机,同时控制舵机旋转至45°的位置。

③通过串口助手向Arduino发送内容“*#AB135CV”,程序检测到串口接收缓存有未处理数据后,调用parseInt函数对其中的数据进行处理,读取并分析出数据中的内容含有整数135,“135”之前的字符全部省略,“135”之后的字符在本次parseInt函数的调用中不进行读取,这部分内容仍存储在缓存中,接着Arduino通过串口将“135”发回给计算机,同时控制舵机旋转至135°的位置,这时串口缓存中还有内容“CV”未处理,故程序再次调用parseInt函数对其中的数据进行处理,但在剩余内容“CV”中找不到整数数据,故返回0,Arduino通过串口将“0”发回给计算机,同时控制舵机旋转至0°的位置。

④通过串口助手向Arduino发送内容“*#AB90CV45”,程序检测到串口接收缓存有未处理数据后,调用parseInt函数对其中的数据进行处理,首先parseInt读取到整数数据“90”,“90”以后的数据不参与本次读取,Arduino控制舵机旋转至90°的位置,这时串口接收缓存中还有数据未处理,则程序再次调用parseInt函数,读取到整数数据“45”,Arduino控制舵机旋转至45°的位置。

4、例3——利用串行通讯控制四个舵机

(1)按照下图所示将电路连接好,其中Arduino、舵机和电源模块需要共地,电源模块选择5V的输出,另外需要注意电源模块的正负极不能短接。

(2)将下面的程序下载到开发板中,然后开始人工调试(示例程序没有限定输入数值的取值范围,在实际应用中应用if语句对Arduino接收到的数值进行越界判断后再做处理)。

#include <Servo.h>
 
Servo base, fArm, rArm, claw;  //建立4个电机对象

void setup() 
{
  base.attach(11);     //base伺服电机连接引脚11 电机代号为'b'
  rArm.attach(10);     //rArm伺服电机连接引脚10 电机代号为'r'
  fArm.attach(9);      //fArm伺服电机连接引脚9  电机代号为'f'
  claw.attach(6);      //claw伺服电机连接引脚6  电机代号为'c'
  Serial.begin(9600);
  Serial.println("Please input serial data.");
}
 
void loop() 
{
  if (Serial.available())   //检查串口缓存是否有数据等待传输
  { 
    char servoName = Serial.read();   //获取电机指令中电机编号信息
 
    Serial.print("servoName = ");
    Serial.print(servoName);    
    Serial.print(" , ");      
     
    int data = Serial.parseInt();   //获取电机指令中电机角度信息
 
    switch(servoName)  //根据电机指令中电机信息决定对哪一个电机进行角度设置
    {
      case 'b':   //电机编号为b,设置base电机的角度
        base.write(data); Serial.print("Set base servo value: ");
        Serial.println(data); break;
      case 'r':   //电机编号为r,设置rArm电机的角度  
        rArm.write(data); Serial.print("Set rArm servo value: ");
        Serial.println(data); break;
      case 'f':   //电机编号为f,设置fArm电机的角度  
        fArm.write(data); Serial.print("Set fArm servo value: ");
        Serial.println(data); break;
      case 'c':   //电机编号为c,设置claw电机的角度  
        claw.write(data); Serial.print("Set claw servo value: ");
        Serial.println(data); break;
    }
  }
}

①通过串口助手向Arduino发送内容“b45”,程序检测到缓存中有未处理数据,遂进行处理,首先获取第一个字节,其ASCII码对应的字符’b’为电机编号,接着从后续数据中获取到整数数据“45”,经过switch语句的逻辑控制将编号为“b”的电机控制旋转至45°。

②通过串口助手向Arduino发送内容“r90”,程序检测到缓存中有未处理数据,遂进行处理,首先获取第一个字节,其ASCII码对应的字符’r’为电机编号,接着从后续数据中获取到整数数据“90”,经过switch语句的逻辑控制将编号为“r”的电机控制旋转至90°。

③通过串口助手向Arduino发送内容“f135”,程序检测到缓存中有未处理数据,遂进行处理,首先获取第一个字节,其ASCII码对应的字符’f’为电机编号,接着从后续数据中获取到整数数据“135”,经过switch语句的逻辑控制将编号为“f”的电机控制旋转至135°。

④通过串口助手向Arduino发送内容“c180”,程序检测到缓存中有未处理数据,遂进行处理,首先获取第一个字节,其ASCII码对应的字符’c’为电机编号,接着从后续数据中获取到整数数据“180”,经过switch语句的逻辑控制将编号为“c”的电机控制旋转至180°。

⑤如果发送一个非法的电机编号(比如“a”),四个舵机均不会有任何响应,因为switch语句中没有实现对这种异常情况进行处理。

5、更多Serial(串行通信)函数

(1)Serial.end():终止串行通讯,让RX和TX引脚用于Arduino的输入(INPUT)或输出(OUTPUT)功能。(可调用Serial.begin()重新打开串行通讯)

(2)Serial.find(target):可用于从设备接收到的数据中寻找指定字符串信息,target为被查找字符串,允许使用String或char类型,当函数找到了指定字符串信息后将会立即结束函数执行并且返回“真”,否则将会返回“假”。

(3)Serial.findUntil(target, terminator):可用于从设备接收到的数据中寻找指定字符串信息,当函数找到了指定字符串信息后将会立即结束函数执行并且返回“真”,否则将会返回“假”。

①该函数在满足以下任一条件后都会停止函数执行:读取到指定终止字符串、找到了指定字符串信息、达到设定时间(可使用setTimeout来设置)。

②target是被查找字符串,允许使用String或char类型;terminator是终止字符串,用于设置终止函数执行的字符串信息,设备在读取数据时一旦读取到此终止字符串,将会结束函数执行并返回。

(4)Serial.flush():让开发板在所有待发数据发送完毕前,保持等待状态。

(5)Serial.peek():从设备接收到的数据中读取一个字节的数据,设备没有接收到数据时返回值为-1,设备接收到数据时返回值为接收到的数据流中的第1个字符;与read函数不同的是,使用peek函数读取数据后,被读取的数据不会从数据流中消除。

(6)Serial.readBytes(buffer, length):用于从设备接收的数据中读取信息,读取到的数据信息将存放在缓存变量中。

①该函数在读取到指定字节数的信息或者达到设定时间(该设定时间可使用setTimeout来设置)后都会停止函数执行并返回。

②buffer是缓存变量/数组,用于存储读取到的信息,允许使用char或者byte类型的变量或数组;length是读取字节的数量,readBytes函数在读取到length所指定的字节数量后就会停止运行,允许使用int类型。

(7)Serial.readBytesUntil(character, buffer, length):用于从设备接收到数据中读取信息,读取到的数据信息将存放在缓存变量中。

①该函数在满足以下任一条件后都会停止函数执行并且返回:读取到指定终止字符、读取到指定字节数的信息、达到设定时间(可使用setTimeout来设置)。

②当函数读取到终止字符后,会立即停止函数执行,此时buffer(缓存变量/数组)中所存储的信息为设备读取到终止字符前的字符内容。

③character是终止字符,用于设置终止函数执行的字符信息,允许使用char类型;buffer是缓存变量/数组,用于存储读取到的信息,允许使用char或者byte类型的变量或数组;length是读取字节数量,readBytes函数在读取到length所指定的字节数量后就会停止运行,允许使用int类型。

(8)Serial.write有两种形式:

①Serial.write(val):将字节数据val通过串口发送,val可以是一个字节数据,也可以是由一系列字节数据组成的字符串。

②Serial.write(buf, len):将同一系列字节组成的数组buf通过串口发送,len为数组长度。

(9)Serial.readString():用于从设备接收到数据中读取数据信息,读取到的信息将以字符串格式返回。

(10)Serial.readStringUntil(terminator):用于从设备接收到的数据中读取信息,读取到的数据信息将以字符串形式返回,该函数在读取到指定终止字符terminator或达到设定时间(可使用setTimeout来设置)时都会停止函数执行并返回。

三、蓝牙模块

1、HC-06蓝牙模块

(1)HC-06蓝牙模块的全称是HC-06无线蓝牙串口透传模块,通过该模块可实现手机与Arduino之间的通信,二者之间无需用电线或者其它实物线相连。

(2)HC-06与Arduino之间使用的通信方式是串口通信,二者的连接方式如下图所示。值得注意的是,HC-06的高电平采用的是3.3V而不是5V,当HC-06向Arduino发送信号时,Arduino虽然把5V标定为高电平,但对于HC-06产生的3.3V电压Arduino依旧能够处理,然而当Arduino向HC-06发送信号时,HC-06并不能长时间接受Arduino产生的5V电压,否则会造成元器件的损坏,对此需要在HC-06的RX引脚处连接分压电路,以处理Arduino产生的5V电压。

(3)透传即透明传输,在数据传输过程中,数据不发生任何形式的改变,原封不动地从发送者传到接收者,仿佛传输过程是透明的一样。

(4)当Arduino的串口(可认为是引脚0和引脚1)被HC-06使用后,Arduino将不能再通过串口向其它外设发送数据,同时计算机也不能通过串口将数据甚至是Arduino程序传输到Arduino中

2、例——通过HC-06蓝牙模块控制LED

(1)通过HC-06蓝牙模块控制LED的开关状态:(引脚11连接演示用的LED)

char serialData;
 
void setup() 
{
  Serial.begin(9600);
  pinMode(11, OUTPUT); //引脚11连接演示用的LED
}
  
void loop()
{
  if(Serial.available() > 0)
  { 
    serialData =  Serial.read();   //获取串口数据
     
    if (serialData == '1')   //接收到点亮LED指令
    {  
      Serial.print("Got command: ");
      Serial.println(serialData); 
      Serial.println("LED-ON");
       
      digitalWrite(11, HIGH);  //点亮LED
    } 
    else                    //接收到熄灭LED指令
    { 
      Serial.print("Got command: ");  
      Serial.println(serialData); 
      Serial.println("LED-OFF");
 
      digitalWrite(11, LOW);   //熄灭LED
    }      
  }
}

①手机连接上HC-06蓝牙模块,然后发送数据“1”,HC-06接收到数据“1”后直接将其通过串口发给Arduino,Arduino获取串口接收缓存中的数据“1”后将变量serialData的值更改为1,接着点亮LED灯。

②手机连接上HC-06蓝牙模块,然后发送数据“0”,HC-06接收到数据“0”后直接将其通过串口发给Arduino,Arduino获取串口接收缓存中的数据“0”后将变量serialData的值更改为0,接着熄灭LED灯。

(2)通过HC-06蓝牙模块控制LED的亮度:(引脚11连接演示用的LED)

int brightness;  //记录LED亮度参数(初始时为0)
int serialData;  //记录串口数据(初始时为0)
 
void setup() 
{
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(11, OUTPUT); //引脚11连接演示用的LED
}
  
void loop()
{
  if(Serial.available() > 0)
  {
    serialData =  Serial.parseInt();      //将串口缓存数值存储到serialData变量
    Serial.print("serialData = ");Serial.println(serialData);  
    if (serialData >=0 && serialData <= 255)   //判断目标亮度是否在取值范围内
    {  
      if (serialData >= brightness)  //如果目标亮度大于当前亮度
      {
        for (brightness; brightness <= serialData; brightness++)  //逐步增加亮度参数到目标值
        {
          analogWrite(11, brightness);
          Serial.print("brightness = ");Serial.println(brightness);  
          delay(5);
        }      
      } 
      else                          //否则目标亮度大于当前亮度
      {
        for (brightness; brightness >= serialData; brightness--)  //逐步减小亮度参数到目标值
        {
          analogWrite(11, brightness); 
          Serial.print("brightness = ");Serial.println(brightness);          
          delay(5);          
        }        
      }       
    }     
  }   
}

①手机连接上HC-06蓝牙模块,然后发送数据“255”,HC-06接收到数据“255”后直接将其通过串口发给Arduino,Arduino获取串口接收缓存中的数据“255”后将变量serialData的值更改为255,接着控制LED灯的亮度参数由0逐渐增加到255,LED灯经过一个由熄灭到最大亮度的过程。

②手机连接上HC-06蓝牙模块,然后发送数据“10”,HC-06接收到数据“10”后直接将其通过串口发给Arduino,Arduino获取串口接收缓存中的数据“10”后将变量serialData的值更改为10,接着控制LED灯的亮度参数由255逐渐减小到10,LED灯经过一个由最大亮度到较暗亮度的过程。

3、软件串口及HC-06模块的AT指令

(1)当需要通信的外设较多时,仅使用Arduino唯一的硬件串口(即引脚0和引脚1)进行通信显然是不够的,为了解决这个问题,可以使用Arduino的其它数字输入/输出引脚,用软件模拟的方式实现串口通信,如下图所示。(引脚11连接演示用的LED,图中未画出)

(2)可通过串口(不论软件/硬件)向HC-06蓝牙模块发送信息,当HC-06蓝牙模块未与其它设备(比如手机)建立连接时,它会自己处理接收到的信息,如果不是AT指令则无视之,如果是AT指令则进行相应的操作,并通过串口给指令发送方发送相应的答复

指令

答复

说明

AT

OK

用于通讯测试

AT+VERSION

OKlinvorV1.8

获取固件版本

AT+NAMEmyBTmodule

OKsetname

设置设备名为“myBTmodule”

AT+PIN6789

OKsetPIN

设置设备 PIN 6789

AT+BAUD1

OK1200

设置波特率1200

AT+BAUD2

OK1200

设置波特率2400

AT+BAUD3

OK1200

设置波特率4800

AT+BAUD4

OK1200

设置波特率9600(默认)

AT+BAUD5

OK1200

设置波特率19200

AT+BAUD6

OK1200

设置波特率38400

AT+BAUD7

OK1200

设置波特率57600

AT+BAUD8

OK1200

设置波特率115200

AT+BAUD9

OK1200

设置波特率230400

AT+BAUDA

OK1200

设置波特率406800

AT+BAUDB

OK1200

设置波特率912600

AT+BAUDC

OK1200

设置波特率1382400

(3)将下面的程序下载到开发板中,然后进行人工调试。

#include <SoftwareSerial.h>    //SoftwareSerial见名思义,软件串口库
SoftwareSerial BTserial(2, 3); //建立SoftwareSerial对象,RX — 引脚2, TX — 引脚3
 
void setup() 
{
  Serial.begin(9600);   //配置硬件串口的波特率(硬件串口与计算机通信)
  BTserial.begin(9600); //配置软件串口的波特率(蓝牙模块默认的波特率为9600)
 
  Serial.print("HC-06 DEMO/TEST  ");
  BTserial.print("AT");  //使用软件串口进行通讯测试(AT指令须在HC-06未连接蓝牙状态输入)

  pinMode(11, OUTPUT);                        
}
  
void loop()
{
    //通过串口监视器显示HC-06发送的数据
    if(BTserial.available() > 0)           //如果软件串口有HC-06发来的数据
    {
      char BTserialData =  BTserial.read(); //将软件串口中的数据赋值给变量BTserialData
      Serial.print(BTserialData);          //通过硬件串口监视器显示HC-06发来的数据
      if (BTserialData == '1')             //判断HC-06发来的数据是否是字符1
      {      
        digitalWrite(11, HIGH);            //如果是字符1,则点亮LED
      } 
      else if (BTserialData == '0')
      {  
        digitalWrite(11, LOW);             //如果是字符0,则熄灭LED
      }
    }
    //将用户通过串口监视器输入的数据发送给HC-06
    if (Serial.available() > 0)          //如果硬件串口缓存中有等待传输的数据
    { 
      char serialData =  Serial.read();  //将硬件串口中的数据赋值给变量serialData
      BTserial.print(serialData);        //将硬件串口中的数据通过软件串口发送给HC-06
    }
}

①手机暂时不连接HC-06蓝牙模块,通过串口监视器观察HC-06蓝牙模块接收到指令“AT”后是否给出答复“OK”,如果有给出答复说明线路能够正常工作,此时可以尝试通过串口监视器输入其它AT指令,Arduino使用硬件串口将指令内容接收,接着再使用软件串口将指令内容发给HC-06蓝牙模块(需要注意的是,给HC-06蓝牙模块配置波特率时要记得配置了多大的波特率,否则配置新波特率后,Arduino的软件串口与HC-06蓝牙模块的波特率可能会无法匹配,从而无法进行通信),蓝牙模块接受指令后会给出相应的答复,Arduino使用软件串口将指令内容接收,接着再使用硬件串口将指令内容发给计算机。

②手机连接上HC-06蓝牙模块,然后发送数据“1”,HC-06接收到数据“1”后直接将其发给Arduino,Arduino通过软件串口获取数据“1”后将变量BTserialData的值更改为1,接着点亮LED灯,然后再把数据“1”通过硬件串口发送给计算机。

③手机连接上HC-06蓝牙模块,然后发送数据“0”,HC-06接收到数据“0”后直接将其发给Arduino,Arduino通过软件串口获取数据“0”后将变量BTserialData的值更改为0,接着熄灭LED灯,然后再把数据“0”通过硬件串口发送给计算机。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevalin爱灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值