Quick Start
- 安装 Vivado 或 Quartus Prime(推荐 Vivado 2020.1 或更高版本),并确认仿真工具(如 ModelSim、Questa)可用。
- 创建新工程,选择目标器件(如 Xilinx Artix-7 XC7A35T)。
- 编写 UART 发送模块(uart_tx),包含波特率生成器、移位寄存器和起始/停止位逻辑。
- 编写 UART 接收模块(uart_rx),包含边沿检测、采样时钟和字节组装逻辑。
- 编写顶层模块(uart_top),例化 tx 和 rx,连接数据端口和控制信号。
- 编写 testbench,模拟发送一个字节(如 0xA5),并验证接收端正确输出。
- 运行行为仿真,检查波形:tx 线在空闲时为高,起始位为低,数据位按 LSB 优先排列。
- 综合并实现,检查资源利用率(LUT/FF 应低于 100 个)和最大频率(通常 >200 MHz)。
- 生成比特流,下载到 FPGA 板卡,用串口助手(如 Putty)发送数据,观察板载 LED 或通过回环测试验证。
- 验收:发送 0x00-0xFF 所有字节,接收端无误码,波特率误差 < 2%。
前置条件与环境
| 项目 | 推荐值 | 替代方案 |
|---|---|---|
| 器件/板卡 | Xilinx Artix-7 XC7A35T(如 Nexys4 DDR) | Intel Cyclone IV / Lattice iCE40 |
| EDA 版本 | Vivado 2020.1 或更高 | Quartus Prime 18.0+ / ISE 14.7 |
| 仿真器 | Vivado Simulator 或 ModelSim SE-64 10.5 | Questa / GHDL + GTKWave |
| 时钟/复位 | 系统时钟 100 MHz,异步复位低有效 | 50 MHz 时钟,高有效复位(需适配) |
| 接口依赖 | FPGA 的 UART 引脚(如 PMOD 或 USB-UART 桥) | 使用板载 USB-UART(如 CP2102) |
| 约束文件 | XDC 文件:时钟周期 10 ns,IO 标准 LVCMOS33 | SDC 文件(Quartus) |
| 串口工具 | Putty / Tera Term(波特率 115200, 8N1) | Python pyserial 脚本 |
目标与验收标准
本设计旨在实现一个全双工 UART 通信模块,支持可配置波特率(默认 115200)、8 位数据、无校验、1 位停止位(8N1)。验收标准如下:
- 功能点:发送与接收独立,支持连续字节传输,无数据丢失。性能指标:波特率误差 < 2%(实际采样时钟频率与理想值偏差),最大传输速率 1 Mbps(时钟 100 MHz 时)。资源开销:LUT < 80,FF < 60,无 BRAM 使用。验收方式:仿真波形显示 tx 输出符合 UART 帧格式;上板测试通过回环(tx 接 rx)发送 256 字节无错。
实施步骤
阶段一:工程结构与顶层模块
创建工程目录:uart_project/src 放 RTL 文件,uart_project/sim 放 testbench。顶层模块 uart_top 例化 tx 和 rx,并连接数据总线(8 位并行输入/输出)、控制信号(tx_start, rx_ready)和串行线(tx, rx)。
// uart_top.v
module uart_top (
input wire clk,
input wire rst_n,
input wire [7:0] data_in,
input wire tx_start,
output wire tx,
input wire rx,
output wire [7:0] data_out,
output wire rx_done,
output wire tx_busy
);
uart_tx u_tx (
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.tx_start(tx_start),
.tx(tx),
.tx_busy(tx_busy)
);
uart_rx u_rx (
.clk(clk),
.rst_n(rst_n),
.rx(rx),
.data_out(data_out),
.rx_done(rx_done)
);
endmodule常见坑与排查
- 若顶层模块例化时报错,检查模块名和端口顺序是否匹配。若未定义 tx_busy 信号,发送可能重叠。
阶段二:UART 发送模块(uart_tx)
发送模块核心是波特率发生器和移位状态机。波特率发生器将系统时钟分频为 16 倍波特率的采样时钟(例如 115200 bps 需 1.8432 MHz 采样时钟)。状态机依次输出起始位(0)、8 位数据(LSB 优先)、停止位(1)。
// uart_tx.v (核心片段)
localparam CLK_FREQ = 100_000_000;
localparam BAUD_RATE = 115200;
localparam DIVIDER = CLK_FREQ / (BAUD_RATE * 16); // 约 54
reg [5:0] baud_cnt;
wire baud_tick = (baud_cnt == DIVIDER-1);
always @(posedge clk or negedge rst_n)
if (!rst_n)
baud_cnt <= 0;
else if (baud_tick)
baud_cnt <= 0;
else
baud_cnt <= baud_cnt + 1;状态机采用三段式写法,状态包括 IDLE、START、DATA、STOP。在 DATA 状态下,每个 baud_tick 移出一位数据,共 8 位。
原因与机制分析
采用 16 倍过采样而非直接 1 倍采样,是为了在接收端提供更精确的位中心对齐,降低因时钟偏差导致的误码风险。分频系数计算时取整,实际波特率与理想值偏差需控制在 2% 以内,否则可能超出接收端容错范围。
落地路径
- 先验证 baud_tick 波形频率是否正确(仿真中计算脉冲间隔)。再验证状态机输出帧格式:起始位、数据位、停止位顺序与电平。
风险边界
若系统时钟频率过低(如 50 MHz),分频系数较小,波特率误差可能增大;建议时钟不低于 50 MHz。此外,连续发送时需确保 tx_start 在 tx_busy 为低时置位,否则数据可能丢失。
阶段三:UART 接收模块(uart_rx)
接收模块同样依赖 16 倍过采样时钟。边沿检测电路识别起始位下降沿,启动采样计数器。在每位的中点(第 8 个采样点)采集数据,并组装成 8 位字节。完成后输出 rx_done 脉冲和 data_out。
// uart_rx.v (核心片段)
reg [3:0] sample_cnt; // 0-15 过采样计数器
reg [2:0] bit_cnt; // 0-7 位计数器
reg [7:0] shift_reg;
always @(posedge clk or negedge rst_n)
if (!rst_n) begin
sample_cnt <= 0;
bit_cnt <= 0;
shift_reg <= 0;
end else begin
// 边沿检测与采样逻辑(略)
end原因与机制分析
过采样并在位中点采样,可有效避开信号跳变沿附近的毛刺和抖动,提升抗干扰能力。边沿检测采用两级寄存器同步,避免亚稳态传播。
落地路径
- 仿真中注入带噪声的 rx 信号,验证采样点是否正确。测试连续接收多个字节,检查 rx_done 脉冲间隔是否稳定。
风险边界
接收端波特率误差容限约为 ±4%(取决于采样点位置),设计应确保两端误差总和不超过此值。若使用非整数分频,需用累加器或小数分频技术。
阶段四:仿真验证
编写 testbench,实例化顶层模块,生成 100 MHz 时钟和复位信号。模拟发送过程:置位 tx_start,等待 tx_busy 拉低后发送下一字节。同时将 tx 输出直接连接到 rx 输入,实现回环测试。
// testbench 核心片段
initial begin
clk = 0;
forever #5 clk = ~clk; // 100 MHz
end
initial begin
rst_n = 0;
#100 rst_n = 1;
#20 tx_start = 1; data_in = 8'hA5;
#20 tx_start = 0;
wait (rx_done);
$display("Received: %h", data_out);
#100 $finish;
end验证结果
仿真波形应显示:tx 线在空闲时为高,起始位为低,数据位按 LSB 优先排列,停止位为高。接收端在停止位结束后输出 rx_done 脉冲,data_out 与发送数据一致。
排障指南
- 仿真无输出:检查时钟和复位是否正常;确认 baud_tick 是否产生脉冲。数据错位:检查 LSB 优先顺序;确认采样点是否在位中心。上板无响应:检查引脚约束是否正确;确认串口工具波特率设置一致。误码率高:测量实际波特率偏差;检查电源噪声或时钟抖动。
扩展方向
- 支持可配置数据位(5-8 位)、校验位(奇/偶/无)、停止位(1/1.5/2)。添加 FIFO 缓冲,实现连续流传输。集成 AXI4-Stream 接口,便于与 SoC 系统互联。实现自动波特率检测功能。
参考
- 《UART 通信协议标准》(ANSI/EIA-232 系列)Xilinx UG901 Vivado 设计流程指南FPGA 设计实战:数字通信系统(作者:王金明)
附录
附录 A:完整代码清单(略,参见工程源码)
附录 B:约束文件示例
# XDC 约束
create_clock -period 10.000 -name sys_clk [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports {tx rx}]
set_property PACKAGE_PIN L17 [get_ports clk]



