1. 项目概述
在FPGA开发中,UART(通用异步收发传输器)是最基础也最常用的通信接口之一。这次我分享一个完整的Verilog实现方案,包含波特率发生器、发送模块、接收模块以及顶层整合模块。这个设计已经在Xilinx Artix-7开发板上实测通过,支持可配置的波特率,代码结构清晰,特别适合初学者理解UART的工作原理。
2. 核心模块设计解析
2.1 波特率发生器模块
波特率发生器是整个UART通信的"心跳",它的精度直接影响通信质量。我们采用计数器分频方案,相比DDS(直接数字频率合成)方式更节省资源。核心参数包括:
verilog复制parameter SYS_CLK_FREQ = 50_000_000; // 默认50MHz系统时钟
parameter BAUD_RATE = 9600; // 默认波特率
分频系数计算公式:
code复制分频值 = 系统时钟频率 / 波特率
例如50MHz/9600≈5208
实际工程中建议使用锁相环(PLL)生成更高频率时钟再进行分频,可以减小量化误差。我在Artix-7上测试时,9600波特率的误差小于0.1%,完全满足要求。
2.2 发送模块设计要点
发送模块采用经典的三段式状态机(IDLE→SEND→DONE),有几个关键细节需要注意:
- 起始位处理:发送使能(tx_en)有效后立即拉低tx_pin,保持1个波特率周期
- 数据位顺序:UART协议规定先发送最低位(LSB),代码中对应tx_data_reg[0]最先送出
- 停止位生成:必须确保停止位为高电平,且持续时间不少于1个波特率周期
verilog复制always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
tx_pin <= 1'b1; // 空闲状态保持高电平
end else begin
case(state)
SEND: begin
if(baud_clk_1x) begin
case(bit_cnt)
4'd1: tx_pin <= tx_data_reg[0]; // LSB first
// ...其他数据位
4'd9: tx_pin <= 1'b1; // 停止位
endcase
end
end
endcase
end
end
2.3 接收模块实现技巧
接收模块的难点在于起始位检测和采样时机。我的经验是:
- 起始位检测:在baud_clk_1x上升沿检测rx_pin低电平,避免毛刺误触发
- 中点采样:理想情况应在每位中间时刻采样,本设计为简化在边沿采样,实测稳定性良好
- 数据重组:注意接收顺序与发送相反,最后需要将各bit拼接成完整字节
verilog复制// 接收状态机片段
RECV: begin
if(baud_clk_1x) begin
case(bit_cnt)
4'd1: rx_data_reg[0] <= rx_pin; // 第1位是LSB
// ...其他数据位
endcase
end
end
3. 系统集成与实测
3.1 顶层模块设计
顶层模块uart_top.v通过例化方式整合各子模块,主要功能包括:
- 统一时钟和复位信号
- 参数传递(波特率、时钟频率)
- 发送/接收接口整合
verilog复制module uart_top #(
parameter SYS_CLK_FREQ = 50_000_000,
parameter BAUD_RATE = 9600
)(
input clk,
input rst_n,
// 发送接口
input [7:0] tx_data,
input tx_en,
output tx_pin,
output tx_done,
// 接收接口
input rx_pin,
output [7:0] rx_data,
output rx_done
);
// 例化各子模块
baudrate_gen #(.SYS_CLK_FREQ(SYS_CLK_FREQ), .BAUD_RATE(BAUD_RATE)) u_baudrate_gen(...);
uart_tx u_uart_tx(...);
uart_rx u_uart_rx(...);
endmodule
3.2 测试方案
我采用的测试方法是:
- 自发自收测试:将tx_pin与rx_pin短接,发送特定数据模式(如0x55、0xAA)
- 逻辑分析仪验证:使用Saleae Logic分析仪抓取实际波形
- 跨平台测试:与PC端串口助手通信,验证兼容性
测试中发现一个常见问题:当波特率误差较大时,连续发送多个字节可能导致错位。解决方法是在发送完成(tx_done)后再触发下一次发送,或者增加FIFO缓冲。
4. 性能优化方向
4.1 提高通信可靠性
- 过采样技术:采用16倍过采样,在多位中点取表决值
- 奇偶校验:增加校验位检测单bit错误
- 帧错误检测:检查停止位是否为预期的高电平
4.2 资源优化方案
- 共享波特率时钟:多个UART通道可共享同一个波特率发生器
- 状态机编码优化:使用独热码(one-hot)提高时序性能
- FIFO集成:添加小深度FIFO缓冲发送/接收数据
5. 常见问题排查
5.1 数据收发不全
可能原因:
- 波特率不匹配(检查两端配置)
- 复位信号异常(确保复位后所有寄存器初始化)
- 使能信号时序错误(tx_en应至少保持1个时钟周期)
5.2 接收到乱码
排查步骤:
- 用示波器测量实际波特率
- 检查数据位序(LSB first)
- 验证电压电平(TTL电平应为0V/3.3V)
5.3 时序违例
解决方法:
- 添加适当的时钟约束
- 对跨时钟域信号使用双寄存器同步
- 降低系统时钟频率或波特率
这个UART实现虽然简单,但包含了串口通信的核心原理。在实际项目中,我会根据需求添加流控、DMA等功能。对于初学者来说,理解这个基础版本后再逐步扩展会更加容易。
