通用异步接收器/发送器 (UART) 是一种硬件功能,它使用广泛采用的异步串行通信接口(如 RS232、RS422 和 RS485)处理通信(即时序要求和数据成帧)。UART提供了一种广泛采用且廉价的方法,可实现不同设备之间的全双工或半双工数据交换。
ESP32 芯片有 3 个 UART 控制器(也称为端口),每个控制器都具有一组相同的寄存器,以简化编程并提高灵活性。
每个UART控制器都可独立配置波特率、数据位长度、位排序、停止位数、奇偶校验位等参数。所有常规UART控制器都与不同制造商的UART设备兼容,还可以支持红外数据关联(IrDA)协议。
本文介绍了如何使用 UART 驱动的功能和数据类型在 ESP32 和其他 UART 设备之间建立通信。典型的编程工作流程分为以下几个部分:
设置通信参数 - 设置波特率、数据位、停止位等。
设置通信引脚 - 分配用于连接到设备的引脚
安装驱动程序 - 为 UART 驱动程序分配 ESP32 的资源
运行 UART 通信 - 发送/接收数据
使用中断 - 在特定通信事件上触发中断
删除驱动程序 - 如果不再需要 UART 通信,则释放已分配的资源
步骤 1 至 3 包括配置阶段。第 4 步是 UART 开始运行的地方。步骤 5 和 6 是可选的。
UART 驱动程序的函数使用 标识每个 UART 控制器。以下所有函数调用都需要此标识。
ESP32有3个UART串口,分别是UART0,UART1,UART2,其中UART0用于程序下载和信息交互,UART1专门用于Flash的读写
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
unsigned long baud
:波特率,表示每秒传输的位数。uint32_t config
:配置位,用于设置串口通信的一些选项,如数据位、停止位和奇偶校验等。int8_t rxPin
:接收引脚编号,用于连接接收器。int8_t txPin
:发送引脚编号,用于连接发射器。bool invert
:是否反转输入信号,如果为 true,则在接收时将信号反转。unsigned long timeout_ms
:超时时间(毫秒),当没有数据接收或发送时,该函数将等待指定的时间。uint8_t rxfifo_full_thrhd
:接收缓冲区满阈值,当接收缓冲区达到此值时,将触发中断。以下是一个示例代码,演示如何使用 HardwareSerial::begin()
函数进行串口通信的初始化:
#include <HardwareSerial.h>
// 创建硬件串口对象
HardwareSerial mySerial;
void setup() {
// 初始化串口通信
mySerial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN, false, 1000);
}
void loop() {
// 检查是否有可用的数据
if (mySerial.available()) {
// 读取一个字节的数据
char receivedChar = mySerial.read();
// 处理接收到的数据
// ...
}
}
在Arduino中,还可以使用Serial
对象来处理串口通信。默认情况下,Arduino有3个串口对象:Serial
, Serial1
和Serial2
。
Serial
:默认的串口对象Serial1
:第二个串口对象Serial2
:第三个串口对象这些串口对象具有相同的方法和属性,可以用于配置串口通信、发送数据和接收数据等操作。以下是一个简单的示例代码,演示如何使用这些串口对象进行串口通信:
void setup() {
// 初始化串口通信
Serial.begin(9600);
Serial1.begin(9600);
Serial2.begin(9600);
}
void loop() {
}
Serial.print("hello world");
Serial.printf("hello world");
Serial.println("hello world");
Serial.print()
、Serial.println()
和Serial.printf()
函数在Arduino编程中都被用于向串口输出数据,但它们之间存在一些主要的区别:
Serial.print()
:这个函数会将参数转换为字符串并打印到串口,参数之间不会自动添加分隔符或换行符。Serial.println()
:此函数除了具有Serial.print()
的功能外,还会在输出的末尾自动添加一个换行符。如果参数是字符串、数组或数字,则会将其转换为字符串然后输出。此外,当传入的参数是单个字符时,该函数还会输出该字符的ASCII编码值和一个换行符。Serial.printf()
:这个函数与C语言中的printf()
函数类似,允许你使用格式化字符串来指定输出数据的格式。与前两者不同,Serial.printf()
会将格式化后的字符串直接发送到串口,而不是逐个字符地打印。void setup() {
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
// 使用Serial.print()函数打印数据
Serial.print("Hello, ");
Serial.print("World!");
// 使用Serial.println()函数打印数据
Serial.println("Hello, World!"); //有回车换行
Serial.println(); //回车换行
Serial.println(14,HEX); //以16进制打印输出数值14
// 使用Serial.printf()函数打印数据
int dat= 15;
Serial.printf("Sensor Value: %d", dat);
}
void Serial.write(uint8_t byte)
uint8_t byte
:串口待发送的字节数据在Arduino中使用Serial.write()
函数来向串口写入单个字节示例:
void setup() {
// 打开串口
Serial.begin(9600);
}
void loop() {
// 要发送的字节数据
byte data = 'A';
// 将字节数据写入串口
Serial.write(data);
// 延时一段时间,以便观察输出结果
delay(1000);
}
int Serial.available()
int Serial.read()
Serial.available()
函数。该函数返回可用的字节数,即从串口缓冲区中可以读取的数据长度。Serial.read()
函数。该函数从串口缓冲区中读取一个字节的数据,并将其作为整数返回。示例:
void setup() {
// 打开串口
Serial.begin(9600);
}
void loop() {
// 检查是否有可用数据
int availableBytes = Serial.available();
// 如果有可用数据,则读取并处理
if (availableBytes > 0) {
// 读取数据
char receivedData = Serial.read();
// 处理数据(例如打印到串口监视器)
Serial.print("Received data: ");
Serial.println(receivedData);
}
}
Serial.available()
函数用于检测串口缓冲区中可用的字节数。如果返回值大于0,表示有可用数据,然后使用Serial.read()
函数读取一个字节的数据,并进行相应的处理。
size_t write(const char * buffer, size_t size)
buffer
:要发送的字节数组指针size
:数组的长度Serial.write() 函数发送多个字节数组示例:
#include <Arduino.h>
void setup() {
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
// 定义要发送的字节数组
byte data[] = {0x01, 0x02, 0x03, 0x04};
// 获取字节数组的长度
int length = sizeof(data) / sizeof(data[0]);
// 通过串口发送字节数组
Serial.write(data, length);
// 延时一段时间,以便观察输出结果
delay(1000);
}
size_t HardwareSerial::read(uint8_t *buffer, size_t size)
buffer
读取数据保存的数据缓冲区size
将要读取的数据长度,单位为字节要通过串口读取多个字节,可以使用Serial.available()
函数来检查可用的字节数,然后使用Serial.read(buffer, size)
函数读取多个字节。以下是一个示例代码:
#include <Arduino.h>
void setup() {
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
// 创建字节数组来存储读取到的字节
byte receivedData[64];
delay(10);
// 读取可用的字节数
int numBytes = Serial.available();
// 逐个读取字节并存储到字节数组中
Serial.read(receivedData,numBytes);
// 处理接收到的数据
//pas
}
}
功能要求是接收通过串口(Serial)发送的数据,并将接收到的每个字节数据加1后重新发送回去。
代码:
#include <Arduino.h>
void setup() {
Serial.begin(115200);
}
void loop() {
unsigned char dat;
if(Serial.available()>0){
dat=Serial.read();
dat++;
Serial.write(dat);
}
}
效果:
在串口助手中发送1接收到2
功能要求接收数据,并发送字符串的大小和字符串
代码:
#include <Arduino.h>
void setup() {
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
// 创建字节数组来存储读取到的字节
byte receivedData[64];
delay(10);
// 读取可用的字节数
int numBytes = Serial.available();
// 逐个读取字节并存储到字节数组中
Serial.read(receivedData,numBytes);
// 处理接收到的数据(这里只是简单地打印出来)
Serial.printf("Received len:%d",numBytes);
Serial.println();
Serial.print("Received data: ");
Serial.write(receivedData, numBytes);
Serial.println();
Serial.print("-----------------------");
Serial.println();
}
}
效果:
#include <Arduino.h>
#define d2 2
void setup() {
//初始化灯光
pinMode(d2,OUTPUT);
//初始化UART
Serial.begin(115200);
}
void loop() {
//灯光的控制
if(Serial.available()>0)
{
uint8_t cmd=0;
cmd=Serial.read();
switch(cmd)
{
case 0xA1:
digitalWrite(d2,HIGH);
Serial.println("d2 is ON!");
break;
case 0xA2:
digitalWrite(d2,LOW);
Serial.println("d2 is OFF!");
break;
default:
Serial.println("输入命令错误");
}
}
}
发送A1,d2被点亮