Arduino蓝牙模块相互通信

Made by Mike_Zhang


在使用Arduino做项目时, 各个元件都需要使用跳线与MCU或者其他元件连接, 一旦元件数量变多, 跳线数量也会变得很多很杂, 这不利于后期的整理和调整, 也会对信号的传输造成影响, 同时外观也不好看. 因此想用蓝牙代替传统的跳线, 并且能让蓝牙模块配合单片机实现互相通信.

材料

MCU: Arduino UNO R3 2
蓝牙模块: HC-08D
2
USB-TTL转接板 : HC-USB-T V2.0 *2
HC-USB-P串口助手 (下载链接)

蓝牙模块初始化

为了使两块蓝牙模块能够互相连接, 首先需要用USB-TTL转接板 和 HC-USB-P串口助手把两块HC-08D初始化并且设置其中一个为主机.

  1. 给两块HC-08D上电
  2. 把其中一块HC-08D与USB-TTL转接板相互连接, 然后把USB-TTL转接板接上电脑
  3. 打开HC-USB-P串口助手, 选择模块类型HC-08, 点击测试指令, 回复“OK”即为测试成功
  4. 点击“设置模块主机”, 然后在指令文本框中输入AT, 点击数据发送, 收到回复“OK”即为测试成功, 如图:
  5. 设置完成后, 两块蓝牙模块上的指示灯常亮说明连接已经成功, 之后断电后上电两块板会自动连接, 可以把两块板连接USB-TTL转接板, 并通过HC-USB-P串口助手互相给另一块板发送以及接收数据, 以测试连接的稳定性.

蓝牙模块与MCU连接方式

连接方式参考上图

VCC —- 5V
GND —- GND
TXD —- D5
RXD —- D3

主机与从机与MCU连接方式相同, 虽然称为主机和从机, 但是两者都具有传输和接收数据的功能, 名称不同只为了区分两者.

Arduino UNO 测试程序

初始化与连接完成后, 可以开始Arduino的编程, 以达到用MCU传输以及接收数据.
程序主体部分, 主机与从机是相同的, 数据处理部分就取决于自己的需求.
需要用到 SoftwareSerial.h 这一头文件, 使用read()方法接收数据, write()方法传输数据, 更多关于此头文件的内容, 请查看Arduino官网对此的描述.
参考程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<SoftwareSerial.h>
SoftwareSerial BT(5,3); // RX:5, TX:3 实例化一个名为BT的SoftwareSerial对象
int btRead;
void setup() {
Serial.begin(9600);
BT.begin(9600); // 初始化BT的频率, 一般为9600, 不建议修改
}
void loop() {
BT.write(100); // BT发送数据100到另一个蓝牙模块
btRead = BT.read(); // BT接收数据
Serial.println(btRead); // 串口打印数据
delay(100);
}

以上示例程序能够让两个MCU互相发送与接收数据, 随后在两个Arduino的串口监视器都能够看到接收的数据100. 可以让两块MCU发送不一样的数据, 以测试数据传输以及接收的成功.
在测试中可能会发现接收到的数据为-1, 这说明在某一时刻接收出错, 因此我们可以用available()方法或者检查read()的数据是否为-1来检查接收的成功性, 示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<SoftwareSerial.h>
SoftwareSerial BT(5,3); // RX:5, TX:3 实例化一个名为BT的SoftwareSerial对象
int btRead;
void setup() {
Serial.begin(9600);
BT.begin(9600); // 初始化BT的频率, 一般为9600, 不建议修改
}
void loop() {
BT.write(100); // BT发送数据100到另一个蓝牙模块
if (BT.available() > 0){ // 检查接收成功性
btRead = BT.read(); // BT接收数据
Serial.println(btRead);// 串口打印数据
}
delay(100);
}

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<SoftwareSerial.h>
SoftwareSerial BT(5,3); // RX:5, TX:3 实例化一个名为BT的SoftwareSerial对象
int btRead;
void setup() {
Serial.begin(9600);
BT.begin(9600); // 初始化BT的频率, 一般为9600, 不建议修改
}
void loop() {
BT.write(100); // BT发送数据100到另一个蓝牙模块
btRead = BT.read(); // BT接收数据
if (btRead != -1){ // 检查接收成功性
Serial.println(btRead);// 串口打印数据
}
delay(100);
}

数据传输算法

需要注意的是, read()方法只能每次传输以及接收一个数据, 并且传输以及接收的是character类型的数据, 数据大小介于0到255, 共256个数据. 若要传输较大的数据, 可以采用同比缩小和放大的方法. 例如, 若要传输一值为12345的数据, 可以在发送端整除100, 变为123后在传输; 并且在接收端乘以100, 最后接收到的数据即为12300. 当然, 这样的过程产生了数据的误差.

此外, 在实际操作中, 我在传输端有多个旋转电阻模块, 用来控制接收端连接的多个舵机, 每一个舵机都是单独被旋转电阻模块控制的. 这种情况下, 用蓝牙模块就需要注意数据的分组以及顺序的匹配性, 不能使接收到的数据与传输的数据错位.

考虑到此蓝牙模块一次只能传输一个数据, 并且在测试中发现, 传输数据的顺序与接收数据的顺序是一致的, 不会发生偏移. 那只需要在发送端使旋转电阻模块的数据以一个特定的顺序发送, 并且在接收端以相同的顺序接收, 那就可以实现一一对应. 之后唯一需要做的就是使第一个值对齐, 防止数据的整体偏移.

因此, 我在每一组传输数据第一位前加上“000”的校验符, 使得接收端每次接收到“000”后, 开始处理校验符之后的数据, 以此使数据对齐. 一旦接收端没有接收到完整的“000”, 则重新接收下一组数据.

参考程序: (传输端有5个传感器控制接收端连接的5个舵机)
代码下载链接:
https://github.com/zhangwengyu999/Arduino_Bluetooth_Transceiving

发送端程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// TX
// 发送端程序
#include<SoftwareSerial.h>
SoftwareSerial BT(5,3); // RX:5, TX:3 实例化一个名为BT的SoftwareSerial对象
int zero = 0;
void setup() {
Serial.begin(9600);
BT.begin(9600);
}
void loop() {
// sensor one A0
int Readone = analogRead(A0);
int Outone = map(Readone, 1023, 880, 1, 100);

// sensor two A1
int Readtwo = analogRead(A1);
int Outtwo = map(Readtwo, 270, 400, 0, 18);

// sensor three A2
int Readthree = analogRead(A2);
int Outthree = map(Readthree, 280, 400, 18, 5);

// sensor four A3
int Readfour = analogRead(A3);
int Outfour = map(Readfour, 1023, 700, 13, 5);

// sensor five A4
int Readfive = analogRead(A4);
int Outfive = map(Readfive, 0, 1023, 0, 180);

// 000 校验符号发送
BT.write(zero);
delay(10);
BT.write(zero);
delay(10);
BT.write(zero);
delay(10);

// 传感器数据以特定顺序传输
BT.write(Outone); // sensor one
BT.write(Outtwo); /// sensor two
BT.write(Outthree); // sensor three
BT.write(Outfour); // sensor three
BT.write(Outfive); // sensor five
delay(50);
}

接收端程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// RX
// 接收端程序
#include<SoftwareSerial.h>
#include<Servo.h>
SoftwareSerial BT(5,3); // RX:5, TX:3 实例化一个名为BT的SoftwareSerial对象
int val;
int zeroCounter = 0; // 用于000校验符的计数
Servo myServoone;
Servo myServotwo;
Servo myServothree;
Servo myServofour;
Servo myServofive;
void setup() {
Serial.begin(9600);
BT.begin(9600);
myServoone.attach(0);
myServotwo.attach(1);
myServothree.attach(2);
myServofour.attach(3);
myServofive.attach(4);
}
void loop() {
// 000校验符检测
while (zeroCounter != 3){ // 循环直到检测到连续的000
val = BT.read();
if (val == 0){
zeroCounter++; // 若检测到0, 则计数加1
}
else{
zeroCounter = 0; // 若检测到不是0, 则计数直接重置为0
}
delay(10);
}
// 000校验完成后开始接收数据, 保证不会偏移
int i = 0;
while (i < 5){
if (i == 0){
val = BT.read();
if (val != -1){
myServoone.write(val);
i++;
}
}
if (i == 1){
val = BT.read();
if (val != -1){
myServotwo.write(val);
i++;
}
}
if (i == 2){
val = BT.read();
if (val != -1){
myServothree.write(val);
i++;
}
}
if (i == 3){
val = BT.read();
if (val != -1){
myServofour.write(val);
i++;
}
}
if (i == 4){
val = BT.read();
if (val != -1){
myServofive.write(val);
i++;
}
}
}
zeroCounter = 0; // 一组数据接收完成后, zeroCounter重置为0, 开始下一轮000校验
delay(50);
}


写在最后

这是第一次研究Arduino的蓝牙模块, 学到很多所以记录一下, 会继续更新.
最后,希望大家一起交流,分享,指出问题,谢谢!


引用:
Arduino-SoftwareSerial Library


原创文章,转载请标明出处
Made by Mike_Zhang




感谢你的支持

Arduino蓝牙模块相互通信
https://ultrafish.io/post/Arduino-bluetooth-transceiving/
Author
Mike_Zhang
Posted on
March 8, 2021
Licensed under