资讯详情

【正点原子MP157连载】第十四章 串口通信实验-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南

1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-318813-1-1.html 4)正点原子官方B站:https://space.bilibili.com/394620890 5)正点原子STM32MP157技术交流群:691905614 在这里插入图片描述

第十四章 串口通信实验

让我们学习这一章STM32MP使用串口的方法,并通过串口发送和接收数据。 本章将分为以下几个部分: 14.1、串口简介; 14.2、STM32MP1串口简介; 14.3、HAL库中串口相关API; 14.四、串口中断接收回显实验; 14.五、章节总结; 14.1 串口简介 在学习串口之前,让我们先了解一些数据通信的基本概念。 14.1.1 数据通信的基本概念 在单片机的应用中,数据通信是必不可少的一部分,如单片机与上位机、单片机与外围设备之间,它们都需要数据通信。由于设备之间的电气特性、传输速率和可靠性要求不同,有各种通信类型和通信协议。最常见的是:USART、IIC、SPI、CAN、USB等。接下来,让我们通信的基本概念。

  1. 数据通信模式 按数据通信方式分为串行通信和并行通信。串行并行对比如下图所示:

图14.1.1. 1数据传输模式 串行通信的基本特征是数据按顺序传输,至少只有一条传输线,所需传输线成本低,但每次只能传输1bit信号,如1Byte发送信号需要8次,传输速度低。串行通信具有较强的抗干扰能力,可用于远程传输,传输距离可从几米到几公里不等。 并行通信是指数据可以通过多条线同时传输,一次传输8bit、16bit、32bit对于更高的位数,需要8、16、32甚至更多的信号线。其优点是传输速率高,缺点是线路成本高,抗干扰能力差,适用于短距离、高速通信。 2. 数据传输方向 根据数据传输方向,通信可分为全双工、半双工和单工通信,其比较如下图所示:

图14.1.1. 2数据传输方式 单工是指数据传输只能沿一个方向传输,不能朝相反的方向传输; 半双工是指数据传输可以沿两个方向进行,但需要分时进行; 全双工是指数据可以同时双向传输; 注意全双工和半双工通信的区别:半双工通信共用一条线实现双向通信(分时),全双工使用两条线,一条用于发送数据,另一条用于接收数据。 3. 数据同步模式 通信可分为同步通信和异步通信。同步通信和异步通信的比较如下图所示:

图14.1.1. 3数据同步方式 同步通信要求双方共享同一时钟信号,并在总线上保持统一的时间顺序和周期来完成信息传输。其优点是:可实现高速、大容量的数据传输和点对点多点传输。缺点是:需要时钟和接收时钟严格同步,接收时钟允许误差小,硬件复杂。 异步通信不需要时钟信号,而是在传输的数据信号中添加一些同步信号,如起始位置和停止位置,以便接收端能够正确接收每个字符。在某些通信中,双方还需要就传输速率达成一致。其优点是:没有时钟信号硬件简单,双方的时钟可能有一定的误差。缺点是通信速度低,只适用于点对点传输。 4. 通信速率 在数字通信系统中,通信速率(传输速率)是指数据在信道中传输的速度,分为传信率和传码率两种。 传信率(Rb):通常使用每秒传输的信息量,即每秒传输的二进制位数Rb表示,单位为bit/s(即比特每秒),所以也叫比特率。 传码率(RB):通常使用每秒传输的码元数RB表示单位为Bd或Baud(即波特每秒),所以也叫波特率。 比特率和波特率的概念经常被混淆。比特率很容易理解。让我们看看波特率。波特率传输码元,码元是信息调制后的概念。一个码元可以表示为多个二进制比特信息。它们的关系可以用公式Rb=RBlog2M表示,M表示M进制码元。 在二进制系统中,波特率等于比特率,但其意义不同。例如,当以每秒50个二进制位数的速率传输时,传信率为50bit/s,传码率也为50Bd。比特率等于波特率的值,无需调制。替换公式:Rb=RBlog2M=RB,M=2。 如果6进制系统中,即使用调制技术,代入公式:Rb=RBlog2M=4RB,M=例如,波特率为1000Bd,在二进制系统中,比特率为100 bit/s;在四进制系统中,比特率为400 bit/s,也就是说,16进制码元表示4个二进制数,可见一个码元可以表示多个比特。 注:比特率单位也常用bps表示每秒传输的比特数(bit per second)。波特是波特的单位(Baud) 14.1.2 串口通信接口标准 在常用的串行通信接口标准中,有RS-232、RS-422和RS-485接口。

  1. 接口 (1)RS-232 电脑机箱后面一般有两个9芯或25芯接口,也叫DB9和DB25连接器符合RS-232C可用于连接标准串行接口MODEM设备或工业仪器仪表等,实现设备与计算机的快速交流。让我们先看看。RS下图为232接口DB9针接头,左公头1脚接母头1脚,其他脚也按数字对应。

图14.1.2. 1 RS232接口 RS-232C定义数据终端设备(DTE)和数据通信设备(DCE)串行二进制数据交换接口技术标准DB以9连接器为例,本标准接口的主要引脚定义如下:

表14.1.2. 1 RS232接口引脚信号 使用RS-232.对于一般的双工通信,只需要一条发送线、一条接收线和一条地线即可实现。这三条线构成共地传输,易产生共模干扰,抗噪声、抗干扰能力弱RS-232最大通信距离一般为15m。RS-以两个计算机通信为例,如果是近距离通信,两个接口可以直接连接:

图14.1.2. 两台设备近距离通信 若为长距离通信,则需要通过数据通信设备,如调制解调器。调制解调器是实现数字信号和模拟信号相互转换的设备。当计算机通过电话线连接到互联网时,发送人的计算机发出的数字信号通过调制解调器转换为模拟信号,接收人的计算机将传输的模拟信号转换为数字信号。两台电脑通过调制解调器实现通信。

图14.1.2. 33两台设备远距离通信 (2)RS-422 RS-422采用4条线(2条发送,2条接收,如果加上5条地线)和差输,全双工作可通过两对双绞线收发。RS-422是单机发送和多机接收的双向平衡传输,即总线上只允许一个主设备,从设备之间可以有多个通信。RS-422输出驱动器是双端平衡驱动器,具有电压放大功能,差异电路具有较强的抗干扰能力RS-422的传输距离较长,可达几十米到几公里。 (3)RS-485 RS-485是RS-422的变形,RS-485采用一对双绞线,可实现半双工作,但随着技术的发展,RS-485已经有了4线通信和4线通信RS-422具有实现多点、双向通信的能力。RS-485采用平衡发送和差分接收的方式,具有良好的抗噪干扰性,传输距离可达几十米到几公里。

图141.2. 4 RS485通信 下表中列出RS-232、RS-422和RS-485的对比: 类型 RS-232 RS-422 RS-485 4线 RS-485 2线

表14.1.2. 2 RS-232、RS-422和RS-485通信对比 2. 电气标准 在电子设计中,要保证不同设备的信号之间的通讯,就会涉及到通信协议以及电平标准,电平标准有很多,常见的电平标准有TTL、RS232、RS485、COMS和LVDS等。TT(Transistor-Transistor Logic),即晶体管逻辑集成电路,TTL电平是数字电路的一种通用接口电平标准,TTL电平信号直接与集成电路连接,下面我们以一张表格来区分串行通信的电平标准。

表14.1.2. 3电气标准 14.1.3 串口通信协议简介 串口通信是一种设备间常用的串行通信方式,串口按位(bit)发送和按位接收字节,一个字节(Byte)有8位,串口必须把这8位依次发送出去才可以完成一个字节的发送,比起按字节发送的并行通信速率要慢,效率较低,但是所需的线少,成本低,通信较稳定。

图14.1.3. 1串行通信和并行通信 串口通信协议是指规定了数据包的内容,双方需要约定一致的数据包格式才能正常收发数据。在串口通信中,常用的协议包括RS-232、RS-422和RS-485等。 随着科技的发展,RS-232在工业上还有广泛的使用,但是在商业技术上,已经慢慢的使用USB转串口了。现在的很多电脑已经没有DB9接口了,取而代之的是 USB 接口,所以就催生出了很多 USB转串口TTL 芯片,比如 CH340、PL2303 等。通过这些芯片就可以实现串口 TTL 转 USB。STM32的串口输出的是TTL电平信号,如果需要RS-232标准的信号可使用MAX3232芯片换成232电平以后,再通过一根USB转串口线与PC机的串口连接来实现通信。

图14.1.3. 2 USB转串口线 正点原子STM32MP157开发板就是用CH340C芯片来完成串口UART和电脑之间的通信的,开发板引出Type-C接口,硬件连接上非常方便,只需要一根Type-C 线就可以。理论上,USB2.0版本,Type-C接口最大传输速率为480Mbps,而USB3.0以上版本可以达到5Gbps或者更高的传输速率。如下图位号为USB_TTL的接口(Type-C接口)是我们后面串口实验要用到的接口。

图14.1.3. 3正点原子STM32MP157开发板USB_TTL接口 下面我们来学习串口通信协议,这里主要学习串口通信的协议层。 串口通信的数据包由发送设备的TXD接口传输到接收设备的RXD接口。在串口通信的协议层中,规定了数据包的内容,它由启始位、主体数据位、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成如下图所示。

图14.1.3. 4串口通信协议数据帧格式 串口通信协议数据包组成可以分为波特率和数据帧格式两部分。

  1. 波特率 串口通信分为同步通信(UART)和异步通信(USART),本章主要讲解的是串口异步通信(USART),异步通信是不需要时钟信号的,但是需要约定两个设备的波特率一致才可以正常通信。波特率表示每秒钟传送的码元符号的个数,所以它决定了数据帧里面每一个位的时间长度。两个要通信的设备的波特率一定要设置相同,常见的波特率是4800、9600、115200等。 根据波特率可以计算出每帧内部数据位各位之间的时间间隔(不是帧与帧之间的时间间隔),1s除以波特率可得时间,例如波特率为115200的时间间隔为1s /115200(波特率) = 8.68us。如果是9600波特率,则时间间隔约为104.2us。
  2. 数据帧格式 数据帧格式需要我们提前约定好,串口通信的数据帧包括起始位、停止位、有效数据位以及校验位。我们来看看这些数据位: 起始位和停止位 串口通信的一个数据帧是从起始位开始,直到停止位,通信的双方要约定一致。 数据帧中的起始位是由一个逻辑0 的数据位表示,当发出一个逻辑 0 信号,表示传输字符的开始。 数据帧的停止位是数据的结束标志,它可以用 0.5、1、1.5或 2个逻辑1的数据位表示(高电平)。 有效数据位 数据帧的起始位之后,接着就是数据位,也称有效数据位,这就是我们真正需要的数据,有效数据位可以是5、6、7或者8个位长构成一个字符,通常采用ASCII码表示,有效数据位从最低位开始传送,低位(LSB)在前,高位(MSB)在后。 校验位 校验位可以认为是一个特殊的数据位。校验位一般用来判断接收的数据位有无错误,检验方法有:奇检验、偶检验、0检验、1检验以及无检验。下面分别介绍一下: 奇校验是指有效数据位和校验位中是“1”的个数为奇数,比如一个 8 位长的有效数据为:10101001,总共有 4 个“1”,为达到奇校验效果,校验位应设置为“1”,最后传输的数据是8位的有效数据加上 1 位的校验位总共 9位。 偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为 4 个,为达到偶校验效果,所以偶校验位为“0”。 0 校验是指不管有效数据中的内容是什么,校验位总为“0”。 1 校验是校验位总为“1”。 无校验是指数据帧中不包含校验位。 我们一般是使用无检验位的情况。 空闲位 这里还注意到,在数据帧与帧之间有空闲信号,我们也称之为空闲位,空闲位处于逻辑 1 状态(高电平),表示当前线路上没有数据在传送,空闲位的长度是不定的。如下图是异步串口通信中,帧与帧之间的空闲间隔是随机的。

图14.1.3. 5空闲信号是不定长的 14.2 STM32MP1串口简介 14.2.1 STM32MP157串口资源

  1. 串口功能 STM32MP157的串口资源相当丰富,功能也相当强劲:支持8/16倍过采样、支持自动波特率检测、支持Modbus通信、支持同步单线通信和半双工单线通讯、支持LIN(局域互连网络)、支持FIFO模式、支持调制解调器操作、智能卡协议和IrDA SIR ENDEC规范、具有DMA等等。支持的功能有很多,我们后面的实验主要是使用串口接收中断。 STM32MP1的串口分为两种:USART(即通用同步收发器)和UART(即通用异步收发器),其中USART有USART1/2/3/6,而UART有UART4/5/7/8。UART是在 USART基础上裁剪掉了同步通信功能,只剩下异步通信功能。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用串口通信基本都是异步通信。如下表是USART和UART的功能对比表。

图14.2.1. 1STM32MP157的USART和UART的功能对比 2. 串口时钟 STM32MP1的每一路串口的时钟均可以来自于HSE、CSI和HSI、PLL4Q。而USART1时钟还可以来源于APB5和PLL3Q,USART2/3以及UART4/5/7/8的时钟还可以来自于APB1,USART6的时钟还可以来自于APB2,如下时钟树的部分截图所示(图中USART和UART标注的不是很正确)

图14.2.1. 2 STM32MP157的串口时钟来源 USART1只供Cortex-A7使用,而其余的串口Cortex-A7和Cortex-M4均可以使用,其中USART1的频率最大为133MHz,其余的6个串口的时钟最大为104.5MHz。其中,UART2/3/4/5/7/8挂在APB1总线上,UART6挂在APB2总线上,UART1挂在APB5总线上。下图是参考手册中串口数据的部分截图。

图14.2.1. 3 STM32MP157的串口时钟来源 14.2.2 USART寄存器 STM32MP1的串口和其它STM32串口一样,只要你开启了串口时钟,并设置相应IO口的模式,然后配置波特率、数据位长度、奇偶校验位等信息,就可以使用了。下面,我们就简单介绍下几个与串口基本配置直接相关的寄存器。

  1. 串口时钟使能寄存器 串口作为STM32MP157的一个外设,其时钟由APB1外设时钟使能寄存器RCC_MC_APB1ENSETR控制,我们后面实验中用到的串口4是在RCC_MC_APB1ENSETR寄存器的第16位,只要对该位写1即可使能串口4的时钟。在后面的实验中,通过在STM32CubeMX上配置,系统会自动为我们完成这步操作。

图14.2.2. 1 APB1外设使能MCU设置寄存器 2. 串口波特率设置寄存器

图14.2.2. 2串口波特率设置寄存器 串口波特率由USART_BRR寄存器来设置,它属于可读可写寄存器,仅低0~15位有效,其它位保留,仅当禁用USART(UE = 0)时才能写入该寄存器,在自动波特率检测模式下,该位由硬件自动更新。前面我们也说了,USART_BRR寄存器的第4~15位,BRR[15:4] = USARTDIV[15:4],剩下的第0~3位分情况: 当OVER8 = 0,BRR[3:0] = USARTDIV[3:0]。 当OVER8 = 1,BRR[2:0] = USARTDIV[3:0],右移1位。(BRR [3]必须保持清除状态,即为0)。 3. 串口控制寄存器 参考手册中将串口控制寄存器USART_CR1分为两种情况来介绍,一种是在启用FIFO模式下,另一种是在禁用FIFO模式下。这里我们以启用FIFO模式下的情况来介绍。

图14.2.2. 3串口控制寄存器 串口控制寄存器32位可设,大部分位可以由软件置1或者清除,我们这里仅分析常用的几位,其它位需要的时候可以再根据参考手册来分析。 第0位,UE为USART使能位。将UE位置1表示使能串口,清0表示禁止USART输出,并进入低功耗模式。 第2位,RE接收器使能位。0:禁止接收器; 1:使能接收器并开始搜索起始位。 第3位,TE表示发送使能位。 0:禁止发送器; 1:使能发送器。 第4位,IDLE 中断使能。0:禁止中断;1:当 USART_ISR 寄存器中的 IDLE=“1”时,生成 USART 中断。 第5位,RXNEIE/RXFNEIE接收数据寄存器非空/RXFIFO 非空中断使能。0:禁止接收器;1:当 USART_ISR 寄存器中的 ORE=“1”或 RXNE/RXFNE=“1”时,生成 USART 中断。 第6位,TCIE表示传输完成中断使能位。0:禁止中断;1:当 USART_ISR 寄存器中的 TC=“1”时,生成 USART 中断。 第7位,TXFNFIE表示发送数据寄存器为空/TXFIFO 未满中断使能,0:禁止中断;1:每当USART_ISR寄存器中的TXFNF = 1时,都会产生USART中断。 第8位,PEIE属于PE中断使能。0:表示禁止中断;1:当 USART_ISR 寄存器中的 PE=“1”时,生成 USART 中断 第9位,PS为校验位选择位。0:偶校验;1:寄校验。仅当禁用USART(UE=0)时,才可以写此位。 第9位,PCE为奇偶校验控制使能位。0:禁止奇偶校验控制;1:使能奇偶校验控制。仅当禁用USART(UE=0)时,才可以写此位。 第10位,PCE表示校验启用位。0:禁用奇偶校验控制,1:启用奇偶校验控制。仅当禁用USART(UE = 0)时才能写入该位。这里,如果启用了奇偶校验位的话,将计算出的奇偶校验位插入到MSB位置(如果M = 1,则为第9位;如果M = 0,则为第8位),并在接收到的数据上检查奇偶校验。 第12和第28位,M0、M1为字长设置位,M[1:0]=00,表示1个起始位,8个数据位,n个停止位;M[1:0]=01,表示1个起始位,9个数据位,n个停止位;M [1:0] ='10’表示1个起始位,7个数据位,n停止位;该位只能在禁止USART(UE = 0)时才可以写入,这里,n个停止位,n的个数,由USART_CR2的[13:12]位控制。 第15位,OVER8为过采样模式设置位。0:16倍过采样;1:8倍过采样。 第29位,FIFOEN为FIFO 模式使能位,0:禁止 FIFO 模式;1:使能 FIFO 模式。只有在禁止 USART(UE=“0”)时才能写入此位。 第30位,TXFIFO 为空时中断使能位。0:禁止中断;1:当 USART_ISR 寄存器中的 TXFE=“1”时,生成 USART 中断。 第31位,RXFIFO 变满时中断使能位。0:禁止中断;1:当 USART_ISR 寄存器中的 RXFF=“1”时,生成 USART 中断。 4. 数据发送与接收寄存器 STM32MP157的串口数据发送和数据接收由两个不同的寄存器组成,发送的数据在USART_TDR寄存器中,接收的数据在USART_RDR寄存器中,我们来看看这两个寄存器

图14.2.2. 4数据发送与接收寄存器 USART_RDR的其它位保留,只有第08位可读,其包含接收到的数据字符,具体多少位,由前面介绍的M[1:0]决定。类似的,USART_TDR的第08位包含要传输的数据字符。当我们需要发送数据的时候,往USART_TDR寄存器写入想要发送的数据,就可以通过串口发送出去了。而当有串口数据接收到,需要读取出来的时候,则必须读取USART_RDR寄存器的置。 我们前面有说过,在有效数据位中,一般是低位(LSB)在前,高位(MSB)在后,在启用奇偶校验的情况下进行接收时,在MSB位中读取的值为接收的奇偶校验位,什么意思呢?即当使能校验位(USART_CR1中PCE位被置1)进行发送时,写到MSB的值会被后来的校验位取代,当使能校验位进行接收时,读到的MSB位是接收到的校验位。对于启用奇偶校验的情况,USART的数据帧格式如下表所示:

表14.2.2. 1串口数据帧格式表 例如M[1:0]=00,PCE=1,停止位为1位的时候,数据有8位,不过第7位的值被校验位改写了,第7位是校验位了。数据位为7位和9位的情况也是类似。

图14.2.2. 5 MSB位会被后来的校验位改写 5. 串口状态寄存器 串口状态通过状态寄存器USART_ISR读取,其各位描述如图所示:

图14.2.2. 6串口状态寄存器 注: 可以在启用FIFO模式和禁用FIFO模式中使用同一寄存器。其中,如果启用FIFO /智能卡模式,则X = 2,如果启用了FIFO并且禁用了智能卡模式,则X = 0。 关于USART_ISR,我们也是介绍常用的几位,其它位大家可以根据参考手册来查阅。 第0位,PE表示校验错误位。0:无奇偶校验错误;1:奇偶校验错误。当在接收器模式下发生奇偶校验错误时,此位由硬件设置,在USART_ICR寄存器的第0位PECF中写入1即可将此位软件清除。 第1位,FE表示帧错误位。0:未检测到帧错误;1:检测到帧错误或 break 字符。当检测到帧错误时,该位将由硬件置位,在USART_ICR寄存器的第1位FECF写入1即可将此位软件清除。 第4位,检测到空闲线路。0:未检测到空闲线路;1:检测到空闲线路。当检测到空闲线路时,该位由硬件置 1,如果响USART_CR1 寄存器中的IDLEIE写1,可以清除此位。 第5位,RXNE表示读取数据寄存器非空/RXFIFO 非空。0:未接收到数据;1:已准备好读取接收到的数据。当RXFIFO不为空时,硬件会将RXFNE位置1,表示已经有数据被接收到了,并且可以从USART_RDR寄存器中读取数据,当RXFIFO为空时,RXFNE的值被硬件清0,也可以软件上通过将1写入USART_RQR寄存器中的RXFRQ位来清除RXFNE标志。 第6位,TC(传输完成),当该位被置位的时候,表示USART_TDR内的数据已经被发送完成了(如果TE位被复位且没有正在进行的传输,则TC位将立即置1),如果为0,表示没有传输完成。该位也有两种软件清零方式: 1)读USART_ISR,写USART_TDR。 2)向USART_ICR寄存器的TCCF位写1。 寄存器的介绍就到此了,因为寄存器位数比较多,每位控制的功能还不一样,文档里不能把每一位都介绍一遍,而且也是记不住的,所以,我们在需要的时候再查看参考手册。 第7位,TXFNF表示发送数据寄存器为空/TXFIFO 未满。0:数据寄存器已满/发送 FIFO 已满;1:数据寄存器/发送 FIFO 未满。 第15位,ABRF表示:自动波特率标志。如果已设置自动波特率,或者自动波特率操 作未成功完成时,此位由硬件置 1。 第16位,BUSY表示忙标志。0:USART 处于空闲状态(无接收);1:正在接收。 第23位,TXFIFO 为空。0:TXFIFO 非空;1:TXFIFO 为空。 第24位,RXFIFO 已满。0:RXFIFO 未满;1:RXFIFO 已满。 第26位,RXFT是RXFIFO 阈值标志。0:接收 FIFO 未达到编程的阈值;1:接收 FIFO 已达到编程的阈值。 第27位,TXFT为TXFIFO 阈值标志。0:TXFIFO 未达到编程的阈值;1:TXFIFO 已达到编程的阈值。 关于寄存器我们就介绍到这里了,遇到寄存器配置不要慌,HAL库都为我们处理好了底层驱动,我们只是从寄存器层面去理解USART是怎样控制串口工作的,下面,我们来看看USART的框图。 14.2.3 USART框图 下面我们先来学习USART框图,通过USART框图引出USART相关的知识点,对之后的编程也会有一个清晰的思路。

图14.2.3. 1 USART框图 为了方便大家理解,我们把整个框图用几根红线分成几个部分来介绍。

  1. 时钟与波特率 框图中①区域主要功能就是为USART提供时钟以及配置波特率。 时钟: 在USART框图中,可以看到有两个时钟域:usart_pclk 时钟域和usart_ker_ck 内核时钟域。 (1)usart_pclk是外设总线时钟,需要访问 USART 寄存器时,该信号必须有效。 (2)usart_ker_ck是USART时钟源,独立于 usart_pclk,由RCC提供。因此,即使usart_ker_ck 时钟停止,也可以连续对 USART 寄存器进行读/写操作。 usart_pclk和usart_ker_ck之间没有约束,usart_ker_ck可以比usart_pclk更快或更慢,唯一的限制是软件足够快地管理通信的能力。当USART在SPI从模式下工作时,它使用从外部主SPI设备提供的外部SCLK信号得出的串行接口时钟来处理数据流,usart_ker_ck时钟必须至少比CK输入上的时钟快3倍。 波特率: 波特率,即每秒钟传输的码元个数,在二进制系统中(串口的数据帧就是二进制的形式),比特率与波特率的数值相等,所以我们今后在把串口波特率理解为每秒钟传输的二进制位数。波特率的计算公式分为16倍过采样和8倍过采样: 在16倍过采样(或者在LIN模式)的情况下,波特率通过以下公式得出:

在8倍过采样的情况下,波特率通过以下公式得出:

以上公式中,Tx/Rx baud表示串口的波特率;usart_ker_ckpres为真正到USART的时钟频率(uart_ker_ck_pres是UART输入时钟除以预分频值后的数值),在usart_ker_ck不分频的情况下,USART1的时钟频率最大为133MHz,其余6个串口的时钟频率最大为104.5MHz。 USARTDIV是一个存放在USART_BRR寄存器中的无符号定点数,其值和USART_CR1寄存器的第15位有关,USART_CR1寄存器的第15位为OVER8,用于设置采样模式。为了从噪声中提取到一个有效目标信号,一般会采用一个频率比较高的信号去采样目标信号,如8倍过采样和16倍过采样,倍数越高,采样的次数越多,采样速度越慢,但是采样后得到的数据越准确。如8倍过采样的速度高达:usart_ker_ck_pres/8。 当OVER8值为0时,表示16倍过采样,此时BRR = USARTDIV; 当OVER8值为1时,表示8倍过采样,此时BRR[2:0] = USARTDIV[3:0],相对于OVER8值为0的情况,这里BRR右移了1位,变成BRR[2:0],此时BRR[3]必须保持清零; 不管是16倍还是8倍,BRR[15:4]都等于USARTDIV[15:4],且USARTDIV都必须大于或等于 16(10进制)。 下面举个例子说明来说明此公式: 当在16倍过采样时,如果需要得到 115200 的波特率,此时usart_ker_ckpre =104.5MHZ,那么可得:

计算出USARTDIV = 907(10进制),可解得 BRR = USARTDIV =388(16进制),那么需要设置USART_BRR 的值为 0x388。这里的USARTDIV是有余数的,我们用四舍五入进行取整,这样会导致波特率会有所偏差,而这样的小误差是可以被允许的。8倍过采样计算方法类似。 2. 收发数据 框图中②区域部分包含了USART双向通信需要的两个引脚: TX:发送数据输出引脚。 RX:接收数据输入引脚。采用过采样技术进行数据恢复,用于区分有效输入数据和噪声。 USART_TDR是USART发送数据寄存器,要发送什么数据,就往这个寄存器里写数据即可,其低9位有效。USART_RDR是USART接收数据寄存器,包含接收到的数据字符,要接收什么数据,读这个寄存器即可,其低9位有效。 USART有一个发送 FIFO (TXFIFO) 和一个接收 FIFO (RXFIFO),所以USART可以工作在FIFO 模式下,可以通过将 USART_CR1寄存器中的 FIFOEN(第29位)置 1 来使能 FIFO 模式。RXFIFO 的默认宽度为 12 位,即最大9位数据+1位奇偶校验位+1位噪声错误+1位帧错误标志。如果使能FIFO,写入到发送数据寄存器 (USART_TDR) 中的数据会在 TXFIFO 中排队,然后再通过TX移位寄存器发送到RX移位寄存器,再由RX移位寄存器发送到RxFIFO,然后USART_RDR寄存器从RxFIFO中获得数据。 向 USART_TDR 中写入要发送的数据前,发送使能位 (TE) 先置 1以激活发送器功能,发送移位寄存器(USART_TDR)中的数据在 TX 引脚输出,默认情况下,先发送数据的最低位(LSB),相应的时钟脉冲在SCLK 引脚输出。一旦向发送数据寄存器中写数据,UART的BUSY位开始有效,当从发送移位寄存器发送最后一个字符(包括停止位)才变无效。 RX接收字符时,如果已禁止 FIFO 模式,则,RXNE位置1,表明移位寄存器的内容已传送到 RDR,也就是说,已接收到并可读取数据;如果已使能 FIFO 模式,则RXFNE位置1,这表示 RXFIFO 非空,读取 USART_RDR会返回输入到 RXFIFO 中的最早数据。 发送器可发送 7 位、8 位或 9 位的数据字,具体取决于 M 位的设置,通USART控制寄存器1(USART_CR1)的 M位(M0:位 12,M1:位 28)来设置: 7 位字符长度:M[1:0] =“10” 8 位字符长度:M[1:0] =“00” 9 位字符长度:M[1:0] =“01” 每个字符从起始位开始到可配置数量的停止位终止,停止位的数量可配置为 0.5、1、1.5 或 2位。在默认情况下,信号(TX 或 RX)在起始位工作期间处于低电平状态。在停止位工作期间处于高电平状态。如果发送期间复位TE 位会冻结波特率计数器,当前发送的数据随即丢失,使能 TE 位时,将发送空闲帧,空闲帧发送将包括停止位。 3. 控制寄存器 框图中③区域部分,我们可以通过控制寄存器控制USART数据的发送、数据接收、各种通信模式的设置、中断、DMA 模式还有唤醒单元等。前面部分我们已经介绍了对应的寄存器。 4. DMA和IRQ中断功能 框图中④区域部分涉及两个接口:IRQ和DMA中断接口。 USART支持DMA传输,可以实现高速数据传输,具体我们会在DMA实验中为大家讲解。在 USART 通信过程中,中断可由不同事件生成,同时支持 USART 模块生成唤醒中断。常用的中断比如:发送数据寄存器为空、发送 FIFO 未满、发送完成、接收 FIFO 非空、接收 FIFO 已满等。有关所有 USART 中断请求的详细说明可以查看参考手册详细列表。 5. USART信号引脚 框图中⑤区域部分是USART信号的引脚。 在 RS232 硬件流控制模式下需要以下两个引脚: CTS(清除以发送):发送器在发送下一帧数据之前会检测 CTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。 RTS(请求以发送):如果为低电平,则该信号用于指示 USART 已准备好接收数据。 在 RS485 硬件控制模式下需要下面这个引脚: DE(驱动器使能):该信号用于激活外部收发器的发送模式。 在同步主/从模式和智能卡模式下需要以下引脚: CK:该引脚在同步主模式和智能卡模式下用作时钟输出,在同步从模式下用作时钟输入。 NSS:该引脚在同步从模式下用作从器件选择输入。 这些引脚我们暂时都没有用到,就给大家简单提一下。 注: DE和 RTS共用同一个引脚。 6. USART工作过程 前面我们分析了USART的框图和串口相关的寄存器,后面的开发中我们使用的是HAL库,HAL库中对这些寄存器的操作已经封装好了,这里我们从寄存器的层面大概了解USART的工作过程: (1)USART发送器 要发送字符,需遵循以下步骤: ①设置USART_CR1 中的 M 位以配置字长; ②设置USART_BRR 寄存器以选择所需波特率; ③配置USART_CR2 中的STOP[1:0]位以配置停止位数; ④将USART_CR1 寄存器中的 UE 位写入 1 以使能 USART; ⑤如果必须进行多缓冲区通信,请选择 USART_CR3 中的 DMA 使能 (DMAT); ⑥将 USART_CR1 中的 TE 位置 1 以使能发送器,在首次发送时发送一个空闲帧; ⑦在 USART_TDR 寄存器中写入要发送的数据。为每个要在单缓冲区模式下发送的数据重复这一步骤: —禁止 FIFO 模式时,向 USART_TDR 写入数据会将 TXE 标志清零; —使能 FIFO 模式时,向 USART_TDR 写入数据会为 TXFIFO 增添一个数据。当 TXFNF标志置 1 时,会对 USART_TDR 执行写操作。该标志会保持置 1,直到 TXFIFO已满。 ⑧将最后一个数据写入 USART_TDR 寄存器后,等待 TC =1(表示传送已完成)。也是分为两种情况: —禁止 FIFO 模式时,这表示最后一个帧的发送已完成; —使能 FIFO 模式时,这表示 TXFIFO 和移位寄存器均为空。

图14.2.3. 2串口发送时TC/TXE的行为 注: TXE位为1表示数据寄存器/发送 FIFO 未满,为0表示数据寄存器已满/发送 FIFO 已满; TC位为1表示传送已完成,为0表示未发送完成。 (2)USART接收器 接收器采用过采样来判断接收到的数据是否准确。在空闲状态时,传送线为高电平状态(逻辑1),而数据的起始位是逻辑0。当接收器检测到一个从1到0的跳变沿的时候,便视为可能的起始位(可能是存在干扰引起跳变),接收器是怎么去判断接收到的数据是否有效呢? 它采用了起始位检测序列来判断,当以16或8倍过采样时,此序列均为:1110 X 0X0X0 000,其中 X表示电平任意,可以为0或者1。如果检测到的序列不完整,则起始位检测将中止,接收器返回空闲状态,在该状态中等待下降沿。如果针对第 3 位、第 5 位和第 7 位进行首次采样时检测到这3位均为“0”;针对第 8 位、第 9 位和第 10 位进行第二次采样时仍检测到这3位均为“0”,则表示起始位有效。如下图所示:

图14.2.3. 3串口过采样时检测有效位 USART 接收期间,首先通过 RX 引脚移出数据的最低有效位(默认配置)。 字符接收步骤: ①设置USART_CR1 中的M位以配置字长; ②设置USART_BRR 寄存器以选择所需波特率; ③配置USART_CR2 中的STOP[1:0]位以配置停止位数; ④将USART_CR1 寄存器中的UE位写入 1 以使能 USART; ⑤如果将进行多缓冲区通信,请选择 USART_CR3 中的 DMA 使能 (DMAR)。 ⑥将USART_CR1的RE位置1以使能接收器开始搜索起始位。 14.2.4 GPIO引脚复用功能 芯片的外设有很多,而芯片的引脚资源却是有限的,如何在有限的引脚里拓展出更多的功能呢,这里就涉及到了复用。复用,就是说,一个引脚除了可以当做普通的IO口功能以外,还可以与一些外设关联起来,作为第二功能或者第三功能甚至更多的功能使用,不过在这些功能当中,在同一个时刻中只能选用其中一种功能来用,这样就不会导致冲突。

  1. 复用功能寄存器 前面我们是有介绍GPIO的部分寄存器,这里,我们再来熟悉和复用功能有关的两个寄存器: GPIOx_AFRL和GPIOx_AFRH(复用功能高位寄存器和复用功能低位寄存器) 有两个32位的复用功能寄存器(或者称为多路复用器),AFRL和AFRH,每4个位配置一个IO口的复用功能,AFRL配置第0至第7个IO口,AFRH 配置第8至第15个IO口,总共16和IO口,每个IO口可以选择AF0至AF15中的某个复用功能(具体根据数据手册中的复用功能映射表来确定)。复位后,多路复用器选择为复用功能AF0,复位后的IO口工作模式由MODER和AFRL/H寄存器共同决定。

图14.2.4. 1 AFRL寄存器 2. 复用功能映射表 IO口并不是想复用什么功能都可以,是有规定的,每个 IO 引脚的复用可以通过查阅数据手册的复用功能映射表来确定,例如我们需要配置PG11复用为UART4_TX,即多路复用器选择为复用功能AF6,则配置寄存器GPIOG_AFRL的AFR11的第12至第15位为0110。虽然可以在STM32CubeMX插件上可以使用图形界面来配置IO口的复用功能,但是它是怎么配置的我们还是要知道的。

图14.2.4. 2 Port G引脚复用 3. 复用功能选择宏定义 我们的开发板上,USB_TTL这个接口使用的是PG11和PB12,他们复用成UART4来用了,从上表中看出PG11可以复用为UART4_TX,是在AF6这一列。在HAL库的stm32mp1xx_hal_gpio_ex.h文件中可以找到这些复用的宏定义:

/** * @brief AF 6选择 */
#define GPIO_AF6_SPI3 ((uint8_t)0x06) /* SPI3复用功能映射 */
#define GPIO_AF6_SAI1 ((uint8_t)0x06) /* SAI1复用功能映射 */
#define GPIO_AF6_SAI3 ((uint8_t)0x06) /* SAI3复用功能映射 */
#define GPIO_AF6_SAI4 ((uint8_t)0x06) /* SAI4复用功能映射 */
#define GPIO_AF6_I2C4 ((uint8_t)0x06) /* I2C4复用功能映射 */
#define GPIO_AF6_DFSDM1 ((uint8_t)0x06) /* DFSDM1复用功能映射 */
#define GPIO_AF6_UART4 ((uint8_t)0x06) /* UART4复用功能映射 */
AF6的宏定义的值都是一样的,即都是(uint8_t)0x06,这些宏名只是为了区分是当做哪个外设而已,例如我们开发板的外设是串口4,所以就很容易选择到我们要复用的功能对应的宏定义,就是GPIO_AF6_UART4。具体的场景应用会在我们后面的实验中有所体现。

14.3 HAL库中串口相关的API 为了更好地使用HAL库来实现串口功能,下面我们来介绍HAL库中和本实验相关的结构体和API函数。 14.3.1 结构体和句柄 我们先来看看和串口相关的结构体和句柄。我们在介绍HAL库的时候有提到句柄(Handle),句柄在HAL库中是一个指针,指针指向地址,在调用API函数的时候,可以利用句柄来说明要操作哪些资源。在stm32mp1xx_hal_uart.h中有定义句柄和结构体。

  1. USART_TypeDef结构体 通过第5.2.3小节总线架构分析,我们知道UART4挂在APB1总线上,UART4的地址范围是0x40010000 ~ 0x400103FF,即UART4的基地址是0x40010000。我们前面也说过(第6.3.2小节),通过寄存器的基地址和偏移地址就可以访问一个寄存器,而HAL里边使用了大量的结构体来对寄存器进行了封装,如果我们要配置某个寄存器,只需要定义一个结构体指针,然后通过指针来配置这个结构体里面的成员变量,当结构体成员配置号以后,HAL库就会根据这些配置来初始化IO。USART_TypeDef结构体定义如下:
/* UART句柄结构定义 */
typedef struct
{ 
        
  __IO uint32_t CR1;    			/* USART控制寄存器1,地址偏移量:0x00 */
  __IO uint32_t CR2;    			/* USART控制寄存器2,地址偏移量:0x04 */
  __IO uint32_t CR3;    			/* USART控制寄存器3,地址偏移量:0x08 */
  __IO uint32_t BRR;    			/* USART波特率寄存器,地址偏移量:0x0C */
  __IO uint16_t GTPR;   	/* USART保护时间和预分频器寄存器,地址偏移量:0x10 */
  uint16_t  RESERVED2;  			/* 保留,0x12 */
  __IO uint32_t RTOR;   			/* USART接收器超时寄存器,地址偏移量:0x14 */
  __IO uint16_t RQR;    			/* USART请求寄存器,地址偏移量:0x18 */
  uint16_t  RESERVED3;  			/* 保留,0x1A */
  __IO uint32_t ISR;    			/* USART中断和状态寄存器,地址偏移量:0x1C */
  __IO uint32_t ICR;    			/* USART中断标志清除寄存器,地址偏移量:0x20 */
  __IO uint16_t RDR;    			/* USART接收数据寄存器,地址偏移量:0x24*/
  uint16_t  RESERVED4;  			/* 保留,0x26 */
  __IO uint16_t TDR;    			/* USART发送数据寄存器,地址偏移量:0x28 */
  uint16_t  RESERVED5;  			/* 保留,0x2A */
  __IO uint32_t PRESC;  			/* USART时钟预分频器寄存器,地址偏移量:0x2C */
  uint32_t  RESERVED6[239];  	/* 预留0x30-0x3E8 */
  __IO uint32_t HWCFGR2;  		/* USART 配置2寄存器,地址偏移量:0x3EC */
  __IO uint32_t HWCFGR1;  		/* USART 配置1寄存器,地址偏移量:0x3F0 */
  __IO uint32_t VERR;   			/* USART版本寄存器,地址偏移量:0x3F4 */
  __IO uint32_t IPIDR;  			/* USART标识寄存器,地址偏移量:0x3F8 */
  __IO uint32_t SIDR;   			/* USART时钟大小识别寄存器,地址偏移量:0x3FC */
} USART_TypeDef;
我们在前面有分析过,__IO在core_m4.h 文件中有定义,表示volatile,volatile表示强制编译器减少优化,告诉编译器必须每次去内存中取变量值。

#define __IO volatile 2. UART_InitTypeDef结构体 UART_InitTypeDef结构体主要用于设置串口的波特率、数据位长度、停止位数、过采样倍数等信息,通过对结构体成员的写操作即可实现这些设置,其定义如下:

/* UART初始化结构定义 */
typedef struct
{ 
        
  uint32_t BaudRate;           	/* 该成员配置UART通信波特率 */
  uint32_t WordLength;         	/* 指定在一帧中发送或接收的数据位数 */
  uint32_t StopBits;           	/* 指定发送的停止位数 */
  uint32_t Parity;             	/* 指定奇偶校验模式 */
  uint32_t Mode;                	/* 指定启用还是禁用接收或发送模式 */                                        
  uint32_t HwFlowCtl;          	/* 指定启用还是禁用硬件流控制模式 */
  uint32_t OverSampling;		 	/* 指定是否启用过采样8 */
  uint32_t OneBitSampling;     	/* 指定是选择单个样本还是三个样本 */
  uint32_t ClockPrescaler;     	/* 指定用于分频UART时钟源的预分频器值 */
} UART_InitTypeDef;

(1)BaudRate:设置波特率,一般设置为 2400、9600、19200、115200; (2)WordLength:设置数据位数,可选 8 位或 9 位。后面的实验我们设置为8位字长; (3)StopBits:设置停止位个数,可选0.5个、1个、1.5个和2个停止位,后面的实验我们选择1个停止位; (4)Parity:设置奇偶校验位,我们设定为无奇偶校验位。 (5)Mode:设置UART模式选择,可以设置为只收模式、只发模式、或者收发模式。我们选择设置为全双工收发模式。 (6)HwFlowCtl:硬件流控制选择,我们选择为无硬件流控制。 (7)OverSampling:过采样选择,可选择8倍过采样或者16过采样,我们可以选择16过采样。 3. UART_AdvFeatureInitTypeDef结构体 如下是UART高级功能初始化结构定义,ST新出的芯片添加了一些新特性,其中: 自动波特率检测是指某一方可以自动检测对方传输数据时的波特率,从而自动采用与对方相同的波特率进行数据传输,而不需要人工去设置波特率。 是否交换TX和RX引脚是否反转是指:RXD和TXD管脚互换。有时候,我们在外接串口引脚时,可能会犯低级错误,会将RXD和TXD引脚的两根线接反了,只能拆下来重新接。不过STM32MP1以及STM32H7系列的串口是支持RXD和TXD管脚互换的,通过设置SWAP位即可将RXD和TXD管脚互换。 指定TX/RX引脚的活动电平是否反转:通常默认串口高电平为逻辑1,低电平为逻辑0, 而在STM32的USART新特性中是可以将高电平设置为逻辑0,低电平设置为逻辑1的。 关于串口的新特性我们就介绍到这里,感兴趣的小伙伴可以自行查阅参考手册的介绍。 /* UART高级功能初始化结构定义 */

typedef struct
{ 
        
  /* 指定初始化哪些高级UART功能,可同时初始化几个高级功能 */
  uint32_t AdvFeatureInit;  
  uint32_t TxPinLevelInvert;      	/* 指定TX引脚的活动电平是否反转 */
  uint32_t RxPinLevelInvert;      	/* 指定RX引脚的活动电平是否反转 */
  uint32_t DataInvert;       /* 指定是否反转数据(正逻辑/正逻辑与负逻辑/反逻辑)*/
  uint32_t Swap;                  		/* 指定是否交换TX和RX引脚 */
  uint32_t OverrunDisable;        	/* 指定是否禁用接收溢出检测 */                                      
  uint32_t DMADisableonRxError;   	/* 指定在接收错误的情况下是否禁用DMA */                                    
  uint32_t AutoBaudRateEnable;    	/* 指定是否启用自动波特率检测 */                                      
  uint32_t AutoBaudRateMode;/* 如启用了自动波特率检测,请指定如何进行速率检测 */                                    
  uint32_t MSBFirst;              		/* 指定是否首先在UART线上发送MSB */                                   
} UART_AdvFeatureInitTypeDef;
4. UART_HandleTypeDef句柄
	UART_HandleTypeDef句柄是基于以上结构体以及HAL库的函数封装后的,其定义如下:
/* UART句柄结构定义 */
typedef struct __UART_HandleTypeDef
{ 
        
  USART_TypeDef        *Instance;        		 	/* UART寄存器基地址 */
  UART_InitTypeDef     Init;             		 	/* UART通讯参数 */
  UART_AdvFeatureInitTypeDef AdvancedInit;     /* UART高级功能初始化参数 */
  uint8_t              *pTxBuffPtr;       /* 指向UART Tx传输缓冲区的指针 */
  uint16_t             TxXferSize;        /* UART Tx传输大小 */
  __IO uint16_t        TxXferCount;      /* UART Tx传输计数器 */
  uint8_t              *pRxBuffPtr;       /* 指向UART Rx传输缓冲区的指针 */
  uint16_t             RxXferSize;        /* UART Rx传输大小 */
  __IO uint16_t        RxXferCount;      /* UART Rx传输计数器 */
  uint16_t             Mask;              	/* UART Rx RDR寄存器掩码 */
  uint32_t             FifoMode;          	/* 指定是否正在使用FIFO模式 */                                                            
  uint16_t             NbRxDataToProcess;   /* RX ISR执行期间要处理的数据数 */
  uint16_t             NbTxDataToProcess;   /* TX ISR执行期间要处理的数据数 */
/* Rx IRQ处理程序上的函数指针 */
  void (*RxISR)(struct __UART_HandleTypeDef *huart); 
/* Tx IRQ处理程序上的函数指针 */
  void (*TxISR)(struct __UART_HandleTypeDef *huart); 
  DMA_HandleTypeDef     *hdmatx;              /* UART Tx DMA句柄参数 */
  DMA_HandleTypeDef     *hdmarx;              /* UART Rx DMA句柄参数 */
#ifdef HAL_MDMA_MODULE_ENABLED
  MDMA_HandleTypeDef    *hmdmatx;            /* UART Tx MDMA句柄参数 */
  MDMA_HandleTypeDef    *hmdmarx;            /* UART Rx MDMA句柄参数 */
#endif /* HAL_MDMA_MODULE_ENABLED */
  HAL_LockTypeDef       Lock;                 	/* 定对象 */
/* 与全局句柄管理以及Tx操作有关的UART状态信息 */                                            
  __IO HAL_UART_StateTypeDef   gState;    	/*与Tx操作有关的UART状态信息 */                  
  __IO HAL_UART_StateTypeDef   RxState;     /* 与Rx操作有关的UART状态信息 */                                                        
  __IO uint32_t                ErrorCode;     /* UART错误代码 */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); 
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);      
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);       
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);           
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);            
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         
  void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); 
  void (* AbortReceiveCpltCallback 

标签: 晶体管输出型cts7简易式db9pin公头连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台