目录
- 一、UART 基础概念
- UART 核心特点
- USART 和 UART 的区别
- 并行传输与串行传输
- 异步通信与同步通信
- 单工、半双工与全双工
- 二、USART 在 MCU 中的应用
- USART 复用 GPIO
- 波特率与比特率
- 三、通信参数与帧格式
- 帧格式
- 四、USART 内部结构
- 发送
- 接收
- 寄存器与地址
- TDR 与 RDR
- 五、发送数据过程详细介绍
- 六、接收数据详细介绍
一、UART 基础概念
UART 是什么
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种硬件电路,用于设备之间的串行通信。所谓串行通信,是指数据按位顺序逐次传输——一次传输 1 位数据,可以根据需求连续发送多次。
UART 核心特点
- 串行通信:数据逐位传输,节省引脚资源。
- 异步通信:无需共享时钟信号,双方按约定波特率收发。
- 1 对 1 通信:点对点连接,结构简单。
- 全双工通信:收发可同时进行,互不干扰。
三个关键引脚
- TX:发送数据(Transmit)
- RX:接收数据(Receive)
- GND:地线,提供共同参考电平
USART 和 UART 的区别
UART 和 USART 是嵌入式串口通信中经常被混用的两个词,但它们其实有明确的区别。简单说:
USART = UART + 同步通信功能
- UART 只能异步通信;
- USART 既能异步,也能同步。
由于同步通信在实际项目中用得较少,本文着重介绍 UART。
并行传输与串行传输
并行传输:多位数据同时传输,通常配合一个时钟信号。
串行传输:数据逐位顺序传输。串行方式在实际应用中更常用,因为它稳定、线少、干扰少、简洁高效——没有其他线的干扰,成本低,速率也高。
异步通信与同步通信
同步通信
- 主机产生时钟信号(SCK/CK);
- 数据在时钟的某个边沿(上升沿或下降沿)变化;
- 接收方在另一个边沿采样;
- 数据可以连续不断地传输,不需要起始/停止位;
- 如果数据块结束,可以拉高片选(CS)或发送结束标志。
异步通信
- 总线空闲时保持高电平;
- 发送方拉低总线一个位时间,作为起始位;
- 接收方检测到下降沿,知道一帧开始了;
- 双方按约定的波特率,在每位中间采样;
- 停止位(高电平)标志一帧结束;
- 帧与帧之间可以有任意长的空闲时间。
单工、半双工与全双工
单工(Simplex)
数据只能单向传输,A 只能发给 B,B 不能发给 A。通信双方角色固定:一个永远发,一个永远收。只需要一条数据线(或一对差分线)。
典型例子:广播、电视、遥控器、打印机。
优点:简单、成本低;缺点:无法反向通信。
半双工(Half-Duplex)
数据可以双向传输,但不能同时进行。同一时刻只能一方发、另一方收,需要切换方向。通常只需要一条数据线(或一对差分线)共享。
典型例子:对讲机、RS-485、I2C、早期以太网(集线器)。
优点:线少、成本低;缺点:切换方向有延迟,效率低于全双工。
全双工(Full-Duplex)
数据可以同时双向传输。收发独立,互不干扰,不需要切换方向。需要两条独立的数据线(或两对差分线)。
USART 在 MCU 中的角色
二、USART 在 MCU 中的应用
USART 是 MCU 上的片上外设,STM32 系列通常集成多个 USART 外设(例如五个)。
也就是说,通信的本质是MCU 内部的 USART 外设与外部串口设备之间进行数据交换。
USART 复用 GPIO
STM32 的引脚数量有限,但外设功能很多。如果每个外设都配专用引脚,芯片引脚会不够用。
因此,STM32 采用复用(Alternate Function, AF)机制:
- 一个 GPIO 引脚可以有多种功能;
- 默认是普通 GPIO(输入/输出);
- 通过配置,可以把它"切换"成某个外设的功能引脚。
波特率与比特率
三、通信参数与帧格式
比特率是每秒钟传送的比特位的个数,也叫做传信率,侧重点在传递有效信息的速度上,单位是 bit/s。
波特率表示每秒传输的符号数。一个符号可以携带 1 个比特,也可以携带多个比特。
- 如果一个符号 = 1 个比特 → 波特率 = 比特率;
- 如果一个符号 = N 个比特 → 比特率 = 波特率 × N。
在研究传输速度时,通常以波特率为主。在比特率 = 波特率的场景中,不考虑帧格式:1 秒内如果全部都是低电平,波特率是 10,那么就是传递 10 个 0;但如果波特率是 20,就会被理解成 20 个 0。
波特率决定了每一位(每个符号)在时间轴上占多宽。图中波特率 = 10,意思是 1 秒传 10 位。
那每一位占多长时间?
1 / 10 秒 = 0.1 秒 = 100 毫秒
所以:
- 第 1 个 0,持续 100 毫秒;
- 第 2 个 0,持续 100 毫秒;
- ……
- 第 10 个 0,持续 100 毫秒。
STM32 中,USART 一般的常用波特率是 9600 Bd 或者 115200 Bd。通信双方发送和接收数据快慢的问题,可以由通信双方设置相同的波特率来解决。
帧格式
对应接收方,它怎么知道数据开始发了?它怎么知道有多少个数据?它怎么知道数据什么时候传递完毕了?这就需要通信双方继续约定通信格式了,这个格式我们叫做——帧格式。
帧格式是人约定出来的,相当于人让通信设备使用相同的规则通信。这个约定的通信格式,也可以叫做协议。不过,在单片机通信领域,更喜欢叫做帧格式。
下图是常见的通信帧格式:
空闲状态
在没有数据传输时,串口线路应保持逻辑高电平(其实叫做逻辑 1),也就是空闲状态。
起始位
起始位的下降沿(1→0)是从空闲状态进入新帧的标志。起始位(逻辑低电平 0)持续 1 个比特位时间(具体长度由波特率决定),起始位用于告知接收端一个新数据帧的开始,这是接收端进行比特位同步的关键信号!
数据位(Data Bits)
STM32 中,数据位个数通常可选 8 位或者 9 位,最常见的是 8 位(一个字节),承载实际要传输的信息内容,逻辑高(1)或逻辑低(0)代表数据位本身。
USART 中,数据 LSB(Least Significant Bit:最低有效位)最先发送,然后是次低位,依此类推,最后发送 MSB(Most Significant Bit:最高有效位)。
UART 规定:低位先发(LSB first)。也就是说,发送一个字节时,先从 D0 开始发,最后才发 D7。
校验位
- 奇校验(Odd):设置校验位使得数据位和校验位中 1 的总个数为奇数;
- 偶校验(Even):设置校验位使得数据位和校验位中 1 的总个数为偶数。
0x55 的二进制是 0101 0101。如果用偶校验,要求总 1 数为偶数,现在已经是 4 个(偶数),所以校验位填 0:
如果用奇校验,要求总 1 数为奇数,现在 4 个(偶数),所以校验位填 1:
停止位
停止位表示帧的结束,固定为逻辑高电平(1),可以配置为 1 位、会回到空闲状态。
起始位需要拉低电平,表征起始位。tx 输出的电平就取决于当前帧的最后一位,如果当前帧传递完毕,没有结束位,即没有强制拉高电平,此时这个高低电平都有可能。那么传递下一帧,它的起始位就不能 100% 有一个拉低的动作,会影响下一帧的正确开始。
四、USART 内部结构
下图是 USART 的整体框图:
可见这个 USART 的功能非常复杂。初学阶段抓住重点学习即可,核心就是 USART 的复用 GPIO 功能,需要 CPU 控制 USART 的寄存器,如下图所示:
下图是MCU与USART的宏观视角
单独拿出 APBx 和 USART 并简化原理图,来介绍 USART 的功能:
发送
发送数据寄存器(TDR - Transmit Data Register)
谁写它:CPU 或 DMA(通过写操作,即图中的 PWDATA)。
作用:当你要发送数据时,CPU 把要发的字节(比如 0x55)写入 TDR。它相当于一个"暂存区",等待被搬运到下一个环节。
特点:CPU 写完就可以干别的事,不用一直等着。
发送移位寄存器(Transmit Shift Register)
谁写它:自动从 TDR 把数据搬过来。
作用:一旦 TDR 有数据,硬件自动把它加载到移位寄存器。然后,它按波特率的节奏,一位一位(LSB first)地把数据推出去,加上起始位、校验位、停止位,变成完整的帧。
特点:发完一帧,如果 TDR 里又有新数据,它会自动加载下一帧,不用 CPU 插手。
接收
接收移位寄存器(Receive Shift Register)
谁写它:外部信号从 RX 引脚一位一位进来。
作用:接收方检测到起始位后,按波特率的节奏,一位一位地把数据收进来。每收满 8 位(加校验位),就自动把这一字节搬运到 RDR。同时检查停止位、校验位,产生错误标志(帧错误、校验错误等)。
接收数据寄存器(RDR - Receive Data Register)
谁读它:CPU 或 DMA(通过读操作,即图中的 PRDATA)。
作用:移位寄存器凑满一字节后,自动把它放到 RDR。同时置位"接收数据非空"标志(RXNE),通知 CPU 来取。CPU 读取 RDR,就把数据取走了。
寄存器与地址
以 USART1 为例,STM32F103ZET6 的 USART1 挂载在 APB2 总线上,其寄存器组从基地址 0x40013800 开始,共包含 7 个寄存器:
STM32F103ZET6 的 5 个串口(USART1、USART2、USART3、UART4、UART5)基地址和地址范围如下:
TDR 与 RDR
在物理上,USART_DR 寄存器有两个:一个是 TDR,一个是 RDR,分别让用户来发送和接收数据。
这两个寄存器被映射到了同一个物理地址,官方没有披露具体是怎么做到访问同一个地址、从而访问不同寄存器的。我们可以推测是通过操作类型(rw)来区分要访问哪一个寄存器。
- PWDATA(Peripheral Write Data):写数据线。
- PRDATA(Peripheral Read Data):读数据线。
在 APB 总线协议中,读写数据线在物理上是分开的。同时,总线还会发出一个读写控制信号(PWRITE)。
五、发送数据过程详细介绍
这里还要介绍下状态寄存器。要发送数据,首次 CPU 向 TDR 写入数据,TDR 将数据传递给发送移位寄存器,这就引出了状态寄存器。如果我要发送多个数据帧,第二个数据帧什么时候写入 TDR 是个问题;第二个数据帧写入 TDR 之后,什么时候写入发送移位寄存器也是个问题,这些都由状态寄存器决定。
TXE:发送数据寄存器空(Transmit data register empty)
当 TDR 寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果 USART_CR1 寄存器中的 TXEIE 为 1,则产生中断。对 USART_DR 的写操作,将该位清零。
- 0:数据还没有被转移到移位寄存器;
- 1:数据已经被转移到移位寄存器。
TC:发送完成(Transmission complete)
当包含有数据的一帧发送完成后,并且 TXE=1 时,由硬件将该位置 1。如果 USART_CR1 中的 TCIE 为 1,则产生中断。由软件序列清除该位(先读 USART_SR,然后写入 USART_DR)。TC 位也可以通过写入 0 来清除,只有在多缓存通讯中才推荐这种清除程序。
- 0:发送还未完成;
- 1:发送完成。
阻塞模式发送
"阻塞"就是 CPU 卡在 while 循环里出不来。
CPU 想发一个字节,但 TDR 还没空(TXE=0),硬件忙不过来。CPU 就只能在循环里一直问:"TXE 变成 1 了吗?变了吗?"直到 TXE=1,CPU 才写数据,然后继续干别的事。
这个"一直问"的过程,就是阻塞。
六、接收数据详细介绍
同理,接收数据也需要状态寄存器来显示状态。
RXNE:读数据寄存器非空(Read data register not empty)
当 RDR 移位寄存器中的数据被转移到 USART_DR 寄存器中,该位被硬件置位。如果 USART_CR1 寄存器中的 RXNEIE 为 1,则产生中断。对 USART_DR 的读操作可以将该位清零。RXNE 位也可以通过写入 0 来清除,只有在多缓存通讯中才推荐这种清除程序。
- 0:数据没有收到;
- 1:收到数据,可以读出。
阻塞式接收数据
"阻塞"就是 CPU 卡在 while 循环里出不来。
CPU 想收一个字节,但 RDR 还没收到数据(RXNE=0),硬件还没收到货。CPU 就只能在循环里一直问:"RXNE 变成 1 了吗?变了吗?"直到 RXNE=1,CPU 才读数据,然后继续干别的事。