---
title: FPGA UART串口通信实现指南：从协议解析到环回测试
url: "https://www.fpgalearn.com/31349.html"
kind: article
id: 31349
excerpt: UART（通用异步收发传输器）是一种广泛应用的异步串行通信协议，因其接口简洁、实现灵活，成为FPGA与PC、传感器、微控制器等外部设备通信的基石。本文旨在提供一…
published_at: 2026-04-11
author: 二牛学FPGA
tags: fpga, UART, 串口通信
word_count: 4025
source: "https://www.fpgalearn.com"
---

# FPGA UART串口通信实现指南：从协议解析到环回测试

> 标签：fpga、UART、串口通信
> UART（通用异步收发传输器）是一种广泛应用的异步串行通信协议，因其接口简洁、实现灵活，成为FPGA与PC、传感器、微控制器等外部设备通信的基石。本文旨在提供一…

> UART（通用异步收发传输器）是一种广泛应用的异步串行通信协议，因其接口简洁、实现灵活，成为FPGA与PC、传感器、微控制器等外部设备通信的基石。本文旨在提供一…

UART（通用异步收发传输器）是一种广泛应用的异步串行通信协议，因其接口简洁、实现灵活，成为FPGA与PC、传感器、微控制器等外部设备通信的基石。本文旨在提供一份从零构建FPGA UART通信系统的完整工程指南，涵盖协议解析、收发器设计、约束配置、仿真验证及环回测试全流程，帮助读者快速搭建一个稳定可靠的通信链路。
## 快速开始 (Quick Start)
1. **环境准备**：安装Vivado 2020.1或更高版本，准备一块带UART接口的FPGA开发板（如基于Xilinx Artix-7系列的板卡）。
1. **创建工程**：在Vivado中新建一个RTL工程，并选择正确的目标器件型号。
1. **添加源文件**：将本指南提供的三个核心RTL模块（`uart_tx.v`, `uart_rx.v`, `uart_top.v`）添加到工程中。
1. **设置顶层模块**：将`uart_top`设置为工程的顶层模块（Top Module）。
1. **添加约束文件**：创建XDC约束文件，正确定义系统时钟、复位信号以及UART的TX、RX引脚位置与电气标准。
1. **综合与实现**：依次运行综合（Synthesis）与实现（Implementation），确保设计无编译错误与时序违例。
1. **生成与下载比特流**：生成比特流文件并下载至FPGA开发板。
## 前置条件与配置说明
| **项目** | **推荐值/配置** | **说明与替代方案** |
| --- | --- | --- |
| **FPGA器件/板卡** | Xilinx Artix-7 (如XC7A35T) | 主流低成本评估板，逻辑资源适中。若使用其他系列（如Kintex、Zynq）或Intel Cyclone V，需相应调整器件约束与可能用到的IP核。 |
| **EDA工具** | Vivado 2020.1 | Xilinx官方工具链。Vivado 2018.3及以上版本或Intel Quartus Prime（对应Intel FPGA）亦可。 |
| **系统时钟频率** | 100 MHz | 用于生成精确的UART波特率时钟。若使用其他频率（如50MHz、125MHz），必须重新计算波特率分频系数。 |
| **UART波特率** | 115200 bps | 常用标准速率，易于与PC端串口调试工具匹配。也可选择9600、19200、57600等，需确保波特率时钟误差 < 2%。 |
| **数据帧格式** | 8位数据，无校验，1位停止位 (8N1) | 最常用配置。设计支持参数化，可扩展为7/9位数据、奇偶校验及1.5/2位停止位。 |
| **仿真工具** | Vivado Simulator | 内置于Vivado，使用便捷。也可选用功能更强大的第三方工具如ModelSim/QuestaSim。 |
| **物理接口** | 板载USB-UART桥接芯片 (如CP2102, FT232) | 连接FPGA的TX/RX引脚至PC USB口。若直接连接RS-232电平，需增加MAX3232等电平转换芯片。 |
| **约束文件 (XDC)** | 必需 | 必须正确定义时钟、复位、UART引脚位置及I/O标准（通常为LVCMOS33）。引脚号需与开发板原理图严格一致。 |
## 目标与验收标准
- **功能目标**：实现一个参数化的UART收发器，能以指定波特率（如115200）可靠地完成数据接收与发送，并实现环回功能（接收数据原样发回）。
- **性能指标**：在100MHz系统时钟下，UART收发逻辑的最高工作频率（Fmax）应显著高于100MHz（通常>200MHz），确保无建立/保持时间违例。
- **资源消耗**：占用极少的FPGA资源（预计LUT < 200， Registers < 100）。
- **验证验收**：
- **仿真验收**：通过Testbench模拟PC发送随机数据流，UART接收后环回发送，波形验证数据正确无误。
- **上板验收**：使用PC串口助手（如Putty、Tera Term）发送任意字符串，能正确接收到相同的字符串回显。
- **压力测试**：连续发送全数据范围（0x00至0xFF循环）的大量数据，长时间运行无误码。
## 实施步骤详解
### 阶段一：工程结构与顶层环回设计
工程包含三个核心模块：发送器(`uart_tx`)、接收器(`uart_rx`)和顶层模块(`uart_top`)。顶层模块负责例化收发器并实现关键的环回控制逻辑。
```
// uart_top.v - 顶层模块与环回逻辑
module uart_top #(
    parameter CLK_FREQ = 100_000_000, // 系统时钟频率 (Hz)
    parameter BAUD_RATE = 115200      // 波特率
) (
    input  wire       clk,      // 系统时钟
    input  wire       rst_n,    // 低电平有效复位
    // UART 物理接口
    input  wire       uart_rx,  // 串行接收线
    output wire       uart_tx   // 串行发送线
);

    // 内部信号声明
    wire [7:0] rx_data;  // 接收到的并行数据
    wire       rx_done;  // 接收完成标志（单周期脉冲）
    wire       tx_busy;  // 发送器忙状态指示
    wire       tx_start; // 发送启动信号

    // 核心环回逻辑：当一帧数据接收完成且发送器空闲时，启动发送
    // 机制分析：此组合逻辑确保每个接收到的数据帧只触发一次发送，避免因信号毛刺或状态重叠导致的数据重复或丢失。
    assign tx_start = rx_done & (~tx_busy);

    // UART 接收器实例化
    uart_rx #(
        .CLK_FREQ  (CLK_FREQ),
        .BAUD_RATE (BAUD_RATE)
    ) u_uart_rx (
        .clk       (clk),
        .rst_n     (rst_n),
        .uart_rx_i (uart_rx),
        .rx_data_o (rx_data),
        .rx_done_o (rx_done)
    );

    // UART 发送器实例化
    uart_tx #(
        .CLK_FREQ  (CLK_FREQ),
        .BAUD_RATE (BAUD_RATE)
    ) u_uart_tx (
        .clk       (clk),
        .rst_n     (rst_n),
        .tx_start_i(tx_start),
        .tx_data_i (rx_data), // 将接收数据直接作为发送数据源
        .uart_tx_o (uart_tx),
        .tx_busy_o (tx_busy)
    );

endmodule
```
#### 常见问题排查 1.1：环回数据异常
- **现象**：数据丢失、重复发送或发送混乱。
- **根本原因**：`tx_start`启动信号不是干净的单周期脉冲。可能因`rx_done`有效期间`tx_busy`状态跳变，或异步信号未同步导致亚稳态传播。
- **检查与解决**：在仿真波形中重点观察`tx_start`信号，它必须在`rx_done`为高且`tx_busy`为低的同一周期内，产生一个时钟周期的正向脉冲。确保`rx_done`和`tx_busy`都来自于同步时钟域。
#### 常见问题排查 1.2：无法识别起始位
- **现象**：接收器始终处于空闲状态，无法进入接收流程。
- **根本原因**：异步的`uart_rx`信号未同步到系统时钟域，导致亚稳态；或波特率时钟分频计算错误，采样点偏差过大。
- **检查与解决**：1) 在`uart_rx`模块入口，使用两级D触发器对输入信号进行同步化处理。2) 复核波特率分频系数计算公式：`BAUD_CNT = CLK_FREQ / BAUD_RATE`。例如，100MHz时钟下115200波特率，分频系数约为868。
### 阶段二：UART接收器（uart_rx）设计要点
接收器采用“过采样”设计，在每位数据的中间时刻进行采样，以提升抗噪声容限。其核心是一个状态机，包含四个状态：空闲(IDLE)、检测起始位(START)、采样数据位(DATA)、确认停止位(STOP)。
```
// uart_rx.v - 状态机定义与采样逻辑（部分）
localparam STATE_IDLE  = 2'b00;
localparam STATE_START = 2'b01;
localparam STATE_DATA  = 2'b10;
localparam STATE_STOP  = 2'b11;

// 波特率时钟生成：每计数BAUD_CNT个系统时钟，产生一个波特率使能脉冲
// 落地路径：使用一个计数器，计满后产生单周期脉冲`baud_en`，作为状态机推进和采样的节拍。
reg [15:0] baud_cnt;
wire       baud_en;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        baud_cnt <= 0;
    else if (state == STATE_IDLE)
        baud_cnt <= 0; // 空闲时计数器清零
    else if (baud_cnt == BAUD_CNT - 1)
        baud_cnt <= 0; // 计满归零
    else
        baud_cnt <= baud_cnt + 1; // 计数
end

assign baud_en = (baud_cnt == BAUD_CNT / 2); // 在计到一半时采样，即数据位中点
```
## 验证结果与波形分析
完成设计后，必须通过仿真验证功能正确性。编写Testbench模拟上位机发送数据（如0x55、0xAA），观察UART RX模块是否能正确解析串行数据，并输出对应的并行数据`rx_data`和完成信号`rx_done`。随后，在顶层观察环回逻辑是否能在`rx_done`有效后，正确启动TX模块将数据（如0x55）发送出去。波形应清晰显示从串行输入到环回串行输出的完整链路，且数据一致。
## 扩展应用与高级主题
- **添加FIFO缓冲**：在收发路径中加入FIFO（先入先出存储器），以解耦数据处理与串行传输的速度，避免高速连续数据丢失。
- **支持硬件流控**：引入RTS（请求发送）和CTS（清除发送）信号，实现基于硬件的流量控制，适用于与需要严格速率匹配的外设通信。
- **多波特率自适应**：设计波特率检测逻辑，使接收器能自动识别并匹配发送端的波特率，增强兼容性。
- **应用层协议封装**：基于此物理层，实现如Modbus RTU、自定义命令帧等应用层协议，用于实际项目中的可靠数据交换。
## 参考资源
- Xilinx, Vivado Design Suite User Guide: Synthesis (UG901)
- UART协议标准，如RS-232、RS-485电气规范。
- 相关FPGA开发板的原理图与用户手册，用于确认引脚约束。
## 附录：关键参数计算
**波特率分频系数**：`BAUD_DIV = CLK_FREQ / BAUD_RATE`。计算出的应为整数。若不为整数，则需考虑采用分数分频或累加器设计以减小误差。
**采样点位置**：通常选择在数据位的时间中点进行采样，即计数到`BAUD_DIV / 2`时。这为边沿抖动提供了最大容忍窗口。
