如何使用FPGA实现UART通信
从 UART 帧格式、波特率生成到 Verilog 收发状态机,完成一个可仿真的串口通信模块。
UART 是 FPGA 项目中最常用的调试接口之一。本文实现一个 8N1 配置的收发模块:1 位起始位、8 位数据位、无校验、1 位停止位。
通信参数与时序
UART 没有共享时钟,双方依靠约定的波特率采样。以 50 MHz 系统时钟和 115200 baud 为例,每一位持续的时钟周期数约为:
CLKS_PER_BIT = 50_000_000 / 115_200 ≈ 434
接收端检测到下降沿后,应当先等待半个 bit,在起始位中心再次确认低电平,再按整 bit 间隔采样。
发送模块设计
发送器可以使用有限状态机依次输出起始位、数据位和停止位。
always @(posedge clk) begin
if (tx_start && !tx_busy) begin
tx_shift <= {1'b1, tx_data, 1'b0};
tx_busy <= 1'b1;
bit_cnt <= 0;
end else if (tx_busy && baud_tick) begin
tx <= tx_shift[bit_cnt];
bit_cnt <= bit_cnt + 1'b1;
if (bit_cnt == 9) tx_busy <= 1'b0;
end
end
波特率使能
更推荐生成一个单周期的 baud_tick,而不是在逻辑内部派生新时钟。这样所有寄存器仍处于同一个时钟域,约束和时序分析都会更简单。
接收模块设计
异步输入首先应经过两级触发器同步,以降低亚稳态传播概率。状态机检测起始位后,在每个数据位中心采样,并按低位优先写入移位寄存器。
实际环境存在时钟误差和线路噪声。要求更高时,可以使用 8 倍或 16 倍过采样与多数表决。
仿真与验证
Testbench 中依次发送 8'h55、8'hA3 和边界值,检查接收数据以及 valid 脉冲。0x55 的比特交替变化,特别适合观察采样位置。
- 验证复位时输出保持高电平。
- 验证连续字节之间不会丢失停止位。
- 注入轻微波特率偏差,观察接收容限。
- 在开发板上做 TX/RX 环回测试。
小结
UART 模块的关键不是复杂逻辑,而是明确时序、同步异步输入并通过仿真覆盖边界情况。下一步可以加入 FIFO,让串口与上层逻辑解耦。