news 2026/5/13 16:34:41

FPGA新手必看:手把手教你用Verilog实现UART串口通信(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FPGA新手必看:手把手教你用Verilog实现UART串口通信(附完整代码)

FPGA实战:从零构建可调试的UART通信系统

第一次接触FPGA的UART开发时,我盯着示波器上杂乱的波形百思不得其解——为什么PC端发送的ASCII字符在FPGA端变成了乱码?这个困扰我三天的问题最终发现是波特率计数器的一个边界条件错误。本文将带你避开这些"新手坑",用Verilog构建真正可用的UART通信系统。

1. UART通信的核心原理

在嵌入式系统中,UART就像设备的"嘴巴"和"耳朵"。与SPI、I2C等同步协议不同,UART的异步特性使其不需要时钟线,但这也带来了精确时序控制的挑战。

关键参数关系表

参数计算公式示例(50MHz时钟,115200波特率)
波特率除数系统时钟频率/(16×波特率)50,000,000/(16×115200) ≈ 27
采样点除数/213
位周期除数×16432

注意:实际应用中建议使用2的幂次方分频,可减少累积误差

常见的波特率配置陷阱:

  • 使用非整数分频时未处理余数
  • 忽略时钟抖动对高波特率的影响
  • 未考虑电缆传输延迟(特别是长距离时)

2. 发送模块设计与实现

UART发送模块需要将并行数据转换为符合RS-232标准的串行比特流。下面是一个经过生产验证的发送器架构:

module uart_tx #( parameter CLK_FREQ = 50_000_000, parameter BAUD_RATE = 115200 )( input clk, input rst_n, input [7:0] tx_data, input tx_valid, output reg txd, output tx_ready ); localparam BAUD_CNT_MAX = CLK_FREQ / BAUD_RATE; reg [15:0] baud_cnt; reg [3:0] bit_cnt; reg tx_active; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_active <= 0; baud_cnt <= 0; bit_cnt <= 0; txd <= 1'b1; end else if (tx_valid && !tx_active) begin tx_active <= 1; baud_cnt <= 0; bit_cnt <= 0; txd <= 1'b0; // 起始位 end else if (tx_active) begin if (baud_cnt == BAUD_CNT_MAX - 1) begin baud_cnt <= 0; case (bit_cnt) 0: txd <= tx_data[0]; 1: txd <= tx_data[1]; // ... 2-6省略 7: txd <= tx_data[7]; 8: begin txd <= 1'b1; // 停止位 tx_active <= 0; end default: tx_active <= 0; endcase bit_cnt <= bit_cnt + 1; end else begin baud_cnt <= baud_cnt + 1; end end end assign tx_ready = !tx_active; endmodule

调试技巧

  1. 用示波器检查起始位下降沿是否清晰
  2. 测量位周期时间是否符合预期
  3. 验证停止位后是否回到高电平
  4. 检查数据位LSB先发还是MSB先发(标准应为LSB first)

3. 接收模块的容错设计

接收模块需要处理真实的信号问题:毛刺、时钟偏移和噪声。以下是增强鲁棒性的关键技术:

三级同步器消除亚稳态

always @(posedge clk) begin rx_sync[0] <= rxd; rx_sync[1] <= rx_sync[0]; rx_sync[2] <= rx_sync[1]; end

智能起始位检测算法

// 在预期起始位中点采样三次 if (~rx_sync[2] && sample_cnt == BAUD_CNT_MAX/2) begin start_bit_valid <= (rx_sync[2]+rx_sync[1]+rx_sync[0]) < 2; end

数据采样策略对比表

采样方式优点缺点适用场景
单次中点采样实现简单抗噪差低噪声环境
三次投票采样抗噪强资源占用多工业环境
过采样容错高计算复杂高波特率

4. 系统集成与调试

将收发模块封装为完整UART核心时,需要特别注意:

顶层接口设计

module uart_core #( parameter CLK_FREQ = 50_000_000, parameter BAUD_RATE = 115200 )( input clk, input rst_n, // 发送接口 input [7:0] tx_data, input tx_valid, output tx_ready, // 接收接口 output [7:0] rx_data, output rx_valid, // 物理接口 input rxd, output txd );

常见调试问题排查指南

  1. 无任何通信

    • 检查线序是否反接(TX-RX交叉)
    • 验证电平标准(3.3V vs 5V)
    • 确认波特率误差<3%
  2. 接收乱码

    • 用逻辑分析仪对比收发波形
    • 检查停止位配置(1/1.5/2位)
    • 测试不同数据模式(全0/全1/交替)
  3. 偶发丢包

    • 增加FIFO缓冲
    • 优化中断处理时序
    • 检查电源稳定性

5. 进阶优化技巧

当系统需要更高性能时,可以考虑以下优化:

时钟恢复技术

// 动态调整采样点 always @(posedge clk) begin if (edge_detected) begin sample_offset <= (baud_cnt > BAUD_CNT_MAX/2) ? sample_offset - 1 : sample_offset + 1; end end

自动波特率检测实现

  1. 测量起始位持续时间
  2. 计算实际波特率
  3. 动态更新分频系数
  4. 误差补偿算法

在最近的一个物联网网关项目中,我们通过以下配置实现了稳定的115200bps通信:

  • 16倍过采样
  • 3位硬件FIFO
  • 可编程超时中断
  • DMA传输支持
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 16:11:09

GeoJSON.io:5分钟掌握浏览器中的地理数据编辑神器

GeoJSON.io&#xff1a;5分钟掌握浏览器中的地理数据编辑神器 【免费下载链接】geojson.io A quick, simple tool for creating, viewing, and sharing spatial data 项目地址: https://gitcode.com/gh_mirrors/ge/geojson.io 你是否曾因复杂的地理信息系统软件而头疼&a…

作者头像 李华
网站建设 2026/5/13 16:11:08

如何快速清理重复图片:终极数字资产管理指南

如何快速清理重复图片&#xff1a;终极数字资产管理指南 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl 你是否曾经因为电脑中堆积如山的重复图片而感到困扰&#xff1…

作者头像 李华