打印
[应用相关]

STM32-串口通讯工作原理

[复制链接]
2270|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32 USART 简介
STM32芯片具有多个USART外设用于串口通讯,USART(通用同步异步收发器)能够灵活地与外部设备进行全双工通讯。USART的全称“通用同步异步收发器”,也就是说他可以同步通信也可以异步通信。但是我们实现串口打印调试信息到电脑,其实只用到了他的异步通信的功能。

USART除了有串口功能,它满足外部设备对工业标准NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器提供了多种波特率,使得它的应用更加广泛。它还支持同步单向通信和半双工单线通信;还支持 LIN(局域互连网络)、智能卡协议与 IrDA(红外线数据协会) SIR ENDEC 规范,以及调制解调器操作 (CTS/RTS)。而且,它还支持多处理器通信。所以说USART还是很强悍的,我们不可能一一讲解这些功能,其他功能还有待大家一起去研究。具体这些功能的详细介绍可查看《STM32F4xx中文参考手册》26章通用同步异步收发器(USART)。
USART框图分析

此图我们可以分为四部分讲解分为引脚讲解、波特率发生器、USART控制单元、数据交换相关寄存器。

使用特权

评论回复
沙发
工程师犹饿死|  楼主 | 2021-9-28 13:37 | 只看该作者
1.USART功能引脚
Tx:发送数据输出引脚

Rx:接收数据输入引脚

SW_Rx:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。

nRST:请求以发送(Request To Send), n 表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高电平。该引脚只适用于硬件流控制。

nCTS:清除以发送(Clear To Send), n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。

SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

STM32F411CCU6一共有3个USART,USART1和USART6时钟来源与APB2总线时钟,其最大频率为100MHz, USART2来源于APB1总线时钟,其最大频率为50MHz。也就意味着他们的最大通讯速率也是不同的。

使用特权

评论回复
板凳
工程师犹饿死|  楼主 | 2021-9-28 13:39 | 只看该作者
2.USART波特率发生器
看USART内部框图2部分,USART的发送器速率控制与接收器速率控制共用一个波特率寄存器(USART_BRR),波特率寄存器里存放的是时钟分频值它一共16位,分为整数部分DIV_Mantissa[16:5]和小数部分DIV_Fraction[4:0]两部分。 USART通信所需波特率是对相应总线时钟分频然后一系列计算所得到的。USART波特率计算公式如下:

波特率计算公式

fck:系统总线时钟。USART1和USART6在APB2总线下,USART2在APB1总线下

0VER8:是由USART_CR1的第15位设置。O:16倍过采样;1:8倍过采样

USARTDIV:波特率分频系数,USART_BRR配置得到。USARTDIV的计算公式

USARTDIV = DIV_Mantissa + (DIV_Fraction/8 * (2-OVER8))

使用特权

评论回复
地板
工程师犹饿死|  楼主 | 2021-9-28 13:39 | 只看该作者
以下例题:

1.知USARTDIV(10进制)算出USART_BRR(16进制)的值

例如:如果OVER8=0, USARTDIV=25.62,求USART_BRR?

DIV_Fraction = 16*0.62 = 9.92 约等于10 = 0xA;

DIV_Mantissa = 25 = 0x19;

则USART_BRR = 0x19A;
————————————————

使用特权

评论回复
5
工程师犹饿死|  楼主 | 2021-9-28 13:41 | 只看该作者
2.知USART_BRR(16进制)算出USARTDIV(10进制)的值

例如:如果OVER8=0, USART_BRR=0x1BC,求USARTDIV?

DIV_Mantissa = 0x1B = 27;

DIV_Fraction = 12/16 = 0.75;

则USARTDIV = 27.75;

使用特权

评论回复
6
工程师犹饿死|  楼主 | 2021-9-28 13:46 | 只看该作者
3.USART波特率计算
例如:USART1通信的波特率位115200,0VER8=0,fck = 100Mhz,求USARTDIV?



解得USARTDIV = 54.253472,可根据上面公式算出DIV_Mantissa = 0x36, DIV_Fraction = 0x4,那么USART_BRR = 0x364

在计算 DIV_Fraction 时经常出现小数情况,经过我们取舍得到整数,这样会导致最终输出的波特率较目标值略有偏差。下面我们从 USART_BRR 的值为 0x364 开始计算得出实际输出的波特率大小。

由 USART_BRR 的值为 0x364,可得 DIV_Fraction=4, DIV_Mantissa=54,所以USARTDIV=54+4/16 =54.25,所以实际波特率为: 115207;这个值跟我们的目标波特率误差为 0.03%,这么小的误差在正常通信的允许范围内。

0VER8=1时,8 倍过采样时计算情况原理是一样的。此部分内容不必全部搞懂,波特率具体计算在库函数中都已完成,不用我们一一计算。
————————————————

使用特权

评论回复
7
工程师犹饿死|  楼主 | 2021-9-28 13:47 | 只看该作者
4.USART控制单元
看USART内部框图3部分,是整个USART外设的控制单元,包括发送控制器、唤醒单元、接收控制器,我们通过配置寄存器相应位来设置这些控制器的工作模式,USART的配置寄存器一共有三个我们在这里不一一讲解,我们看这个框图只需理解USART的大致工作过程即可,具体寄存器的配置我们直接调用库函数即可配置,无需我们一位一位的手动配置,如想仔细了解各寄存器的位详细意义,可参考《STM32f4xx中文参考手册》和《RM0383_STM32F411CCU6_Reference manual》。

发送控制器:工作在发送模式,它将按照程序设置的波特率、帧格式将CPU的数据或者DMA总线上的数据一位一位送到Tx引脚。

接收控制器:工作在接收模式,它将按照程序设置的波特率、帧格式将数据从Rx引脚一位一位的接收外部发来的数据并上传给CPU或者DMA。
————————————————

使用特权

评论回复
8
工程师犹饿死|  楼主 | 2021-9-28 13:49 | 只看该作者
5.USART数据寄存器和移位寄存器
看USART内部框图4部分,此部分是USART外设外部与内部总线和DMA联系的接口,4部分一共四个寄存器,发送模式用的“发送数据寄存器(TDR)”和“发送移位寄存器”,接收模式用的“接收数据寄存器(RDR)”和“接收移位寄存器”。其实TDR和RDR都属于数据寄存器(USART_DR)具体寄存机介绍看《STM32F4xx中文参考手册》。我们用的时候可以当成两个用。
————————————————

使用特权

评论回复
9
工程师犹饿死|  楼主 | 2021-9-28 13:49 | 只看该作者
USART发送过程:
     内部总线有数据需要发送时,

首先要使能发送即USART_CR1的TE位置1;

使用特权

评论回复
10
工程师犹饿死|  楼主 | 2021-9-28 13:50 | 只看该作者
接着内部总线的数据的一个字节写入“发送数据寄存器(TDR)”;(该操作将清零TXE位也就是发送数据寄存器非空,数据其他数据不可以写入)

使用特权

评论回复
11
工程师犹饿死|  楼主 | 2021-9-28 13:51 | 只看该作者
紧接着“发送数据寄存器(TDR)”中的数据一次性复制进入“发送移位寄存器”;(将TXE位置既发送数据寄存器为空,后续数据可以接着写入)

使用特权

评论回复
12
工程师犹饿死|  楼主 | 2021-9-28 13:56 | 只看该作者
“发送移位寄存器”将刚才“发送数据寄存器(TDR)”复制得数据一位一位的送到Tx引脚

使用特权

评论回复
13
工程师犹饿死|  楼主 | 2021-9-28 13:56 | 只看该作者
循环执行上面的操作,直到总线将最后一个数据写入“发送数据寄存器(TDR)”后,等待TC=1。这表明最后一帧的传送已完成。

使用特权

评论回复
14
工程师犹饿死|  楼主 | 2021-9-28 13:59 | 只看该作者
USART接收过程:
      Rx引脚有数据输入时,

使用特权

评论回复
15
工程师犹饿死|  楼主 | 2021-9-28 14:00 | 只看该作者
首先要使能接收即USART_CR1的RE位置1;

使用特权

评论回复
16
工程师犹饿死|  楼主 | 2021-9-28 14:02 | 只看该作者
然后Rx引脚移入数据的最低有效位,到“接收移位寄存器”;

使用特权

评论回复
17
工程师犹饿死|  楼主 | 2021-9-28 14:05 | 只看该作者
当“接收移位寄存器”8位满时,将数据一次性写入“接收数据寄存器(RDR)”;(该操作将RXNE置1既接收数据寄存器非空,总线可读取)

使用特权

评论回复
18
工程师犹饿死|  楼主 | 2021-9-28 14:05 | 只看该作者
总线发现RXNE=1时立即读取数据并将RXNE置零(注意接收期间每接收一个字节RXNE都置1)

使用特权

评论回复
19
工程师犹饿死|  楼主 | 2021-9-28 14:07 | 只看该作者
循环执行上面操作,直到Rx引脚将最后一字节数据传送入“接收数据寄存器(RDR)”后,等待总线读取完成。

使用特权

评论回复
20
wakayi| | 2021-10-11 11:12 | 只看该作者
连这个都能长篇大论  基本功很扎实啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

75

主题

886

帖子

1

粉丝