UART (Universal Asynchronous Receiver/Transmitter),即通用异步收发传输器,是一种硬件设备,用于通过串行端口在计算机或微控制器与外设之间进行异步串行通信。它是最常见、最基本的串行通信方式之一,广泛应用于设备调试、传感器数据传输、模块间通信等场景。

核心思想:UART 通过两根线(发送线 TX 和接收线 RX)以位为单位,按照预设的波特率、数据位、停止位和奇偶校验位,异步传输数据,无需时钟线。


一、为什么需要 UART?

在微控制器和外部设备(如电脑、传感器、其他微控制器、蓝牙模块、GPS 模块等)之间进行数据交换是嵌入式系统的核心需求。

  • 并行通信的局限性:并行通信(如 SPI 的某些模式)虽然速度快,但需要多根数据线(例如 8 位数据需要 8 根线),这会增加硬件成本、PCB 布线难度和功耗,尤其是在远距离传输时容易产生信号同步问题。
  • 串行通信的优势:串行通信每次只发送一个数据位,大大减少了所需的信号线数量(UART 只需要两根线),简化了硬件设计。
  • 异步通信的简便性:UART 是一种异步通信协议,这意味着发送方和接收方不需要共享一个时钟信号。它们各自独立地使用自己的内部时钟,但必须预先约定好通信参数(如波特率)。

UART 的出现,使得在资源有限的嵌入式系统中,高效、可靠地进行设备间通信成为可能。

二、UART 的核心概念与通信参数

UART 的通信是全双工 (Full-Duplex) 的,即可以同时发送和接收数据,分别通过两根独立的线实现:

  • TX (Transmit):发送数据线,连接到接收方的 RX。
  • RX (Receive):接收数据线,连接到发送方的 TX。

UART 通信的关键在于发送方和接收方必须就以下几个通信参数达成一致:

  1. 波特率 (Baud Rate)
    • 表示每秒传输的位数 (bits per second, bps)
    • 发送方和接收方必须使用相同的波特率,否则接收方无法正确采样数据。
    • 常见波特率:9600, 19200, 38400, 57600, 115200 bps 等。波特率越高,传输速度越快。
    • 波特率选择的考量:数据传输量、传输距离、设备性能。
  2. 数据位 (Data Bits)
    • 每个数据帧中实际数据位的数量。
    • 通常为 5、6、7、8 或 9 位,最常用的是 8 位(传输一个字节)。
  3. 停止位 (Stop Bits)
    • 用于标记一个数据帧的结束。
    • 通常为 1、1.5 或 2 位,最常用的是 1 位
  4. 奇偶校验位 (Parity Bit)
    • 一个可选的位,用于检测数据传输过程中是否发生错误。
    • 无校验 (None):最常用,不使用校验位。
    • 偶校验 (Even):数据位和校验位中 1 的总数为偶数。
    • 奇校验 (Odd):数据位和校验位中 1 的总数为奇数。
    • 原理:发送方计算数据位中 1 的数量,然后设置校验位使其符合奇偶规则。接收方收到数据后进行同样的计算,如果结果不符,则认为数据传输有误。
    • 局限性:奇偶校验只能检测出单个位错误,或奇数个位错误。如果发生偶数个位错误,校验可能仍然通过。因此,它是一种简单但有限的错误检测机制。

2.1 UART 数据帧结构

一个完整的 UART 数据帧通常包括:

  1. 空闲状态 (Idle State):当没有数据传输时,UART 数据线保持在高电平。
  2. 起始位 (Start Bit):当发送方准备发送数据时,首先会将数据线从高电平拉低(1 位低电平),通知接收方数据传输即将开始。接收方检测到这个下降沿后,会开始以波特率进行采样。
  3. 数据位 (Data Bits):紧随起始位之后是实际的数据位,通常是 低位在前,高位在后 (Least Significant Bit first - LSB first)。
  4. 奇偶校验位 (Parity Bit):如果启用了奇偶校验,数据位之后会有一个奇偶校验位。
  5. 停止位 (Stop Bit(s)):数据帧的结束标志,通常是 1 位高电平。它确保了在下一个起始位到来之前,接收方有足够的时间进行处理,并重新同步。

一个典型的数据帧 (8N1):
这是一种常见的配置,表示:

  • 8 个数据位
  • 无奇偶校验 (None)
  • 1 个停止位

三、UART 的硬件实现 (RS-232, TTL)

虽然 UART 描述的是数据传输的逻辑协议,但在物理层,它有不同的电压标准:

  1. TTL (Transistor-Transistor Logic) UART
    • 电压电平:高电平通常为 3.3V 或 5V,低电平为 0V。
    • 特点:这是微控制器(如 Arduino、ESP32)内部直接使用的电压电平。
    • 应用:设备内部通信、短距离(通常小于 1-2 米)通信。
  2. RS-232 UART
    • 电压电平
      • 逻辑 ‘0’ (空闲/停止位):+3V 到 +15V
      • 逻辑 ‘1’ (起始位/数据位):-3V 到 -15V
    • 特点:RS-232 是一种标准,需要一个电平转换芯片(如 MAX232)将 TTL 电平转换为 RS-232 电平,反之亦然。
    • 应用:与传统计算机的串行端口、工业设备进行通信。
    • 连接器:通常使用 DB9 或 DB25 连接器。

重要提示:直接连接 TTL UART 和 RS-232 端口会导致电压不匹配,可能损坏设备!始终使用电平转换模块。

四、UART 在 Arduino 中的应用

Arduino 板(如 Uno、Mega、ESP32)都集成了 UART 硬件模块,并提供了易于使用的软件库。

4.1 Arduino Uno (AVR 微控制器)

  • 硬件串口 (Serial)
    • Arduino Uno 有一个硬件 UART 模块,连接到 RX (D0)TX (D1) 引脚。
    • 这些引脚同时也被用于与 USB-to-Serial 芯片(如 ATmega16U2)通信,从而实现与电脑的 USB 串口通信和程序上传。
    • 注意:在使用 D0/D1 进行外部设备通信时,可能会干扰 USB 调试和程序上传。
  • 软件串口 (SoftwareSerial)
    • 通过软件模拟 UART 功能,可以在任意数字引脚上创建额外的串口。
    • 优点:可以有多个串口,不占用硬件串口。
    • 缺点:占用 CPU 资源,最高波特率有限,精度不如硬件串口。

示例:Arduino Uno 硬件串口通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
Serial.begin(9600); // 初始化硬件串口,设置波特率为 9600 bps
Serial.println("Arduino Uno ready.");
}

void loop() {
// 从串口读取数据
if (Serial.available()) {
char incomingByte = Serial.read(); // 读取一个字节
Serial.print("Received: ");
Serial.println(incomingByte);
}

// 向串口发送数据
Serial.println("Hello from Arduino!");
delay(1000); // 每秒发送一次
}

4.2 ESP32 Arduino

ESP32 拥有多个硬件 UART 模块 (通常是 3 个:UART0, UART1, UART2),这使得它在串行通信方面非常强大,可以同时与多个设备通信,而无需使用软件串口。

  • Serial (UART0)
    • 默认情况下,Serial 对象对应于 ESP32 的 UART0。
    • UART0 通常连接到 USB-to-Serial 芯片,用于与电脑通信、调试和上传程序。
    • 默认引脚:通常是 GPIO1 (TX) 和 GPIO3 (RX)。
  • Serial1 (UART1)
    • ESP32 的第二个硬件 UART。
    • 默认引脚:GPIO10 (TX) 和 GPIO9 (RX) 或 GPIO2 (TX) 和 GPIO13 (RX),具体取决于开发板。
    • 可以通过 Serial1.begin() 函数指定自定义的引脚。
  • Serial2 (UART2)
    • ESP32 的第三个硬件 UART。
    • 默认引脚:GPIO17 (TX) 和 GPIO16 (RX)。
    • 同样可以通过 Serial2.begin() 指定自定义引脚。

ESP32 优点

  • 硬件 UART 性能稳定,速度快。
  • 支持引脚重映射 (Pin Remapping),可以在几乎所有 GPIO 引脚上使用 UART 功能,提供了极大的灵活性。

示例:ESP32 使用 Serial1 与外部设备通信

假设你有一个 GPS 模块连接到 ESP32 的 GPIO17 (TX) 和 GPIO16 (RX)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void setup() {
Serial.begin(115200); // 初始化用于调试的 UART0
Serial.println("ESP32 UART Example");

// 初始化 UART1,指定波特率和引脚
// Serial1.begin(baudRate, config, rxPin, txPin);
Serial1.begin(9600, SERIAL_8N1, 16, 17); // 波特率 9600, 8N1, RX: GPIO16, TX: GPIO17
Serial.println("Serial1 initialized on RX:16, TX:17");
}

void loop() {
// 从 Serial1 (GPS 模块) 读取数据并转发到 Serial (电脑)
if (Serial1.available()) {
String data = Serial1.readStringUntil('\n'); // 读取一行数据
Serial.print("GPS Data: ");
Serial.println(data);
}

// 向 Serial1 发送数据 (如果外部设备需要)
// Serial1.println("Request data...");
// delay(1000);
}

五、UART 的优缺点

5.1 优点

  1. 简单易用:只需要两根线(TX/RX)进行通信,硬件连接简单。
  2. 全双工通信:可以同时发送和接收数据。
  3. 广泛支持:几乎所有微控制器和许多外设都支持 UART。
  4. 无需时钟线:异步通信,简化了布线。
  5. 低成本:不需要额外的复杂硬件。

5.2 缺点

  1. 速度相对较慢:相比 SPI 或 I2C,UART 的传输速度通常较低(虽然现代 UART 模块也能达到很高的波特率)。
  2. 无主从结构:UART 是点对点通信,不能像 I2C 那样挂载多个从设备。
  3. 无错误检测/纠正:标准的奇偶校验功能有限,对于高可靠性要求的数据传输,可能需要额外的协议层(如 CRC 校验)。
  4. 距离有限:TTL 电平的 UART 通常适用于短距离通信。RS-232 虽然可以传输更远,但仍有距离限制。
  5. 波特率匹配:发送方和接收方必须精确匹配波特率,否则会产生数据错误。

六、总结

UART 作为一种历史悠久且广泛应用的串行通信协议,因其简单、可靠和易于实现的特点,成为嵌入式系统中不可或缺的一部分。无论是调试输出、与传感器模块通信还是与其他微控制器交互,UART 都提供了一种高效的解决方案。理解其核心参数、数据帧结构以及在不同微控制器平台上的应用,是进行嵌入式开发的必备技能。