从寄存器层面重学STM32(5)——串口USART理论部分

一、前言

前面我们学习了GPIO、AFIO、RCC、时钟树以及EXTI等知识,以及初步了解了STM32自己能完成什么事情了,现在我们学习一下串口通信,彻底搞懂单片机使用串口,与外界通信的原理。我是跟着铁头山羊和江科大的教程综合学习的。2位伟大的老师!

二、通信协议

我们都清楚,人与人之间通信都需要语言,语言就像是一种通信协议,中国人和中国人之间规定:"我"是什么意思,"再见"是什么意思,"你好"是什么意思;那英国人和英国人不能用中国人与中国人的通信协议了,他们用自己的"I"表示我,"bye"表示再见,"hello"表示你好,这就是通信协议。

所以,如果要让单片机与外界通信,就需要规定通信协议,比如CAN的通信协议,I2C的通信协议,串口的通信协议等等,就看单片机要用什么与外界通信了。

就比如单片机要用串口与外界通信,那么就要遵守串口的通信协议。

串口的通信协议

串口的通信协议比较简单,分为:起始位,数据位,校验位(可不选),停止位。

起始位:串口的Tx空闲时,都是高电平,如果需要发信息了,就需要发起始位,所以起始位是拉低Tx的电平,即起始位就是一位低电平

数据位:数据位分2种,根据长度分成长度为8和长度为9的数据位,数据就在这里发送,发送的数据内容根据ASCLL码表发送。

校验位:校验位包含在数据位里面,占1位,我们在配置串口时可以选择使用或者不使用校验位。比如长度为8的数据位里,我们使用校验位的话那么实际有效的数据只有7个bit,不足1字节

停止位:停止位为高电平,放在数据(含校验)之后,表示一帧结束。发完停止位,若继续发送,就立刻拉低 TX 产生起始位;若无数据发送,TX 持续高电平,保持空闲。串口可配置 1/1.5/2 位停止位,最常用 1 位。

这里拿铁头山羊老师教程里的例子为例,串口发送十进制数27和发送字符串"Hello"

注意,串口发送一个字节,先传最低 bit(LSB first),比如串口发送0001 1011,是先发送1-1-0-1-0-0-0-1,从最低位的bit开始发送!!

如果是输入数据的话,起始位和停止位和发送数据一样,只是要求在时钟高电平接收数据,保持同一个波特率。

奇校验与偶校验

校验方式有这2种

奇校验和偶校验原理差不多,比如我串口发送0x1100 0101,采用奇校验,那么校验位就需要补1,,保证数据位加校验位'1'的个数为奇数,接收方收到时就会判断'1'的个数是不是奇数,如果是说明发送正确。

如果采用偶校验,校验位就补0,保证数据位加校验位'1'的个数是偶数,接收方同样需要检查。

所以串口通信有4种方式,根据数据位长度和是否需要校验位决定

数据位 校验位 有效数据 bit 说明
8bit 关闭 8bit 最常用,无校验,一字节完整数据
8bit 开启 7bit 剩下 1bit 作为校验位
9bit 关闭 9bit 多用于多机通信,地址标记位
9bit 开启 8bit 8bit 有效数据,1bit 校验位

三、USART收发流程

串口是全双工:发线 TX、收线 RX 互相独立,可以一边发、一边收,互不耽误。
收发本质:发送就是把并行的一个字节数据,拆成一串比特,按约定速度,串行送到线上;接收就是把线上一串串行比特,重新拼接成并行数据,拼成一个字节交给 CPU。
这是USART的框图,我们主要看上面的部分。

发送流程

CPU 先把数据放入发送数据寄存器 TDR,此时查看发送移位寄存器的状态,如果发送移位寄存器为空,就直接把 TDR 里的数据整体搬运到发送移位寄存器,再由发送移位寄存器按照低位先行的规则,逐位把比特送到 TX 引脚;如果发送移位寄存器正在工作、里面还有数据,就先等待移位寄存器把当前这一帧全部发送完毕、变空之后,再接收 TDR 里面的数据。

CPU 持续监测 TDR 的状态,当 TDR 变空时就会产生 TXE 提示,代表可以放入下一个新数据,只要及时往 TDR 写入新字节,就能在移位寄存器发完上一帧停止位之后立刻接续发送下一帧,实现不间断连续发送,直到所有数据发送完成,移位寄存器送出停止位后,就会产生 TC 提示,代表当前这一帧已经完整送到 TX 线上、TX 回到空闲状态。

接收流程

接收移位寄存器一直盯着 RX 引脚的电平,一旦抓到下降沿也就是起始位,就按照约定的波特率逐位采集线上比特,低位先行,先收到的数据放入低位,依次收下数据位、校验位、停止位,等一帧全部采集完成,就把拼好的完整字节整体送入 RDR,同时产生 RXNE 提示,告诉 CPU,RDR 里面已经收到新数据,等待 CPU 读取;如果 CPU 迟迟不把 RDR 里的数据取走,新的一帧又接收完成,RDR 放不下新数据,就会触发溢出错误,造成数据丢失。

四、USART寄存器

USART和其他外设寄存器原理差不多,肯定都有状态寄存器、控制寄存器和数据寄存器三大类,具体有

USART_SR 状态寄存器(Status Register) ------ 存储USART状态

USART_DR 数据寄存器(Data Register) ------ 存储收发数据(TDR/RDR 复用地址)

USART_BRR 波特率寄存器(Baud Rate Register) ------ 设置波特率

USART_CR1 控制寄存器 1 ------ 总开关、字长、校验、中断使能

USART_CR2 控制寄存器 2 ------ 停止位配置

USART_CR3 控制寄存器 3 ------ 流控、DMA等相关

状态寄存器**(USART_SR)**

只读寄存器,每一位记录当前USART的状态我们最常用的,比如:

PE:parity error,校验错误,如果为1时,说明出现奇偶校验错误。
RXNE:Rx no end,读数据寄存器非空,如果为1,说明收到数据了,可以读出数据,反之没有收到数据,不能读。
TC:Tx complete,发送完成,如果是1,说明发送完成,当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置'1'

TXE:Tx end发送结束,如果是1,说明发送结束,发送数据寄存器为空。

数据寄存器**(USART_DR)**

在寄存器层面,DR只有8位,但是在STM32硬件层面,TDR(发送数据寄存器)和RDR(接收数据寄存器)是独立存在2个寄存器的,DR既是TDR(发送数据寄存器),也是RDR(接收数据寄存器)。

那进行读写操作时,STM32怎么分清楚是读数据还是写数据,数据应该放在哪个寄存器呢?这就与指令知识有关了,一个指令包含 "要操作的地址和读写操作",比如指令是"操作USART_DR 寄存器,写操作",那么数据放到DR寄存器,但是在硬件上其实是放在TDR寄存器;如果指令是"操作USART_DR寄存器,读操作",那么数据依旧是放到DR寄存器,但是硬件上其实是放在RDR寄存器。

进行写操作:写DR

把数据赋值到DR寄存器里,但实际上是写入TDR寄存器,此时,如果发送移位寄存器为空,即SR寄存器TXE 位为1,则立马把TDR里的数据放入发送移位寄存器,一位一位的移到Tx引脚;如果发送移位寄存器正在发送数据,即SR寄存器TXE位为0,那么就等待发送移位寄存器发送完数据之后,再把数据放入发送移位寄存器。当数据全部发送完成,最后一帧数据发送了停止位,串口进入空闲状态时,SR寄存器的TC标志位置1,表明发送完成。

注意:TXE置1,不意味着数据发完了,只是说发送移位寄存器发完一帧数据了,TDR可以往发送移位寄存器传下一个数据了,可能还会有下一帧数据,当TDR的数据放入发送移位寄存器时,TXE置1;但是TC位才是意味着数据正式发送完了,最后一个数据的停止位之后,Tx拉高,进入空闲状态,则TC置1。

进行读操作:读DR

读取DR寄存器里的数据,但实际上是读取RDR里的数据。具体流程是,数据从Rx引脚来,把Rx引脚的数据一位一位的存入接收移位寄存器,收满一帧数据之后,再整体放到DR寄存器,也就是RDR寄存器,此时SR寄存器的RXNE位硬件置1,表明RDR接收数据寄存器非空,然后由CPU通过数据总线读走数据,此时SR寄存器的RXNE位硬件置0,表明RDR接收数据寄存器空。

注意:如果RDR寄存器的数据还没被 CPU 读走,即此时RXNE=1,新的一帧又收好了要往 RDR 存,就触发 ORE 溢出错误,新数据覆盖旧数据。

波特比率寄存器**(USART_BRR)**

用来计算串口的波特率,波特率由串口收到的时钟,BRR寄存器(也就是分频系数DIV)的值共同决定。

寄存器分成两部分:高 12 位是 DIV_Mantissa(整数部分),低 4 位是 DIV_Fraction(小数部分),合起来就是分频系数 DIV。

我们看这个图,假设USART的输入时钟是72MHz,经过下面的波特率发生电路,我们只需要配置BRR寄存器来设置分频器里的值,再经过固定的16倍分频,得到115200的波特率。

计算BRR的值:

假设分频器为x,那么72Mhz/x/16 = 115200,这样就能算出x = 39.0625,这样,,把39.0625换算成二进制0000 0010 0111 0001,就能得到BRR的值了,BRR前12位为整数,后4位为小数

控制寄存器****1(USART_CR1)

这里只截取部分寄存器描述了

这个寄存器是非常重要的,包括串口数据字长但是,是否实验校验位,校验位选择奇校验还是偶校验,是否使能UART,是否允许产生中断,允许产生哪种类型的中断,是否允许接收或者发送?这些都是在这个寄存器控制的

一般常用的位有以下几个

  1. UE(bit13):串口整体使能,配置好其他位之后,最后打开
  2. M(bit12):数据字长,配置0,字长=8 位,1=9 位
  3. PCE(bit10):校验使能,要不要校验就靠它
  4. PS(bit9):奇偶选择,PCE 开启才生效,0 偶 1 奇
  5. TXEIE(bit7):TXE 中断使能(发送寄存器空中断)
  6. TCIE(bit6):TC 中断使能(发送完成中断)
  7. RXNEIE(bit5):RXNE 中断使能(收到数据中断,最常用)
  8. TE(bit3):发送使能
  9. RE(bit2):接收使能

控制寄存器****2(USART_CR2)

这里只截取部分寄存器描述了。

这个寄存器主要是设置在串口同步模式下的一些配置,大部分位只有打开同步模式配置才有意义,我们只需要重点中断停止位的配置即可。

bit13、bit12 STOP 1:0:停止位配置

00:1 位停止位,默认,蓝牙、串口助手、绝大多数模块都用这个

01:0.5 位停止位

10:2 位停止位,远距离通信、一些老协议用来增加间隔、提升容错

11:1.5 位停止位

控制寄存器****3(USART_CR3)

这个寄存器常用到的就是位6和位7,DMA使能接收和DMA使能发送,如果需要用DMA转运收发的数据的话,就需要用到这2位。

这里面的有些位涉及到流控的概念,流控就是用来防止收得慢的一方被数据淹没、丢数据,收发双方互相通知对方 "能不能继续发"。

串口流控分两种:软件流控 XON/XOFF 、硬件流控 RTS/CTS(对应 CR3寄存器 里那两个位)。

硬件流控需要多加2条线,软件流控则根据收到的数据:收到 XON(0x11),继续发,收到 XOFF(0x13),停止发送。所以我们在使用软件流控时,避免传输0x11和0x13,以免被识别成流控信号。

一般高速波特率、大批量连续传输、接收端处理速度比较慢(比如一边收数据一边存 Flash),容易溢出丢数据,这时候加上硬件流控。

保护时间和预分频寄存器**(USART_GTPR)**

USART_GTPR 是保护时间与预分频寄存器,内部分为 GT 保护时间段和 PSC 预分频段,它不参与常规异步串口的波特率生成,只在 LIN 总线模式和智能卡通信模式下生效,GT 用来设置帧与帧之间需要预留的保护间隔时长,PSC 负责为这两种专用模式提供独立的预分频,产生对应功能所需要的采样时序,我们平时使用最常见的异步串口收发时不需要配置这个寄存器,保持复位默认值即可。

相关推荐
女神下凡1 小时前
芯参谋(83):AliOS Things_驱动开发指南
arm开发·驱动开发·单片机·嵌入式硬件·设计规范·1024程序员节
女神下凡2 小时前
芯参谋(84):Linux eMMC 驱动开发指南
linux·运维·arm开发·驱动开发·单片机·嵌入式硬件
szxinmai主板定制专家13 小时前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x
HQB202616 小时前
屹晶微电子 EG1130|2‑24V 输入 / 最高 28V 输出 内置 MOS 异步升压 DC‑DC|SOT23‑6|摄像头 / 车充 / 电池充电电源
嵌入式硬件·硬件工程
泛凡(Linyongui)17 小时前
基于 CW32L010 的智能厨卫调温旋钮方案--低成本 EC21 编码旋钮全解析
单片机·嵌入式硬件·c#
十年磨一剑~18 小时前
Linux 内核中断处理机制与软硬件协同流程
linux·嵌入式硬件
糖糖单片机设计19 小时前
基于单片机的热水器节能控制系统
单片机·嵌入式硬件
数字新视界19 小时前
数字孪生技术赋能智能化转型与创新实践
嵌入式硬件·物联网·系统架构·机房管理·动力与环境监控系统
HQB202620 小时前
屹晶微电子 EG1195|10‑120V/10A+ 外置 MOS 异步降压控制器|ESOP‑8|电动车转换器 / 快充 / 工业电源
嵌入式硬件·硬件工程