UART(通用异步收发传输器)是一种广泛应用的异步串行通信协议,因其接口简洁、实现灵活,成为FPGA与PC、传感器、微控制器等外部设备通信的基石。本文旨在提供一份从零构建FPGA UART通信系统的完整工程指南,涵盖协议解析、收发器设计、约束配置、仿真验证及环回测试全流程,帮助读者快速搭建一个稳定可靠的通信链路。
快速开始 (Quick Start)
- 环境准备:安装Vivado 2020.1或更高版本,准备一块带UART接口的FPGA开发板(如基于Xilinx Artix-7系列的板卡)。
- 创建工程:在Vivado中新建一个RTL工程,并选择正确的目标器件型号。
- 添加源文件:将本指南提供的三个核心RTL模块(
uart_tx.v,uart_rx.v,uart_top.v)添加到工程中。 - 设置顶层模块:将
uart_top设置为工程的顶层模块(Top Module)。 - 添加约束文件:创建XDC约束文件,正确定义系统时钟、复位信号以及UART的TX、RX引脚位置与电气标准。
- 综合与实现:依次运行综合(Synthesis)与实现(Implementation),确保设计无编译错误与时序违例。
- 生成与下载比特流:生成比特流文件并下载至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时。这为边沿抖动提供了最大容忍窗口。





