在本教程中,我们将使用 Arduino IDE 的 UART 硬件库在两个 ESP32 板之间执行 UART 或串行通信。
在串口不够的时候,这种方法很管用。
要使用 USB 端口调试和编程 ESP32,需要使用串行端口,即通用异步接收器/发送器 (UART) 通信。对于大多数传感器和系统,主要通信方法被认为是 UART。为了共享工作负载、信息并执行不同的任务,有时需要两个 ESP32 板之间进行通信。
我们将使用 Arduino IDE 对 ESP32 开发板进行编程。因此,您应该拥有最新版本的 Arduino IDE。此外,您还需要安装ESP32环境。
目录
串口简介
通用异步接收传输 (UART) 或串行通信是两个设备之间最简单的通信协议之一。它通过在设备之间连接两根线来在设备之间传输数据,一根是传输线,另一根是接收线。数据以位的形式一点一点地从一个设备传输到另一个设备。该通信协议的主要优点是两个设备不必具有相同的工作频率。例如,以不同时钟频率运行的两个微控制器可以通过串行通信轻松地相互通信。然而,通常在两个微控制器的闪存中设置被称为波特率的预定义比特率,以便两个设备都能理解指令。
发送和接收串行数据
发送 UART 获取数据字节并以顺序形式发送这些位。第二个发送器(即接收器)将这些位重新组装成一个完整的字节。通过OneWire串行传输数据实际上比通过多线并行传输更具成本效益。
两个 UART 设备之间的通信可以是单工、全双工或半双工。单工通信是一种单向类型的通信,其中信号从一个 UART 移动到另一个。它没有为接收 UART 发送回信号的规定。全双工是指两个设备可以同时发送和接收通信。半双工是指设备轮流发送和接收。
UART协议的结构
- UART 包含一个时钟发生器。这允许在一个比特周期内进行采样。
- 它还包含输入和输出移位寄存器。
- 发射和接收控制。
- 读或写控制逻辑。
- UART 的其它可选组件有:发送或接收缓冲区、FIFO 缓冲存储器和 DMA 控制器。
串口技术
以前,键盘、鼠标和打印机的电缆很粗,连接器也很笨重。这些设备使用 UART 与计算机通信。尽管这些笨重的电缆已被 USB 取代,但您仍然可以在 DIY 电子产品中找到 UART,例如 Raspberry Pi、Arduino 和其它常见的微控制器。我们可以用它来连接蓝牙模块和GPS模块。
UART 具有与其它通信协议(例如 SPI 和 I2C)不同的传输协议。它是微控制器中的物理电路。它还可以用作独立的集成电路。 UART 的一个显着优点是它仅依靠两根线来传输数据。
两个设备如何通过UART进行通信?
需要两个 UART 才能直接相互通信。在一端,发送 UART 将来自 CPU 的并行数据转换为串行形式,然后将串行形式的数据发送到第二个 UART,第二个 UART 将接收串行数据并将其转换回并行数据。然后可以从接收设备访问该数据。
发送和接收位使用数据包的起始位和停止位信号来代替隐身信号。这些起始位和停止位定义数据包的开始和结束。因此,接收 UART 知道何时开始和停止读取位。
接收 UART 将检测起始位,然后开始读取这些位。用于读取传入位的特定频率称为波特率。波特率是用于衡量数据传输速度的指标。波特率的单位是比特每秒 (bps)。为了使数据传输成功,发送和接收 UART 必须以几乎相同的波特率运行。然而,如果两个 UART 之间的波特率不同,则它们只能相差 10%。接收和发送 UART 必须配置为接收相同的数据包。
ESP32 串口引脚
ESP32 提供 UART0、UART1、UART2 三个工作在 3.3V TTL 电平的通用异步接收器和发送器 (UART) 端口。这三个串行接口均受硬件支持。它们每个都暴露 4 个引脚:RX、TX、RTS 和 CTS。然而,Arduino IDE 仅使用 RX 和 TX 引脚。
下表指定了 ESP32 中可用的三个 UART 端口中每个端口的 RX 和 TX 引脚。
串口端口 | Rx | Tx | 可用 |
---|---|---|---|
串口0 | GPIO3 | GPIO1 | Yes |
串口1 | GPIO9 | GPIO10 | Yes,但需要重新分配引脚 |
串口2 | GPIO16 | GPIO17 | Yes |
在 Arduino IDE 中初始化 ESP32 UART
当使用 UART1 或 UART2 端口进行 ESP32 UART 通信时,我们使用 HardwareSerial 库。因此,首先将库包含在脚本中。
#include <HardwareSerial.h>
接下来,如果我们使用 Serial.begin(),则使用引脚 1 和 3,这意味着我们正在使用 UART0。如果我们想使用其它串行端口,那么我们必须在代码中定义它们。我们使用以下命令来定义我们选择的 UART 端口:
这里我们创建一个名为“SerialPort()”的 HardwareSerial 库对象,并在括号内指定 UART 端口。
Serial.begin() //if using UART0
HardwareSerial SerialPort(1) //if using UART1
HardwareSerial SerialPort(2) //if using UART2
接下来,在 setup() 函数中,我们将使用 begin() 方法中的 SerialPort 对象初始化 UART 通信,并在其中指定四个参数,如下所示:
SerialPort.begin (BaudRate, SerialMode, RX_pin, TX_pin)
这些参数包括串行通信的波特率、串行模式、所使用的 RX 引脚和 TX 引脚。
如果使用UART2,我们将按如下方式初始化它:
#include <HardwareSerial.h>
HardwareSerial SerialPort(2); // use UART2
void setup()
{
SerialPort.begin(15200, SERIAL_8N1, 16, 17);
}
如果使用UART1,我们将按如下方式初始化它:
这里需要注意的重要一点是,作为 UART1 TX 和 RX 引脚一部分的 GPIO 引脚 9 和引脚 10 在内部连接到闪存。此外,这些引脚在 ESP32 板上也不可用。因此,我们必须重新分配 UART1 的引脚以进行串行通信。幸运的是,ESP32 板能够使用几乎所有 GPIO 引脚进行串行连接。这里我们将 GPIO4 重新分配为 RX 引脚,将 GPIO2 重新分配为 TX 引脚。
#include <HardwareSerial.h>
HardwareSerial SerialPort(1); // use UART1
void setup()
{
SerialPort.begin(15200, SERIAL_8N1, 4, 2);
}
ESP32 到 ESP32 串行通信
让我们看一个串行通信的示例,其中 ESP32 主站将向 ESP32 从站发送“1”或“0”。然后从设备将接收该数据并控制与其数字引脚连接的 LED。我们将使用 UART2 在两块板之间进行通信。
该项目将需要以下组件。
所需组件
- 两块 ESP32 开发板
- 1 个 5mm LED
- 220欧姆电阻1个
- 连接线
- 面包板
连接图
将主 ESP32 板的 TX2 引脚与从 ESP32 板的 RX2 引脚连接。同样,将主 ESP32 板的 RX2 引脚与从 ESP32 板的 TX2 引脚连接。
LED 的阳极引脚通过 220 欧姆的限流电阻与数字引脚 15(from)连接。阴极引脚接地。
还要确保两个 ESP32 板有共同的接地点。
掌握 ESP32 Arduino 程序
打开 Arduino IDE 并转到“文件”>“新建”以打开一个新文件。复制下面给出的代码并保存。
代码如何运作?
现在让我们看看上面的代码是如何工作的。
首先使用#include 文件包含硬件串行库。该行包含 HardwareSerial.h 库。
#include <HardwareSerial.h>
这里声明了 HardwareSerial 库的串行对象,名为“SerialPort”。我们指定 UART 端口号作为其中的参数。在本例中我们使用 UART2。
HardwareSerial SerialPort(2); // use UART2
在 setup() 函数中,我们将使用 SerialPort.begin (BaudRate、SerialMode、RX_pin、TX_pin)打开 UART2 端口的串行通信。
void setup()
{
SerialPort.begin(15200, SERIAL_8N1, 16, 17);
}
这里主站每隔 5 秒就会向从站发送数字 1 和 0。
void loop()
{
SerialPort.print(1);
delay(5000);
SerialPort.print(0);
delay(5000);
}
从机 ESP32 Arduino 程序
打开 Arduino IDE 并转到“文件”>“新建”以打开一个新文件。复制下面给出的代码并保存。
#include <HardwareSerial.h>
HardwareSerial SerialPort(2); // use UART2
char number = ' ';
int LED = 15;
void setup()
{
SerialPort.begin(15200, SERIAL_8N1, 16, 17);
pinMode(LED, OUTPUT);
}
void loop()
{
if (SerialPort.available())
{
char number = SerialPort.read();
if (number == '0') {
digitalWrite(LED, LOW);
}
if (number == '1') {
digitalWrite(LED, HIGH);
}
}
}
代码如何运作?
首先包含硬件串行库。
#include <HardwareSerial.h>
这里声明了 HardwareSerial 库的串行对象,名为“SerialPort”。我们指定 UART 端口号作为其中的参数。在本例中我们使用 UART2。
HardwareSerial SerialPort(2); // use UART2
称为“number”的字符变量存储从站将从主站接收的数据。
char number = ' ';
LED 与从 ESP32 GPIO15 连接。
int LED = 15;
在 setup() 函数中,我们将使用 SerialPort.begin (BaudRate、SerialMode、RX_pin、TX_pin)打开 UART2 端口的串行通信。另外,使用 pinMode() 函数将 LED 引脚设置为输出引脚。将引脚指定为第一个参数,将模式指定为第二个参数。
这里需要注意的一点是ESP32主板和从板的波特率应该相同。
void setup()
{
SerialPort.begin(15200, SERIAL_8N1, 16, 17);
pinMode(LED, OUTPUT);
}
在loop()函数中,我们将检查缓冲区中是否存在数据。如果某些数据可用,则将其存储在变量“number”中。如果数字为“0”,则 LED 将关闭。如果数字为“1”,则 LED 将亮起。
主设备将设置 5 秒连续发送“1”和“0”给从设备。因此,LED 将保持亮起 5 秒,然后熄灭 5 秒。
void loop()
{
if (SerialPort.available())
{
char number = SerialPort.read();
if (number == '0') {
digitalWrite(LED, LOW);
}
if (number == '1') {
digitalWrite(LED, HIGH);
}
}
}
硬件演示
要观看演示,请将主站代码和发送器代码上传到两个 ESP32 板。但是,在上传代码之前,请确保从“工具”>“开发板”中选择 ESP32 开发模块,并从“工具”>“端口”中选择与开发板连接的正确 COM 端口。
LED 将亮起并保持亮起 5 秒,然后熄灭 5 秒。当主设备继续向从设备发送 1/0 时,这种情况会持续下去。
不错