FPGA小白模块实战:UART串口通信模块,从原理到直接调用
## 写在前面
我相信很多刚学 FPGA 的朋友,第一次接触串口的时候都会有点懵。
一方面,UART 看起来很基础;另一方面,真正上手时问题特别多。比如仿真能跑、上板不通,或者串口助手一开全是乱码。网上 UART 代码确实很多,但真正适合小白直接拿来用的并不多。有些代码没有接口说明,有些参数不好改,还有些只能“演示一下”,一接到自己的工程里就很别扭。
所以这次我把自己项目里常用的一套 UART 模块整理出来,作为 BuildFPGA 的基础模块资源。这个系列就叫:**《FPGA小白模块实战系列》**。UART 是第一篇,后面我会继续整理 SPI、IIC、FIFO、PWM、OLED、VGA 这些高频模块,尽量做到拿来就能用,小白也能看明白。
## 这个 UART 模块适合谁?
如果你属于下面这几类人,这篇会很实用:
- 刚开始学 FPGA,想做串口通信实验的朋友
- 想用串口助手和 FPGA 通信的朋友
- 想给自己项目加一个调试口的朋友
- 想找一个接口清晰、能直接调用的 UART 模块的朋友
- 不想再被各种“能跑但不好接”的源码折腾的朋友
## UART 到底是干什么的?
你可以把 UART 理解成 FPGA 和电脑之间的一条“说话通道”。
电脑这边通常是 USB 转串口模块,FPGA 这边接 `RX/TX`。只要波特率和帧格式一致,FPGA 就能收电脑的数据;反过来 FPGA 也能把调试信息发回串口助手。
在很多项目里,UART 不只是“通信模块”,更是最实用的调试通道。
## FPGA 和电脑串口到底怎么接?
这部分一定要先搞对。很多小白第一次卡住,不是代码错了,而是线接错了。
电脑一般不是直接接 FPGA,而是通过 **USB 转串口模块** 连到 FPGA。
正确接线关系:
- USB转串口模块 `TXD` -> FPGA `RX`
- USB转串口模块 `RXD` -> FPGA `TX`
- USB转串口模块 `GND` -> FPGA `GND`
| USB转串口模块 | FPGA开发板 | 说明 |
| ------------- | ---------- | ------------------ |
| TXD | RX | 电脑发送,FPGA接收 |
| RXD | TX | FPGA发送,电脑接收 |
| GND | GND | 必须共地 |
这里重点强调 6 件事:
1. `TX` 和 `RX` 一定要交叉接,不是同名直连。
2. `GND` 一定要共地,不共地会非常不稳定。
3. 不要把 **RS232 电平** 直接接 FPGA IO。
4. FPGA IO 通常是 **3.3V TTL**,要确认 USB 转串口模块电平一致。
5. `TX/RX` 接反最常见现象就是“完全收不到数据”。
6. `GND` 没接常见现象是“偶尔能收、乱码、时好时坏”。
## UART 一帧数据到底长什么样?
很多教程一上来讲术语,小白更容易糊涂。你先记住这个画面:
UART 线在空闲时是高电平(`1`)。
真正开始发数据时,会先拉低 1 位,这就是起始位(`0`)。
然后发 8 位数据,而且是 **低位先发**。
最后再拉高 1 位,作为停止位(`1`)。
如果发送 `8'h55`(二进制 `0101_0101`),UART 发数据位时是从 `bit0` 开始,不是 `bit7`。
空闲位:`1`
起始位:`0`
数据位:`bit0 -> bit1 -> bit2 -> bit3 -> bit4 -> bit5 -> bit6 -> bit7`
停止位:`1`
只要你把“低位先发 + 起始位先拉低”这两个点记住,后面看波形会轻松很多。
## 这个工程里面有什么?
`uart` 目录里不是只有一个版本,而是分成了几个常见使用场景:
- `uart_echo`:回环测试版本,电脑发什么 FPGA 回什么
- `uart_const_baud`:固定波特率基础收发模块(TX/RX 顶层封装)
- `uart_fifo`:带 FIFO 缓冲的版本,适合实际项目数据流
- `uart_sw_2ch`:双通道相关版本
- `uart_var`、`uart_var_limit`:可变波特率相关版本
如果你是第一次用,别一上来就啃所有文件。
建议先跑通 `uart_echo`,先确认链路和板子没问题;然后看 `uart_const_baud` 把收发接口吃透;最后再上 `uart_fifo`,把它接进你的实际工程。
## 小白建议先跑哪个版本?
我给你一个非常实用的顺序:
1. 先跑 `uart_echo`,看串口通不通
电脑发 `55 AA`,能稳定回显,说明硬件连接、波特率、基础时序都没大问题。
2. 再看 `uart_const_baud`,理解 TX/RX 怎么拆分
这个版本接口清楚,最适合当你后续工程里的 UART 基础 IP。
3. 最后看 `uart_fifo`,解决“项目化”问题
比如数据连续来、上层处理慢、发收节奏不一致,这时候 FIFO 版本就很有价值。
这个顺序跑下来,你不是“看懂了代码”,而是真的能把 UART 接进自己的工程。
## 模块接口怎么用?
这里不贴完整源码,只放几个关键片段,帮你先把“怎么接”跑通。
### 1) 顶层例化(参数配置)
```verilog
uart_const_baud #(
.clock_freq(50_000_000),
.baud_rate (115200)
) uart_inst (
.clk(clk), .rst(rst),
.rx (uart_rx), .tx(uart_tx),
.rx_data(rx_data), .rx_rec_flag(rx_rec_flag),
.tx_data(tx_data), .tx_start(tx_start),
.tx_idle(tx_idle), .tx_done(tx_done)
);
```
### 2) 发送接口怎么驱动
```verilog
if (tx_idle && send_req) begin
tx_data <= send_byte;
tx_start <= 1'b1; // 拉高一个时钟启动发送
end else begin
tx_start <= 1'b0;
end
```
### 3) 接收接口怎么取数
```verilog
if (rx_rec_flag) begin
rx_byte_valid <= 1'b1;
rx_byte_data <= rx_data;
end
```
上面三个片段基本就是小白最常用的接法。完整工程代码我放在 BuildFPGA 资源包里,文章里只讲关键思路,避免把整套源码直接铺开。

浙公网安备 33010602011771号