蓝牙信使
学习使用 HC-05 蓝牙组件,以便你可以与 Arduino 通信
引言
使用 Arduino 时,最令人兴奋的事情之一就是让它与其他组件进行通信。组件不一定(或不总是)需要连接到互联网。这时蓝牙就派上用场了。有一个非常便宜(而且大部分)易于使用的组件 (HC-05),可以与您的 Arduino 配对,让您远程控制 Arduino。学习使用该组件还可以为您可能考虑的更大型的 Arduino 项目打下坚实的基础。
背景
我们将使用的蓝牙模块非常易于与 Arduino 一起使用。您只需四根线即可将其连接到 Arduino(VCC、GND、Tx(发送)、Rx(接收))。基本上,当模块接收到数据时,它会将其写入 Tx 引脚,将数据发送到 Arduino(通过 Rx 引脚传入)。
要使用蓝牙组件,您需要准备一些东西
- 蓝牙 (BT) 组件(在本文中,我们使用的是 HC-05)
- 一种通过蓝牙发送消息的方式。在本文中,我们将使用我为此目的编写的 Android 应用程序。它的名称是
BTMessenger
,我在我的 GitHub (https://github.com/raddevus/BTMessenger^) 上提供了源代码。它易于使用。您可以键入一条消息并按 [发送] 按钮(稍后详述)。 - 了解蓝牙组件的配置方式以及如何将其与您将用于向其发送消息的设备配对。您可以直接使用开箱即用的蓝牙组件(默认设置:速度 9600,PIN 1234,名称=HC-05),但如果您想更改设备的名称和 PIN,则需要了解如何配置它。要配置组件,您需要以特殊方式连接它,并使用串行应用程序向其发送 AT 命令。(我将引导您阅读我正在撰写的一篇文章,以便您了解其中的细微之处。)
此背景信息的要点
我想强调的主要一点是
设置 HC-05 蓝牙 (BT) 组件并进行基本使用非常容易。但是,自定义该组件却相当困难。您会发现,关于该组件存在大量错误信息,而且许多不同制造商的产品工作方式略有不同。
为什么不使用蓝牙 4.x / BLE?
要使 BLE(低功耗蓝牙)正常工作,需要更多细节。我计划将来对 BLE 进行更深入的研究,因为切换到 BLE 是明智的,这样您就可以支持 iOS 应用程序(iPhone、iPad 等)。
本文零件清单
- Arduino Uno - 我使用的是 Elegoo 克隆版(https://amzn.to/2JOoiIp),约 11 美元
- I2C LCD -(https://amzn.to/2NBWl8S)我在我另一篇文章(使用 20x4 LCD 和 Nano 了解代码执行情况[^])中展示了如何使用它,约 10 美元
- 蓝牙模块 / HC-05(https://amzn.to/2ABeAcQ),8.99 美元
- 面包板 - 我使用的是这些(https://amzn.to/2uVHteA),3 个约 8.50 美元
- 连接线:这是我订购的连接线套装,我非常满意(https://amzn.to/2JsVKsz)。约 20 美元。
让我们开始使用开箱即用的 HC-05 模块。
连接 HC-05 并使用它
HC-05 的工作电压为 3.6V - 6V,因此您的 Uno 可以从 5V 引脚提供正确的电源。这使得一切都非常简单。您只需按照以下方式连接 HC-05,然后将 Uno 连接到 USB 端口,您就会看到 HC-05 启动并开始快速闪烁 LED。
为什么我们使用了 Arduino 引脚 10 和 11
您可能首先想知道的是,为什么我们使用引脚 10 和 11 作为 Rx(接收)和 Tx(发送)引脚。您可能熟悉 Uno,并且知道引脚 0 是 Rx(串行接收),引脚 1 是 Tx(串行发送)。
我选择将其他数字引脚分配为我们的 Rx 和 Tx 有两个原因。
- 从 IDE 上传将失败:当您尝试将程序上传到 Uno 时,Arduino IDE 将使用硬件串行 Rx 和 Tx 引脚。当 IDE 尝试这样做并且 HC-05 连接到这些引脚时,您会发现上传会失败。这是因为 IDE 认为这些引脚正在使用中,并且无法与之建立连接。实际上,它只是 Rx(引脚 1)无法连接。但这会导致它无法上传您的草图。每次移除连接线即可轻松修复,但在开发过程中会很麻烦。使用引脚 10 作为我们的 Rx 可以缓解此问题。
- 使用串行监视器将失败:同样,如果您想使用 Arduino IDE 串行监视器,您将无法使用,因为蓝牙设备会占用硬件(引脚 0 和引脚 1)的 Rx 和 Tx 引脚。连接到引脚 10 和 11 可以将 0 和 1 腾出来供串行监视器使用。
交叉连接:Rx => Tx 和 Tx => Rx
另外,请注意,为了使 HC-05 和 Arduino 之间的串行通信正常工作,我们需要确保
- HC-05
Tx
引脚连接到 Arduino UnoRx
引脚 - HC-05
Rx
引脚连接到 Arduino UnoTx
引脚
再仔细看看第一个原理图,您就会清楚地看到这一点。我将引脚放置在设备上,这样导线实际上就不会交叉。
蓝牙消息发送或接收时发生的情况
您需要真正理解这一点并思考它是如何工作的。
蓝牙接收消息
当 HC-05 设备通过蓝牙接收消息时,它会将该消息写入其 Tx
(发送引脚)。
由于我们希望 Uno 接收消息,因此我们将 HC-05 Tx
引脚连接到 Uno Rx
引脚(在本例中为数字 10)。
蓝牙发送消息
当我们想从蓝牙设备发送消息时,我们将让 Uno 将串行字节写入其 Tx
引脚(数字 11)。当我们向 Uno Tx
引脚写入数据时,它将被 HC-05 的 Rx
引脚接收。HC-05 将其 Rx
引脚接收到的数据通过蓝牙信号广播出去。
现在,让我们编写一个非常简单的草图来接收数据并将其显示在串行监视器中。
第一个草图:在串行监视器中显示数据
看看 HC-05 组件。
您可以看到它有六个引脚,但我们只需要使用其中四个。还有一个按钮(第一个图的右上角),在将组件置于配置模式时使用。
背面标有引脚。我们只使用 Rxd、Txd、GND 和 VCC。
这是它连接并运行的样子。
您可以看到 HC-05 上的红色 LED 已亮起 - 它实际上正在快速闪烁,表明它已准备好接收数据。
现在,让我们上传一些代码,这些代码将从蓝牙读取字节并将其打印到串行监视器中。
这是完整的代码列表
#include <SoftwareSerial.h>
SoftwareSerial BT_Serial(10, 11);
void setup() {
Serial.begin(19200);
Serial.println("BT Messenger");
BT_Serial.begin(38400);
}
void loop() {
String outMsg;
int incomingByte;
byte byteCounter = 0;
byte words[64];
if (BT_Serial.available() > 0) {
Serial.println("got data");
incomingByte = BT_Serial.read();
while (incomingByte > 0){
words[byteCounter++] = incomingByte;
Serial.print(incomingByte,DEC);
incomingByte = BT_Serial.read();
Serial.print(" ");
} // while
Serial.println("");
for (int x = 0; x < byteCounter; x++){
outMsg += char(words[x]);
} // for
Serial.println(outMsg);
} // if (BT_Serial.available()
} // loop()
获取代码:BTMessenger_v001.zip
下载代码并将其上传到您的 Uno 并进行尝试。
一旦运行起来,您将返回 Arduino IDE 并打开串行监视器。
它位于 [工具]...[串行监视器]...
当您选择该菜单项时,将打开串行监视器窗口。如果您的 Uno 通过 USB 电缆连接并且您已经上传了草图,它将打印一条初始消息(BT Messenger)。
在串行监视器的右下角,请注意我们已开启回车符和换行符[Both NL & CR]。我们将速度设置为[19200 波特]。
如果您看到乱码字符
如果您看到一些乱码输出,那很可能是因为波特率与我们在草图中设置的(19200)不匹配。
这是我将其设置为 9600 波特时的样子。看到那些奇怪的反向问号了吗?如果您看到乱码输出,几乎总是因为您没有正确匹配波特率。
现在让我们来谈谈代码。
软件串行
我们首先包含 SoftwareSerial
库,因为我们使用的是数字引脚 10 和 11,而不是使用引脚 0 和 1 上的硬件串行。
接下来,我们实例化一个 SoftwareSerial
对象,传入 Rx 的数字引脚(10)和用于 Tx 的数字引脚(11)。请记住,我们在这里配置的是 Uno。
SoftwareSerial BT_Serial(10, 11);
我们将软件串行对象命名为 BT_Serial
,以便在整个代码中引用它。
在 setup()
方法中,我们初始化将要使用的两个串行设备。
配置软件和硬件串行
每当您看到变量 Serial
时,我们都在引用内置的硬件串行。
这就是为什么我们将串行监视器设置为 19200,因为我们在代码中将其初始化为该值。
Serial.begin(19200);
// 在这里我们将波特率设置为 19200。
Serial.println("BT Messenger");
// 在这里我们将文本打印到硬件串行。由于串行监视器连接到它,因此会打印出来。
接下来,我们还必须初始化软件串行对象的速率。串行定时非常精确,因为它以特定速率发送字节。这就是为什么此值必须与蓝牙 (HC-05) 发送和接收数据的速度匹配。我们将其初始化为 38400,因为这是 HC-05 的默认设置。
BT_Serial.begin(38400);
现在,两个串行组件都可以工作了。
接下来,我们只需从 Arduino 的 Rx 线读取数据,一次一个字节地获取。
在解释其余代码之前,请看看我在发送消息后,串行监视器中的输出是什么样的。
获取 Android 应用程序发送数据
当然,要向设备发送数据,您需要编写一个程序。我编写了一个非常简化的 Android 应用程序,可以让您在 TextEdit 框中键入数据并按 [发送] 按钮。这是应用程序的快照。
下载 APK 并侧载 BTMessenger
首先,您需要下载 .apk 文件。最简单的方法是让您的手机或平板电脑指向我网站上的以下 URL:http://raddev.us/btmessenger.apk。当您从浏览器指向该 URL 时,您的 Android 设备将下载 APK 并询问您是否要安装该应用程序。它未签名,因此会发出警告。
如果您不想下载应用程序,可以在我的 GitHub 上获取源代码^,然后构建并安装它。
将您的 Android 设备与您的蓝牙组件配对
下载并安装应用程序后,请勿立即启动它。首先,您需要将设备与蓝牙组件配对。为此,您需要
- 为您的 HC-05 供电 - 您必须这样做,以便设备可以扫描该项目。项目必须打开才能找到它。
- 接下来,您基本上需要打开设备上的蓝牙功能,然后可能需要告诉它扫描新设备。
这是我的设备上的样子。您还可以看到它正在自动扫描新设备,并且它们的 GUID(全局唯一 ID)地址首先显示出来。过一会儿,您通常会看到设备名称,以便更轻松地识别它。
您还可以看到我有很多已配对的蓝牙设备。这是因为我断断续续地研究 Arduino 蓝牙技术已经有几年了。
当您单击要配对的设备时,会弹出一个框,您需要输入 PIN。默认是 1234,因此您输入它,您将与设备配对。配对后,您可以运行应用程序,设备将显示在底部,以便您可以选择它并向其发送数据。
运行应用
在底部的下拉列表(spinner)中选择您的蓝牙设备的名称。您的设备可能默认命名为 HC-05。我的名字是 superblue。在顶部的 TextEdit 字段中输入您的消息,然后按 [发送] 按钮。
检查数据是否已到达
当然,草图会持续运行 loop()
函数,并使用以下行检查是否有任何数据到达
if (BT_Serial.available() > 0)
available()
函数是一个 SoftwareSerial
函数,它返回串行缓冲区中的字节数。如果蓝牙设备收到了消息,则串行缓冲区中会有字节,因为当蓝牙设备收到消息时,它会将这些字节写入其 Tx 引脚。由于蓝牙设备的 Tx 引脚连接到 Uno 的 Rx(接收引脚),因此 Uno 的串行缓冲区中有字节。
草图在收到数据时首先做的事情是向硬件串行输出打印“got data”,该输出会显示在串行监视器中。我这样做只是为了让您知道我位于代码的这一部分,作为一个调试消息。
从串行缓冲区读取字节
串行缓冲区最多可以容纳 64 个字节,我们使用以下行将这些字节读取到我们自己的字节缓冲区中,以便我们可以对它们进行操作。
incomingByte = BT_Serial.read();
read()
函数一次读取一个字节,因此我将草图放入一个循环中以读取缓冲区中所有可用的字节。
然后,我使用以下行将每个字节打印为其字节值
Serial.print(incomingByte,DEC);
这就是打印“got data”行之后串行监视器中所有数字的代码
之后,我将每个字节转换为字符并将其添加到 outMsg string
中,最后,我们将基于字符的消息打印到串行监视器中。
这就是全部了。但是现在,您可以看到您可以向您的 Arduino 发送蓝牙消息了。
您可能遇到的挑战
您可能会遇到一些挑战,它们几乎总是与设置了错误的速率有关。
可能是因为您的 HC-05 默认设置为 9600。如果是这样,您将在串行监视器中看到乱码输出,并且需要更改将速率设置为 38400 的行,将其更改为 9600。这意味着,在 setup()
中的以下行
BT_Serial.begin(38400);
您将拥有
BT_Serial.begin(9600);
这就是全部。这将帮助您开始使用 Arduino 进行蓝牙通信,并通过向其发送各种消息来通过手机控制 Arduino。
其他蓝牙信息
您可能还想知道如何更改 PIN 码和设备名称。有一种方法可以做到这一点,而且并不算太难,但需要另一种电路设置和一些不同的代码。我将在我的博客或 CodeProject 上很快介绍这一点。到时候再见。
历史
- 2018-08-02:首次发布