1. UART协议基础:串行通信与并行通信的区别、UART帧格式、波特率的概念与计算
大家好,我是你们的FPGA讲师。今天咱们来聊聊UART——这个在嵌入式世界里几乎无处不在的通信协议。
说实话,我刚开始接触FPGA那会儿,第一个调通的通信接口就是UART。那时候看着示波器上跳动的波形,心里还挺激动的。UART看起来简单,但它是理解串行通信最好的切入点。
1.1 串行通信 vs 并行通信
先问大家一个问题:你要把8位数据从A点传到B点,怎么传?
两种思路:
- 并行通信:拉8根线,一次把8位全传过去。快不快?快。但代价呢?线多、占引脚、抗干扰差。
- 串行通信:只拉1根线,一位一位地传。慢是慢了点,但省线、省引脚、成本低。
我在一个项目中用过并行总线连接两块FPGA,结果布线布得我头皮发麻。后来换成串行方案,板子清爽多了。你想想看,如果每个外设都用并行,那FPGA的引脚再多也不够用。
串行通信的核心思想就一句话:用时间换空间。慢一点,但省资源。
串行通信 vs 并行通信 对比
| 对比项 | 串行通信 | 并行通信 |
|---|---|---|
| 传输线数量 | 1~2根 | 8根以上 |
| 传输速度 | 相对较慢 | 相对较快 |
| 抗干扰能力 | 强 | 弱(线间串扰) |
| 引脚占用 | 少 | 多 |
| 典型应用 | UART、SPI、I2C | 并口、DDR内存 |
UART属于异步串行通信。什么叫异步?就是收发双方没有单独的时钟线。那怎么对齐数据?靠约定好的波特率。
1.2 UART帧格式
UART的一帧数据长什么样?我画个图给你看。
UART的一帧包含这几个部分:
- 起始位:1位,固定为低电平。告诉接收方“注意,数据来了”。
- 数据位:5~8位,常见的是8位。先传低位(LSB),再传高位(MSB)。
- 校验位:可选。奇校验、偶校验,或者不要。
- 停止位:1位或2位,固定为高电平。给接收方一点时间处理。
我个人习惯用8位数据、无校验、1位停止位,也就是常说的8N1。简单可靠,大部分场景都够用。
小提示:我曾经在一个项目中遇到通信偶尔出错的问题,查了半天发现是校验位配置错了。发送端配了偶校验,接收端配了奇校验,两边对不上。所以配置UART时,收发双方的帧格式必须完全一致,一个字都不能差。
1.3 波特率的概念与计算
波特率,说白了就是每秒传多少位。单位是bps(bits per second)。
比如9600波特率,意思就是每秒传9600位。那传一个字节需要多久?
算一下:一帧数据 = 1起始 + 8数据 + 0校验 + 1停止 = 10位。所以传一个字节需要 10 / 9600 ≈ 1.04ms。
常见的波特率有:
| 波特率(bps) | 每位时间(μs) | 传1字节时间(ms) |
|---|---|---|
| 9600 | 104.2 | 1.04 |
| 19200 | 52.1 | 0.52 |
| 38400 | 26.0 | 0.26 |
| 115200 | 8.68 | 0.087 |
| 921600 | 1.09 | 0.011 |
在FPGA里实现UART,核心就是用一个计数器来产生波特率时钟。比如系统时钟是50MHz,要产生9600波特率,那计数器要数多少?
// 波特率计算示例
// 系统时钟: 50MHz = 50,000,000 Hz
// 目标波特率: 9600 bps
// 每位需要的时钟周期数 = 50,000,000 / 9600 ≈ 5208
// 所以计数器从0数到5207,翻转一次,就得到了9600波特率的时钟
// 注意:实际中常用16倍过采样,即每位采样16次
// 过采样计数器 = 50,000,000 / (9600 * 16) ≈ 325
注意:波特率不是越高越好。我曾经在一个长距离通信项目里把波特率设到921600,结果数据全是错的。为什么?因为线太长,信号衰减严重。后来降到38400,稳得很。所以选波特率要看你的传输距离和线缆质量。
还有一个容易踩的坑:FPGA的时钟频率和波特率要能整除。如果除不尽,就会产生累积误差。比如50MHz时钟产生115200波特率,50,000,000 / 115200 ≈ 434.03,不是整数。这个0.03的误差累积多了,接收端就会采样错位。
我一般怎么处理?要么选一个能整除的波特率,要么用PLL把时钟调整一下。实在不行,就用16倍过采样,误差容忍度会大一些。
1.4 本章小结
UART协议看起来简单,但它是串行通信的基石。记住三点:
- 串行通信省引脚,并行通信快——看场景选
- UART帧格式:起始位 + 数据位 + 校验位 + 停止位,收发必须一致
- 波特率决定了通信速度,选型时要考虑误差和传输距离
下一章我们会在FPGA里把UART的发送模块写出来,到时候你会看到这些理论知识是怎么变成代码的。