Arduino 智能小车 - 蓝牙控制(20180504实训课--华清远见)
1.cc2541 蓝牙模块
蓝牙( Bluetooth®)是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波).
在 Arduino 小车上我们使用的蓝牙模块是基于 cc2541 蓝牙芯片构成的.
在 cc2541 芯片内部已经实现了 蓝牙协议,我们不需要开发调试蓝牙协议,一般的蓝牙模块都是采用的串口协议与外部设备进行通讯,当需要通过蓝牙模块发送数据时,直接使用串口即可,蓝牙模块会自动通过蓝牙协议发送给配对好的蓝牙设备.
2.串口通讯
2.1 uart 简介
- 一般我们所说的串口都是表示 uart 口,即通用异步串行收/发装置.
- UART 有4个引脚分别为:
- VCC : 电源
- GND : 接地
- RX : 接收
- TX : 发送
2.2 TTL 电平
- UART 在传输数据时使用的是 TTL 电平,即 0(0v) 表示低电平 1(3.3v或5v) 表示高电平.
- 具体可以参考下图:
2.3 RS232 电平
- RS232 主要是为了解决 TTL 电平抗干扰能力不强的问题,提高了电平的范围,并使用了负逻辑电平
3.Arduino 串口通讯
- 由于蓝牙模块与 Arduino 开发板通过串口通讯,所以我们必须先了解 Arduino 的串口.
- Arduino 开发板上有一个串口,在操作时要调用 Arduino 对应的库函数.
-
相关的库函数如下:
-
begin() 用于设置串口波特率.
Serial.begin(speed)
-
end() 函数用于关闭串口通讯
Serial.end();
-
available() 函数用于判断串口缓冲区是否有数据输入
Serial.available();
-
read() 函数用于读取串口数据
Serial.read();
-
print() 函数用于将数据写入到串口中
Serial.print();
-
println() 函数用于将数据(包括'\n')写入到串口中
Serial.println();
-
-
一般 Arduino 串口编程步骤如下:
-
设置串口波特率,一般在 setup() 中添加即可
void setup() {
Serial.begin(115200);//设置串口0的波特率
}
-
调用 print 或者 println 函数可以通过 Arduino 串口发送给 pc,可以通过串口监视器可以查看,具体编码如下
void loop() {
//每隔 1s 输出字符串
Serial.println("Hello,HQYJ.");
delay(1000);
}
具体在调试窗口上显示的如下图:
-
4.Arduino 与 蓝牙模块连接
- Arduino 与蓝牙模块主要有以下的引脚需要连接:
- +5v : 接5v电源
- GND :接地
- RX : 与 Arduino TX 引脚连接
- TX : 与 Arduino RX 引脚连接
- 在 TX / RX 引脚在连接时, 可以选择任意引脚,这里选择的引脚8,9,可以根据实际情况进行选择
5.Arduino 软串口
5.1 Arduino 软串口
- 由于 Arduino 的物理串口只有一个,一般用于调试,当有更多的设备需要使用串口时,则需要通过普通的 IO 口模拟,在 Arduino 提供了相应的函数接口用于将普通的 IO 口编程串口的 RX/TX 功能.
5.2 Arduino 软串口编程
5.2.1 Arduino 软串口定义
- 在 Arduino 库函数中使用 SoftwareSerial 来定义一个软串口,一般定义如下:
SoftwareSerial bluetoothSerial(8,9);
- 在上述语句中,将 Arduino 的引脚 8,9 设置为与蓝牙模块串口通讯的 RX 与 TX 的功能.
5.2.2 Arduino 软串口监听
- 在使用 Arduino 的软串口时,需要调用 listen() 函数进行监听,具体编程如下:
char recv;
//监听蓝牙串口数据
bluetoothSerial.listen();
5.2.3 Arduino 软串口数据判断
- 在读取串口数据之前需要调用 available() 函数来判断是否有数据.
//判断串口是否产生数据
while(bluetoothSerial.available() > 0){
}
5.2.4 Arduino 软串口数据读取
- 当读取串口数据时需要调用 read() 函数来获取串口的数据.
recv = bluetoothSerial.read();//读取蓝牙串口的数据
Serial.println(recv);//通过Arduino 串口进行输出
- 完整的测试程序如下:
#include <SoftwareSerial.h>
//将8,9引脚设置为串口的rx,tx
SoftwareSerial bluetoothSerial(8,9);
void setup() {
Serial.begin(115200);//设置Arduino开发板的串口的波特率
bluetoothSerial.begin(115200);//设置蓝牙的串口的波特率
}
void loop() {
char recv;
//监听蓝牙串口数据
bluetoothSerial.listen();
while(bluetoothSerial.available() > 0){
//读取蓝牙串口数据
recv = bluetoothSerial.read();
Serial.println(recv);
}
delay(1000);
}
5.使用蓝牙助手调试
5.1 ios 平台
- 在 ios 平台下可以下载 LightBlue 软件进行调试,会自动进行搜索,对应的名字为 JDY-08 .
- 当搜索到之后可以选择 write new value 向蓝牙模块传输值
- 当蓝牙模块接收到数据后,可以通过 Arduino 物理串口进行发送至pc上的调试窗口
5.2 Android 平台
- 在 Android 安装 Tools 目录中的 apk 即可,通过这个软件进行控制.
- 在使用时需要注意以下问题:
- 上下左右发送的值为 10 11 12 13
- 如果单独发送指令,则需要使用两位的十六进制实现,比如发送1,则需要发送01
6.通过蓝牙控制小车
- 当蓝牙模块可以通讯后,则可以实现通过蓝牙控制小车,具体的代码如下:
#include <SoftwareSerial.h>
#include <Servo.h>
SoftwareSerial bluetoothSerial(8,9);
#define STOP 0 //停止
#define FORWARD 1 //前进
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
//左边的电机控制引脚
int leftMotor_1 = 12;
int leftMotor_2 = 13;
//右边的电机控制引脚
int rightMotor_1 = 10;
int rightMotor_2 = 11;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
bluetoothSerial.begin(115200);
pinMode(leftMotor_1, OUTPUT);
pinMode(leftMotor_2, OUTPUT);
pinMode(rightMotor_1, OUTPUT);
pinMode(rightMotor_2, OUTPUT);
}
void loop() {
char cmd;
while(bluetoothSerial.available() > 0){
cmd = bluetoothSerial.read();
//以下指令根据实际情况调整
switch(cmd){
case 'F':
moveForward();
delay(2000);
stopCar();
break;
case 'B':
moveBackward();
delay(2000);
stopCar();
break;
case 'L':
moveLeft();
delay(500);
stopCar();
break;
case 'R':
moveRight();
delay(500);
stopCar();
break;
default:
stopCar();
break;
}
}
}
void moveLeft(void)
{
digitalWrite(leftMotor_1, HIGH);
digitalWrite(leftMotor_2, LOW);
digitalWrite(rightMotor_1, LOW);
digitalWrite(rightMotor_2, HIGH);
}
void moveRight(void)
{
digitalWrite(leftMotor_1,LOW);
digitalWrite(leftMotor_2, HIGH);
digitalWrite(rightMotor_1, HIGH);
digitalWrite(rightMotor_2, LOW);
}
void moveForward(void)
{
digitalWrite(leftMotor_1, LOW);
digitalWrite(leftMotor_2, HIGH);
digitalWrite(rightMotor_1, LOW);
digitalWrite(rightMotor_2, HIGH);
}
void moveBackward(void)
{
digitalWrite(leftMotor_1, HIGH);
digitalWrite(leftMotor_2, LOW);
digitalWrite(rightMotor_1, HIGH);
digitalWrite(rightMotor_2, LOW);
}
void stopCar(void)
{
digitalWrite(leftMotor_1, LOW);
digitalWrite(leftMotor_2, LOW);
digitalWrite(rightMotor_1, LOW);
digitalWrite(rightMotor_2, LOW);
}