嘿,想用FPGA实现UART串口通信吗?这可是嵌入式开发和FPGA入门的必修课!UART(通用异步收发传输器)协议简单又经典,是连接各种设备最常用的“对话”方式之一。
掌握它,不仅能让你深刻理解时序逻辑设计,更是你后续挑战SPI、I2C等更复杂协议的坚实跳板。在成电国芯的FPGA培训课程里,实现UART可是数字系统设计模块的“王牌实践项目”。今天,我们就来深入聊聊FPGA实现UART的两个核心魔法:波特率生成与数据帧解析,为你的学习之路点亮一盏灯。
一、先来快速回顾:UART通信的“基本礼仪”
在动手用FPGA实现之前,咱们得先统一一下“语言规则”:
- 异步通信:双方没有统一的时钟信号指挥,全靠事先约定好的“语速”——也就是波特率(Baud Rate)来同步每一位数据。
- 数据帧格式:一帧数据就像一列小火车。车头是起始位(1位低电平,喊一声“发车啦!”),中间是数据位(5-8位,真正的货物),后面可能跟着一个奇偶校验位(1位,检查货物有没有出错),最后是停止位(1-2位高电平,表示“到站了”)。最常见的是8N1格式(8位数据,无校验,1位停止位)。
- 空闲状态:不“说话”的时候,通信线就保持高电平,相当于静静待机。
二、FPGA里的波特率生成:时钟分频的艺术
波特率,简单说就是每秒传输多少位数据。比如9600波特率,就是每秒传9600个比特。我们的FPGA内部时钟跑得飞快(比如50MHz),要让它“慢下来”匹配我们想要的波特率,关键就在于精确的分频计数。
1. 分频系数怎么算?
假设系统时钟频率是clk_freq,目标波特率是baud_rate。通常,我们会生成一个波特率采样时钟,它的频率是目标波特率的16倍(这是一种常用的过采样方法,能让数据采样更稳、抗干扰能力更强)。那么,分频系数就是:
divisor = clk_freq / (baud_rate * 16)
举个例子:系统时钟50MHz,目标波特率115200。divisor = 50_000_000 / (115200 * 16) ≈ 27.13
我们取个整,用27。这就意味着,每数27个系统时钟周期,就让我们的波特率采样时钟“跳一下”。
2. Verilog代码长啥样?
下面是一段经典的用计数器生成波特率使能信号的代码,你可以感受一下:
module baudrate_gen (
input wire clk, // 系统时钟,比如50MHz
input wire rst_n, // 异步复位,低电平有效
output reg baud_tick // 波特率采样使能信号,每16个波特率周期产生一个脉冲
);
parameter CLK_FREQ = 50_000_000;
parameter BAUD_RATE = 115200;
localparam DIVISOR = CLK_FREQ / (BAUD_RATE * 16);
reg [15:0] counter;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
baud_tick <= 1'b0;
end else begin
// ... 计数器逻辑(此处为示例,未完整展开)
end
end
endmodule看,原理是不是挺清晰的?通过精准的计数分频,我们就能从高速的系统时钟里,“雕刻”出我们需要的波特率节奏。这就是用FPGA实现串口通信的第一步,也是最关键的一步。



