欢迎大家来到IT世界,在知识的湖畔探索吧!
作者:junziyang
设备与MCU的数据和指令交互是通过通信接口来实现的。STM32单片机集成了多种通信接口,如USART、SPI、IIC等。理解这些通信方式的工作原理,是使用单片机的基础。
(注:如非特別声明,以下笔记内容均针对STM32F103ZET6而言。不同型号,细节可能存在差别。)
一、 USART简介
USART全称为Universal Synchronous Asynchronous Receiver Transmitter,意为通用同步异步收发器。顾名思义,该模块可以以同步或异步方式,实现数据的接收或发送。USART是一种最为常用的串行通信(数据按一定的格式按位排队发送)接口。该协议虽然支持同步通信,但应用中多以异步通信为主,如通过RS232转USB与计算机的通信,蓝牙透传通信等。STM32的USART主要功能和特点如下:
- 采用NRZ(none return zero)行业标准
- 支持全双工异步通信
- 支持单线半双工通信
- 支持IrDA串行红外(SIR)编解码器,常规模式支持3/16位长度
- 支持LIN(local interconnection network),具备主同步断开发送能力和从断开检测能力。当USART硬件配置位LIN时,可生成13位断开符和10/11位断开检测符
- 具备智能卡模拟功能。支持ISO 7816-3标准定义的异步协议智能卡,支持0.5和1.5停止位
- 通过DMA可配置多缓冲器通信。采用集中式DMA,可在SRAM中预留接收/发送缓冲字节
- 采用分数波特率发生系统,可编程传输和接收波特率高达460800(4.5M bits/s)
- 数据字长可编程(8位或9位)
- 停止位可配置,支持1个或2个停止位
- 发射器为同步传输提供时钟
- 接收器和发射器使能位独立
- 支持丰富的传输检查标志和校验,包括:接收缓冲器满,发射缓冲器空,传输结束标志,校验控制(发送校验位;对接收到的数据字节进行校验),4个错误检查标志(溢出错误;噪声错误;帧错误;校验错误),10个带标志中断源(CTS改变;LIN断开;传输数据寄存器空;传输完成;接收数据寄存器满;传输线空闲检测;溢出错误;噪声错误;帧错误;校验错误)。
- 支持多处理器通信 – 如果地址不匹配,进入静默模式
- 从静默模式唤醒(通过空闲总线检测或地址标准检测)
- 具备2种接收器唤醒模式:地址位(MSB第9位),总线空闲
STM32F103ZET6共有3个USART和2个UART,UART功能与USART类似,只是仅支持异步通信。同步通信和异步通信的本质区别在于,通信时是否需要时钟同步。平时常用的串口通讯基本都是UART。
二、USART工作原理
STM32中用7个寄存器来实现USART的功能配置。寄存器地址映射与复位值如图1所示。
2.1 USART原理框图
图2所示为USART的原理框图。通过7个寄存器来实现功能的配置,图中加粗显示的USART_BRR、CR1等即为对应模块的配置寄存器。左下角是波特率发生器,通过配置USART_BRR寄存器设置波特率分频系数,对总线时钟PCLKx进行分频,产生接收器时钟,再经16分频产生发送控制器时钟。两路时钟分别送往接收控制器(Receiver control)和发送控制器(Transmit control)。两个控制器在中部5个寄存器的调控下,将控制信号分别发往两个移位寄存器和中断控制器。
2.2 功能引脚
USART共有6个功能引脚,双向通信时至少需要2个引脚(RX和TX)。各引脚功能简述如下:
- RX为接收数据输入端。接收器通过过采样技术来辨别数据和噪声,从而恢复数据。
- TX为发送数据输出端。当发射器被禁用时,此引脚恢复为IO端口。当发射器被开启且无数据待发送时,此引脚处于高电平。在单线和智能卡模式下,此IO同时担负发送和接收任务。
- SW_RX为单线输入引脚,这是一个内部引脚,在单线半双工模式下,RX和TX同时切换到SW_RX内部引脚。
- nCTS为停止发送(Cease To Send)引脚。该引脚为高电平时,当前传输结束后会阻断下一次数据传输。
- nRTS为请求发送(Request To Send)引脚。该引脚为低电平时,指示USART已经准备接收数据。
- CK为发送器时钟输出(Transmitter ClocK output)引脚。该引脚将发射器时钟输出,用于实现同步传输。时钟的相位和极性可以通过软件控制。在智能卡模式下,CK可为智能卡提供时钟。
2.3 USART数据格式
USART通信是一种串行通信,数据以帧(Frame)为单元,按位依次发送,低位优先。USART通信过程中共涉及3种帧结构:
- 数据帧(Data frame): 包含数据的帧。每个数据帧发送1个字节的数据(8个比特),除了数据位,每个数据帧包括1个起始位(Start bit)、1个可选校验位(Parity bit)和0.5-2个停止位(Stop bit)。数据位和校验位的总长度称为字长(Word length),所以根据有无校验位USART的可能字长为9或8。 很显然,起始位和停止位是为了区分相继传递的两个数据的。数据帧也称为数据包。
- 空闲帧(Idle frame): 一个全为“1”的帧。空闲帧长度包含停止位。在发送数据帧之前,USART的发送器会先发出一个空闲帧。空闲帧主要是用来同步的,如果接收端处于睡眠模式,收到空闲帧后会被唤醒,从空闲帧以后开始解析数据,这是USART通信协议的一部分。空闲帧发送出去的字符称为空闲字符。
- 断开帧(Break frame): 一个全为“0”的帧。断开帧包含1或2个停止位,即断开帧是长度为10或11位的低电平。断开帧之后发送器会插入1或2个停止位(“1”)来确认下一帧的起始位。断开帧也是用于同步的,是USART通信协议的一部分。断开帧发送出去的字符称为断开字符。
图3所示为9位字长和1位停止位的帧结构和时序,8位字长时不包括Bit8。时钟信号来自波特率发生器,一个时钟周期发送1个bit的数据。显然,为了正确解析信息,收发双方必须采用相同的波特率,波特率越高数据发送速度越快。
从图中可以看出,起始位期间TX引脚为低电平,而停止位期间TX引脚为高电平。停止位后是下一帧的起始位,依此次序按帧将数据发送到TX引脚。
发送和接收受同一个波特率发生器驱动,通过将接收器或发送器的使能位置1,来产生各自的时钟。异步通信并不是不需要同步,只是通过发送同步信号和约定波特率,收发双方可以使用各自的本地时钟,不需要一个共同的时钟来进行同步。
2.4 发送器 (Transmitter)
发送器的字长通过USART_CR1寄存器中M位来设置,发送器可以发送8位或9位字长的数据。发送使能位(CR1的TE位)被设置后,发送移位寄存器中的数据被依次输出到TX引脚,相应的时钟脉冲被输出到CK引脚。每个数据包包含一个字节,低位优先,每个字节前有一个起始位(长度为1个位周期的低电平)来作为前导,其后用一个停止位来结尾。
1. 发送端停止位的设置
停止位的长度可以在CR2寄存器中(STOP[1:0])进行配置,USART支持长度为0.5,1,1.5和2个周期的停止位。整数对应正常模式,小数对应智能卡模式。详情如下:
- 0.5 – 用于智能卡模式接收数据
- 1 – 默认停止位位数
- 1.5 – 用于智能卡模式收发数据
- 2 – 常规USART、单线模式、调制解调器模式
2. 发送器的配置步骤
常规模式下USART发送数据的基本过程如下:
- 向CR1寄存器的UE(USART enable)位写入1来使能USART;
- 设置CR1的M位来定义字长;
- 设置CR2的STOP[1:0]来配置停止位的个数;
- 如果采用多缓冲器通信,设置CR3的DMAT使能DMA。按多缓冲器通信要求配置DMA寄存器;
- 设置BRR(Baud rate register)寄存器来选择所需的波特率;
- 向CR1的TE位写入1,使能发送器并发送一个空闲帧作为第一帧;
- 将待发送数据依次写入DR寄存器(此操作会清除SR寄存器中的TXE位);
- 在向DR寄存器写入最后一个数据后,等待SR寄存器中的TC位(Transfer complete)被置1。在关闭USART或进入宕机模式时都要进行这种检查,以避免破坏最后一次传输。
数据从总线传入,依次经TDR和移位寄存器被发送出去。当向DR寄存器写入数据时,如果有数据正在传输,数据会被写入TDR缓存,在当前数据传输完毕,数据会被复制到移位寄存器。TDR与移位寄存器间数据是并行传输的。若写入数据时没有数据正在传输,则数据将会被直接写入移位寄存器。数据的传输状态可以通过查询相关的寄存器来获知。
3. 数据的发送
与发送过程密切相关的寄存器位有4个:TXE(Transmit data register empty)、TC(Transmision complete)、TXEIE(TXT interrupt enable)、TCIE(TC interrupt enable)。
- SR寄存器中的TXE位为1时,表明前一个数据已从TDR被移入移位寄存器并开始发送了,TDR寄存器已空。因此,此时向TDR写入下一个数据已不会覆盖前一个数据。
- 如果CR1寄存器中的TXEIE位开启,TXE被置1时会产生中断。此中断可以用来通知软件,将下一个数据写入TDR。
- 在数据传输过程中,SR寄存器的TC位处于低电平。如果一帧数据传输完毕(stop bit之后)且TXE位为1,TC位变为高电平,如果CR1寄存器中的TCIE位开启,则会产生中断。因为数据从移位寄存器发送出去需要一定的时间,因此在将最后一个数据写入DR寄存器后,必须等待TC=1。在此之前不可以关闭USART或让MCU进入低功耗模式,否则会破坏最后一个数据。显然,开启TCIE,在中断回调函数中执行后续这些操作,可以避免破坏数据。
图4所示为数据发送过程中相关寄存器的时序变化:软件使能USART时,TXE为高电平,第一个数据被软件写入DR寄存器,TEX被拉低;空闲帧发送完毕,stop bit下降沿触发第一帧数据F1被移入移位寄存器;因DR为空,TXE被拉高,软件检测到TXE=1将第二帧F2迅速写入DR,TEX又被拉低;重复此过程直到最后一个数据包被写入DR;软件开始等待TC=1;最后一个数据包被移入移位寄存器后,TXE开始持续为高电平;最后一帧发送完毕,在其stop bit下降沿因TXE=1,硬件将TC置1,传输过程结束。
从上述工作过程可以看出:
- 整个工作过程中,TXE和TC寄存器都是通过硬件置1,软件置0的。软件向DR写入数据,TXE和TC即被置0。在stop bit下降沿,TDR中的数据被移走后,TXE被硬件置1。
- 硬件在stop bit的下降沿通过检测TXE是否为1来判断数据传输是否结束。由于从TDR移走数据需要一定的时间,如果不是最后一个数据,TXE的置1有所滞后。stop bit下降沿TXE仍为0,所以TC保持低电平。而最后一个数据被移入移位寄存器后,TXE即持续为高电平,它被发送完毕后,在其stop bit下降沿会检测到TXE=1,因此硬件会将TC置1。数据发送完毕。
- 数据发送结束后,TX、TXE、TC均为高电平。
- 软件等待TC=1的时长至少为2个数据包的发送周期,即从最后一个数据包写入TDR开始,至TC=1结束。
空闲字符和断开字符的发送通过软件设置寄存器来实现。向CR1寄存器的SBK位写入1,会在完成当前传输后在TX发送一个断开字符。在断开字符的stop bit,硬件会将SBK位重置为0。USART会在最后一个断开字符的尾部添加一个逻辑1位,来确保对下一帧start bit的正确识别。空闲字符的发送通过设置CR1寄存器的TE位实现,发送第一个数据帧之前需要发送给一个空闲帧,来实现接收器的唤醒或同步。
2.5 接收器(Receiver)
接收器接收的数据字长可以为8位或9位,由CR1寄存器中M位进行设置。异步通信模式下,收发双方的波特率、字长、停止位必须一致。
1. 接收器的配置步骤
接收器配置过程的前5步与发送器配置过程完全一致。
- 向CR1寄存器的UE(USART enable)位写入1来使能USART;
- 设置CR1的M位来定义字长;
- 设置CR2的STOP[1:0]来配置停止位的个数;
- 如果采用多缓冲器通信,设置CR3的DMAT使能DMA。按多缓冲器通信要求配置DMA寄存器;
- 设置BRR(Baud rate register)寄存器来选择所需的波特率;
- 向CR1寄存器的RE(Receiver enable)位写入1,使能接收器,使其开始寻找起始位。
2. 起始位的检测原理
如前所述,每个数据包是以起始位(低电平)开始和停止位(高电平)结束的,识别起始位是正确接收和解析数据的前提。
起始位的检测原理如图5所示。USART接收器的采样频率是发送器波特率的16倍(参见图2)。自前一个包(数据帧或空闲帧)下降沿,到下一个包起始位结束,共有16次采用。为了避免噪声干扰,从接收到下降沿开始,分别判断此后第3、5、7和8、9、10次采用的值。如果两组采样全为0,则确认找到起始位,并将SR寄存器中的RXNE(Receiver data register not empty)置1,如果开启了RXNEIE,则会产生相应的中断;如果两组采样中,有非0值,但每组的3个采样值都至少有2个为0,仍判为有效起始位(RXNE置1,如果开启了中断则触发),但同时会将SR寄存器中的NE(Noise error)位置1,标明检测到噪声;如果非前两种情况,则停止检测,接收器恢复空闲状态,继续等待下一个下降沿。
3. 数据的接收
如图2所示,接收数据时数据先是存入接收移位寄存器(Receive Shift Register),然后再转入接收数据寄存器(RDR,receive data register)的,低位优先。移位寄存器与RDR间数据是并行传输的。与接收过程相关的关键寄存器位有2个:RXNE和RXNEIE。
- SR寄存器中的RXNE位为1时,表明移位寄存器的内容已被转移到RDR,可以被读取了。
- 如果CR1寄存器中的RXNEIE位开启,RXNE被置1时会产生中断。此中断可以用来通知软件,及时将RDR中的数据读取。
- 在单缓存模式(非DMA)中,软件读取DR寄存器时会将RXNE位清0。在下一个字符接收完成之前(移位寄存器被填满),RXNE必须被清0,否则会导致溢出错误。多缓存模式下,DMA读取DR寄存器也会将RXNE位清0。
- 数据位的值是根据第8,9,10三个采样点的值来确定的。详细情况见下面的噪声错误部分。
空闲字符会被当作正常字符来接收,如果设置了IDLEIE中断,接收到空闲字符时会触发该中断。断开字符则会被当作帧错误来处理。USART可以识别3种接收错误并根据设置触发相应的中断。
4. 噪声错误
为了区分有效的输入数据和噪声,异步USART接收器中采用了过采样技术。RX线上的输入电平会被以波特率的16倍进行采样。这样1个数据位中会有16个采样点。USART会用每个位中间的3次(第8,9,10次)采样值确定数据位的电平并判断数据是否有效。
如前所述,在找到有效起始位时会设置RXNE为1,在RNXE的上升沿会同时会设置NE位。如图6所示,如果NE为0,即起始位无噪声时,后续各位的取样中只有中间3次取样值全部相同才会被判定为有效数据。如果NE=1,接收到的位的值会根据中间3次取样的值按照少数服从多少的原则确定,并判定为无效数据。无效数据也会被从移位寄存器转入DR寄存器。在单缓冲器通讯情况下,噪声错误不会参数中断,但由于NE和RXNE是被同时设置的,RXNE可以触发中断。如果需要检查噪声错误,可以在该中断中实现。在多缓冲器通信情况下,如果已经设置了CR3寄存器中的EIE(Error interrupt enable)位,将产生一个错误中断。
通过读取SR寄存器,接着读取DR寄存器,可以复位NE标志位。
5. 溢出错误(Overrun error)
RDR每次收到数据硬件会将RXNE置1,数据被读取后RXNE被复位为0。如果数据没有被及时读取(RXNE=1),移位寄存器被充满后无法将数据转移到RDR,就会触发溢出错误。错误出现后:
- SR寄存器的ORE位会被置1;
- 如果开启了RXNEIE或同时开启了EIE和DMAR,会触发中断;
- 溢出错误期间,RDR中的数据不会被破坏,但移位寄存器中收到的数据会因被重写而丢失;
通过读取SR寄存器,接着读取DR寄存器,可以复位ORE标志位。
6. 帧错误
由于同步出错或因噪声太多,导致在预期的时间没有识别到停止位,就会产生帧错误。如前所述,当接收到断开帧时也会当作帧错误来处理。当检测到帧错误时:硬件会将SR寄存器的FE(Frame error)位置1。后续处理与噪声错误类似,但字节通信时也可以在RXNE相关的中断中进行检查。
通过读取SR寄存器,接着读取DR寄存器,可以复位FE标志位。
7. 接收端对停止位的处理
接收端停止位设置与发送端相同,也是通过CR2寄存器中STOP[1:0]位来设置。但由于接收端是过采样,要分情况处理:
- 0.5个停止位(智能卡接收) 因为在0.5个停止位的位置(第8和第9次采样中间)没有采样,导致这种情况下无法检测帧错误和断开帧。
- 1个停止位 用第8,9,10个采样点的值来确定停止位。
- 1.5个停止位(智能卡收发) 前0.5个周期不采样,对后一个时钟周期的中间3个取样点取样。如果从停止位上升沿开始计数,对应第16,17,18个采样点。详情查阅智能卡相关章节。
- 2个停止位 对第一个停止位的第8,9,10个采样点采用。
2.6 分数波特率的产生
1. 计算公式
USART的接收器和发送器的波特率是通过对外设总线的时钟频率分频得到的,计算公式如下:
其中fCK为USART所在外设总线的时钟频率,USARTDIV为分频系数,由USART_BRR寄存器进行设置。从上述公式可以看出,USART的最高波特率为外设总线APBx频率的1/16,原因在于接收端要16倍过采样来接收数据,采样频率不可能高于APBx频率。如图2右下角所示,USART的接收器和发射器的波特率是通过同一个寄存器进行配置的。为了支持分数波特率,BRR寄存器的低16位被分成了两部分:0-3位设置分数部分,4-15位设置整数部分。二者共同定义分配因子USARTDIV。
根据BRR寄存器的设置,USARTDIV的计算规则如下:
- 4-15位转为10进制,作为整数部分。整数部分的取值范围为0-4095;
- 0-3位转为10进制再除以16即为小数部分。之所以是16,是因为小数部分在寄存器中只占4位,所以能精确表示的小数只能是N/16,其中N的取值范围为0-15。
反之,根据系统时钟频率和要求的波特率,BRR寄存器的整数和分数部分分别按下列公式计算:
- UrtDIV = fCK/(16×baudrate)
- 整数部分:IntDIV = (u16)UrtDIV
- 分数部分:FrcDIV = (u16)[(UrtDIV-IntDIV)*16+0.5]
例如:APB2总线频率72MHz,要求波特率115200。计算结果:UrtDIV=39.0625,IntDIV=0d39(0x27),FrcDIV=0d01(0x01)。
受USARTDIV取值的限制,不是所有的波特率都可以精确的配置出来。波特率设置值与实际值之间有时会存在误差。图7所示即为常用波特率设置值与实际值之间的相对误差情况。
对STM32F1系列芯片而言,APB1总线的最高频率为36MHz,APB2总线的最高频率为72MHz。除了USART1挂载在APB2总线上外,其余USART/UART均挂载与APB1总线。从图2可以看出,常用的波特率设置115200,在36MHz情况下就会有0.15%的相对误差。通常时钟频率越低,具体波特率的精度也会越低。USART1的最高波特率可达4.5M bps。
2. 接收器时钟公差
异步通讯中,只有整个时钟系统的误差小于USART接收器容许的公差时数据才能被正确接收。误差的主要来源包括:
- DTRA:发送端引入的误差,例如发送端时钟的漂移
- DQUANT:接收端波特率量化误差
- DREC:接收端本地时钟的漂移
- DTCL:传输线引入的漂移,通常来源于收发器高-低、低-高时序切换间的不同步
为保证数据能被正确接收,上述4种误差总和必须小于USART接收器的公差。而公差又与三个因素有关:字长,即CR1寄存器的M=0或1;分数波特率,即BRR寄存器的低4位是否全为0;噪声帧的处理,忽略还是当作错误。根据这三个因素的不同,公差表分别如图8所示:
2.7 静默与唤醒
通过USART可以实现多处理器通信。为了减少USART的服务开销,可以让空闲的USART进入静默模式(mute mode),在需要与某个USART进行通信时,可以将其定向唤醒,而其余空闲USART不受影响。即使是两个USART之间的通信,在无数据传输时双方也可以进入静默模式,有数据传输需求时,提出需求的一方(软件唤醒)通过发送唤醒信号,激活对方。
USART的静默与唤醒共涉及3个寄存器功能位:CR1寄存器的WAKE和RWU、CR2的ADD[3:0]。WAKE位设置唤醒方式,根据WAKE位的不同,使USART进入或退出静默模式有两种方法:空闲总线检测(WAKE=0)和地址标记检测(WAKE=1)。
1. 空闲总线检测
空闲总线检测静默-唤醒示意图如图9所示。当WAKE=0时,通过向RWU(Receiver wakeup)位写入1可使USART进入静默模式。进入静默模式后,接收器停止接收数据,但仍会检测RX引脚上的输入信号,如果检测到空闲帧,硬件会清除RWU,USART被唤醒开始正常接收数据(RXNE位开始变化)。
- 在静默模式下收到的空闲帧不会触发IDLEIE中断,因为硬件不会设置SR寄存器中的IDLE位。
- 这种方式适合于同时需要唤醒多个USART的情形。只需发送一个空闲帧,所有WAKE=0且RWU=0的USART收到后都会被唤醒。
2. 地址标记检测
地址标记检测静默-唤醒示意图如图10所示。这种模式下通常将字长设置为9,最高位(MSB)用来作为数据和地址的标识符。当MSB=1时,数据包被解析为地址;而当MSB=0时,则解析为数据。地址包的低4位存储一个地址标记,USART收到地址包后会与CR2寄存器的ADD[3:0]中的地址进行比较。如果地址不匹配,硬件将RWU置1,进入/保持静默模式,RXNE不会被设置,也不会有中断产生;如果地址匹配,硬件将RWU置0,唤醒USART,在地址包中Stop bit的下降硬件会设置RXNE,后续字符会被正常接收。
- 地址包也会被接收,唤醒后收到的第一个字符是地址。
- 这种模式需要提前配置每个USART的ADD[3:0],为其分配一个地址(不一定唯一)。
- 这种方式是一种以地址包为前导的定向通信,通信对象更明确。每次只唤醒地址匹配的USART,如果有多个同地址的会被同时唤醒。
2.8 数据校验
奇偶校验是一种校验代码传输正确性的方法。根据被传输的一组二进制代码中“1”的个数是奇数还是偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。校验方式是通信双方提前约定好的。通过在数据包中的校验位来进行校验。发送方根据数据设置校验位,接收方接收数据后对校验位进行检查,从而确定传输代码的正确性。
通过将CR1寄存器的PCE(Parity control enable)位置1来使能奇偶校验,校验方式通过PS(Parity selection)位来设置:PS=0,偶校验;PS=1,奇校验。
需要说明的是,如果开启了奇偶校验,USART的字长包含1个校验位;如果同时开启了地址标记唤醒,数据位的最高位会被用作地址标记,这种情况下实际数据的位数比所设字长会少2位。注意合理设置,防止数据被修改或误用(比如数据包被解析为地址包)。
举例来说:如果设置字长9位,停止位1位,同时开启奇偶校验和地址标记唤醒,则最高位被校验位占据,剩余数据为的最高位会被当作地址标记位。实际数据占7位,设为1011011,如果选择偶校验,则校验位为0。整个数据包的内容为:10010110110,从左到右依次为停止位1、奇偶校验位0、地址标记0(这是数据帧)、数据位1011011、起始位0(数据传输低位优先)。
接收器收到数据后,会检查数据位中“1”的个数是奇数还是偶数,并按校验规则与校验位核对。如果不符表明传输出错(比如噪声干扰等),SR寄存器中的PE(Parity error)位会被置1,如果CR1中的PEIE(Parity error interrupt enable)开启,则会产生中断。
2.9 USART同步模式
USART可以以同步模式工作。向CR2寄存器的CLKEN(Clock enable)写入1即可开启同步模式。同步模式下,数据在TX引脚输出的同时,发送器时钟从CK引脚输出,但在数据包的起始位和停止位CK引脚上无时钟脉冲。
- 通过配置CR2寄存器的LBCL位,可以设置最后一个有效数据位(地址标记)是否输出时钟脉冲;
- 通过CR2寄存器的CPOL(Clock polarity)可以设置时钟的极性,即在传输窗口外CK引脚的电平是高(CPOL=1)还是低(CPOL=0);
- 通过CR2的CPHA位可以设置时钟的相位,即在时钟的第一个边缘进行数据捕获(CPHA=0),还是在时钟的第二个边沿进行数据捕获(CPHA=1)。CPOL和CPHA一起配合来产生需要的时钟/数据采样关系。
发射器的运作在同步模式下和异步模式下完全相同。只是TX引脚上的数据是与CK引脚上的时钟同步发出的。
接收器的运作在同步模式下与异步模式下不同。由于有同步时钟,因此不需要不需要进行过采样。而是在RE=1使能接收器后,数据在CK的上升沿或下降沿被直接采样。但必须重视建立时间(setup time)和保持时间(hold time)。
- 建立时间是指,采样时钟边沿到来之前,数据提前保持不变的时间;保持时间是指,采样时钟边沿到来之后,数据必须继续保持不变的时间。这两个时间与波特率有关,通常要求这两个时间不低于1/16个bit的时长。
- USART只支持主模式,即只能由它来输出时钟同步其他设备,而不能反过来。CK引脚永远都是输出端。
- 同步模式下CR2寄存器的LINEN位、CR3寄存器的SCEN,HDSEL和IREN位必须清零。相关寄存器位(包括LBCL、CPOL、CPHA)的设置都必须在TE和RE使能前完成,发送器和接收器使能后不能再修改这些位,否则可能会导致时钟工作不正常。
- CK和TX引脚一起运作,因此只有TE=1且数据已开始传输时才能提供时钟。在发送数据前是无法向异步模式中那样,提前发送一个数据进行同步的。
图11所示是USART同步通信的时序示意图。图示是M=1,即9位字长的情况,8位字长与此类似。
从图11可以看出,CPOL=0时,闲时电平为低电平,而CPOL=1时,闲时电平为高电平;CPHA=0时,第一个时钟沿采样,而CPHA=1时,第二个时钟沿采样。LBCL(Last bit clock)控制的是最后一个数据是否产生输出时钟脉冲。
2.10 单线半双工通信
单线通信的最大好处是只占一根线,通过分时收发(半双工)来实现通信。通过将CR3寄存器的HDSEL(half-duplex selection)位置1来选择半双工模式。在此模式下,CR2寄存器的LINKEN位、CLKEN位,CR3寄存器的SCEN和IREN位必须清零。
单线半双工模式下,TX和RX引脚在芯片内部被连通。HDSEL被写入1后,RX引脚被停用;在无数据发送时,TX引脚被释放。TX引脚在空闲或接收数据时跟一个标准的I/O口一样。所以在不被USART驱动时,TX引脚必须配置位浮空输入(或输出高开漏)。除此以外,通信与正常USART模式相似。由于只有一条线路,要由软件来负责避免出现线上冲突。特别需要说明的是,发送永远不会被硬件阻断,当TE=1时,只要有数据被写到DR寄存器,就会被发送出去。
2.11 硬件流控制
所谓硬件流控制,是指通过硬件发送控制信号来控制数据流的一种方式,相当于一种握手协议。主要是为了避免因双方处理速度不匹配或USART网络中多个发送器同时向一个接收器发送数据导致接收端溢出错误和数据丢失。硬件流控制的基本原理图如图12所示,在两个USART间增加了两条控制信号线,一个USART的nRTS连到另一个的nCTS(n表示低电平有效)。当接收端数据处理即将完毕时,通过nRTS端口向发送端发送RTS(Request to send)请求发送信号。而发送端的nCTS端口收到信号后,将其解读为CTS(Clear to send)允许发送信号,进而允许发送器继续发送数据。
RTS和CTS可以通过向CR3寄存器的RTSE(RTS enable)和CTSE(CTS enable)位写入1来独立开启。
1. RTS流控
图13所示为RTS流控过程示意图。如前所述,接收器接收数据时,数据先通过移位寄存器接收,当接收到Stop bit后,数据会被存入缓存RDR,RXNE=1。如果使能了RTS,在RXNE=1期间,接收器停止接收数据,nRTS输出高电平1,向发送器发出停止发送请求,发送器应当在当前帧发送结束后会暂停发送,直至收到新的发送请求。
数据被从RDR读取后,RXNE=0。如果使能了RTS,nRTS输出低电平0,向发送器发出新的发送请求。如果数据传输通畅,RXNE=1的时间很短,数据几乎是连续发送。如果发生特殊情况耽误了RDR中数据的读取(比如发生中断),nRTS=1,停止发送,防止丢失数据。
2. CTS流控
图14所示为CTS流控过程示意图。使能CTS后,发送器在发送下一帧前会检查nCTS输入端口的电平。如果nCTS有效(低电平)且TXE=0(TDR非空),则下一帧被发送;反之,则不会进行发送。如果nCTS在数据发送期间失效(变为了高电平),当前帧传输完成后会停止发送。如图14中所示,Data2发送期间CTS失效,Data3虽已被移入TDR,但Data2发送后会停止发送,等待CTS=0再开始发送Data3。从图14还可以看到,在Stop bit后,Data2被移入移位寄存器,TDR中有个短暂的empty期,即TXE=0的间隙。
使能CTS后,只要nCTS电平发生跃变,硬件就会自动将SR寄存器中的CTS状态位置1。如果设置了CR3寄存器的CTSIE位,则会产生中断。
三、 USART模式配置与中断
3.1 模式配置
STM32F103ZET6共有3个USART和2个UART。3个USART支持所有的模式,但2个UART只支持部分模式,而且两个UART支持的模式也存在差别。具体配置如图15所示。
3.2 事件与中断
图16所示为USART相关中断事件和标志位。共有11个中断标志和8个相关中断,其中前3个为发送器相关中断,其余为接收器相关中断。通过设置相关的控制位使能中断。USART的所有中断都连接到同一个中断向量。
四、USART寄存器
STM32F103ZET6中与USART相关的寄存器共有7个,地址映射与复位值表如图1所示。这些寄存器虽然都是32bit寄存器,但功能位没有超过16bit的。所以这些寄存器允许按半字或全字访问。
4.1 USART_SR 状态寄存器
USART_SR为状态寄存器(Status Register),用以管理USART相关的状态标志。
位置 |
名称 |
功能说明 |
9 |
CTS |
CTS flag nCTS引脚输入电平跳变(上升/下降)时,硬件将此位置1。软件写入0清除。若CR3寄存器中的CTSIE=1,会触发中断。USART4&5无此功能。 |
8 |
LBD |
LIN break detection flag LIN模式下检测到断开帧时,硬件将此位置1。软件写入0清除。若CR2寄存器中的LBDIE=1,会触发中断。 |
7 |
TXE |
TDR empty TDR寄存器中的数据被移入移位寄存器后,硬件将此位置1。向TDR写入数据会清0。若CR1寄存器中的TXEIE=1,会触发中断。 TXE=1,说明TDR已空,数据已转让发送移位寄存器,可缓存下一个待发送数据了。 注意:此位在单缓存发生时可用。不适用于DMA。 |
6 |
TC |
Transmission complete 数据帧传输完毕且TXE=1时,硬件将此位置1。软件序列清零。也可以直接向TC写入0来清除(仅DMA模式推荐)。若CR1寄存器中的TCIE=1,会触发中断。 |
5 |
RXNE |
RDR not empty 当发送移位寄存器中的数据被转入RDR时,硬件将此位置1。读取RDR或向此位写入0可清除(只写法仅DMA模式推荐)。若CR1寄存器中的RXNEIE=1,会触发中断。 RXNE=1,说明RDR非空,接收移位寄存器中的数据被移出,可接收下一个数据了。 |
4 |
IDLE |
IDLE line detected 当检测到空闲帧时,硬件将此位置1。软件序列清零。若CR1寄存器中的IDLEIE=1,会触发中断。 |
3 |
ORE |
Overrun error 接收移位寄存器已满但RXNE=1(RDR非空)时,硬件将此位置1。软件序列清零:先读USART_SR,接着写入USART_DR。若CR1寄存器中的RXNEIE=1,会触发中断。 注意:RDR中的内容无恙,但移位寄存器中的数据被覆盖。多缓存通信时若EIE=1,会触发中断。 |
2 |
NE |
Noise error 接收到的帧中检测到噪声时,硬件将此位置1。软件序列清除。 注意:NE不会产生中断,因为它与RXNE同时出现,RXNE自己会产生中断。多缓存通信时若EIE=1,NE发生会触发中断。 |
1 |
FE |
Framing error 当检测到同步错误、噪声过多或端口字符时,硬件将此位置1。软件序列清除。 注意:FE不会产生中断,因为它与RXNE同时出现,RXNE自己会产生中断。若FE和ORE同时发生,引发错误的帧仍会被传输,只有ORE位被设置。多缓存通信时若EIE=1,FE发生会触发中断。 |
0 |
PE |
Parity error 当接收端出现奇偶校验错误时,硬件将此位置1。软件序列清除。清零前必须等待RXNE被置1(有新数据缓存如RDR)。若CR1寄存器中的PEIE=1,会触发中断。 |
注:软件序列清零是指,软件先读USART_SR,接着写入USART_DR。
4.2 USART_DR 数据寄存器
USART_DR为数据寄存器(Data Register),用以容纳接收或发送的数据。该寄存器由两个寄存器构成:TDR和RDR。二者均为9位,共用地址(软件读取时用RDR、写入时用TDR),与配套的寄存器间并行通信。若开启了奇偶校验,MSB位会被校验位取代。
4.3 USART_BRR 波特率寄存器
USART_BRR为波特率寄存器(Baud Rate Register),用以配置分数波特率发生器的分频系数USARTDIV。该寄存器共占用16位,分为两个功能区:
DIV_Mantissa[15:4]:配置USARTDIV整数部分;
DIV_Fraction[3:0]:配置USARTDIV分数部分。
4.4 USART_CR1 控制寄存器1
USART_CR1为控制寄存器(Control Register)。USART共有3个控制寄存器,CR1主要用来设置收/发过程相关的参数,包括字长、校验位设置、唤醒方式、收/发器使能、静默模式、及收/发过程相关的5个中断。
位置 |
名称 |
功能说明 |
13 |
UE |
USART enable 0: USART分频器和输出关闭; 1: USART开启 。 |
12 |
M |
Word length 0: 停止位1,数据位 8,,停止位n (n=0.5,1,1.5,2) 1: 停止位1,数据位 9,停止位n 注意:传输过程中不要修改 |
11 |
WAKE |
Wakeup method 0: 空闲帧唤醒; 1: 地址标记唤醒 |
10 |
PCE |
Parity control enable 0: 关闭奇偶校验; 1: 开启奇偶校验 |
9 |
PS |
Parity selection 0: 偶校验; 1: 奇校验 |
8 |
PEIE |
PE interrupt enable 0: 禁用PE(奇偶校验错误)中断; 1: 开启PE中断 |
7 |
TXEIR |
TXE interrupt enable 0: 禁用TXE(TDR空)中断; 1: 开启TXE中断 |
6 |
TCIE |
TC interrupt enable 0: 禁用TC(传输完成)断; 1: 开启TC中断 |
5 |
RXNEIE |
RXNE interrupt enable 0: 禁用RXNE(RDR非空)中断 1: 开启RXNE中断 |
4 |
IDLEIE |
IDLE interrupt enable 0: 禁用IDLE(空闲帧)中断 1: 开启IDLEL中断 |
3 |
TE |
Transmitter enable 0: 关闭发送器;1: 使能发送器 注意:除了智能卡模式,若在传输过程中TE位上有0脉冲,会在当前帧传输结束发送一个前导符(空闲帧);TE设1后要延迟1个bit才开始传输。 |
2 |
RE |
Receiver enable 0: 关闭接收器;1: 使能接收器,并开始查找起始位 |
1 |
RWU |
Receiver wakeup 0: 退出静默模式;1: 进入静默模式 |
0 |
SBK |
Send break 该位写入1会发生一个断开符。 |
4.5 USART_CR2 控制寄存器2
CR2主要用来设置CK引脚的同步时钟、LIN模式、停止位以及USART地址。
位置 |
名称 |
功能说明 |
14 |
LINEN |
LIN mode enable 0: 关闭LIN模式; 1: 开启LIN模式 |
13:12 |
STOP |
STOP bits 00: 1; 01: 0.5; 10: 2; 11: 1.5; UART4 & 5 不支持0.5和1.5个停止位 |
11 |
CLKEN |
Clock enable 0: 停止CK时钟输出; 1: 使能CK时钟输出 |
10 |
CPOL |
Clock pority 0: 闲时低电平; 1: 闲时高电平 UART4 & 5 不支持 |
9 |
CPHA |
Clock phase 0: 第1个始终沿捕获数据; 1:第2个时钟沿捕获数据 UART4 & 5 不支持 |
8 |
LBCL |
Last bit clock pulse 0: Last bit不输出时钟脉冲; 1:输出 UART4 & 5 不支持 |
6 |
LBDIE |
LIN break detection interrupt enable 0: 禁止LIN断开帧中的; 1: 开启 |
5 |
LBDL |
LIN break detection length 0: 10bit断开符检测; 1:11位断开符检测 |
3:0 |
ADD |
USART address 为USART分配地址。此位在多处理器通信时用于通过地址标记定向唤醒。 |
注意:CPOL,CPHA,LBCL在传输过程中禁止修改。
4.6 USART_CR3 控制寄存器3
CR3主要用来设置硬件流控制、DMA收发、智能卡和IrDA模式,以及FE/ORE/NE错误中断。
位置 |
名称 |
功能说明 |
10 |
CTSIE |
CTS interrupt enable 1: 使能CTS中断; UART4 & 5 不支持 |
9 |
CTSE |
CTS enable 1: 使能CTS硬件流控制; UART4 & 5 不支持 |
8 |
RTSE |
RTS enable 1: 使能RTS硬件流控制; UART4 & 5 不支持 |
7 |
DMAT |
DMA enable transmitter 1: 使能DMA模式发送; UART4 & 5 不支持 |
6 |
DMAR |
DMA enable receiver 1: 使能DMA模式接收; UART4 & 5 不支持 |
5 |
SCEN |
Smartcard mode enable 1: 使能智能卡模式; UART4 & 5 不支持 |
4 |
NACK |
Smartcard NACK enable 1: 出现奇偶校验错误时使能NACK; UART4 & 5 不支持 |
3 |
HDSEL |
Half-duplex selection 1: 选择半双工模式 |
2 |
IRLP |
IrDA low-power 0: 正常模式;1: 低功耗模式 |
1 |
IREN |
IrDA mode enable 1: 使能IrDA红外模式 |
0 |
EIE |
Error interrupt enable 1: 多缓冲区模式下,使能FE、ORE、NE中断 |
4.7 USART_GTPR保护时间和预分频寄存器
USART_GTPR为保护时间和预分频寄存器(Guard Time and Prescaler Register)。该寄存器共占16位,分为两个功能区:
GT[15:8]:用于设置智能卡模式下的保护时间,单位为波特率时钟个数,保护时间过后才会设置TC标志位。
PSC[7:0]:用于设置智能卡和IrDA低功耗模式下的波特率预分频系数。IrDA低功耗模式下,
五、 USART功能设置
初始化USART的基本步骤如下:
- 使能时钟。查阅芯片手册,USART1相关引脚为:PA8-CK、PA9-TX、PA10-RX、PA11-CTS、PA12-RTS。所以应该使能GPIOA的时钟和USART1的时钟。二者均在RCC_APB2ENR寄存器中设置。
- 配置引脚模式:TX-输出复用推挽;RX-输入浮空。
- 配置USART参数:波特率、字长、停止位、奇偶校验、硬件流控制、收/发模式、…..
- 配置USART中断:选择通道、优先级配置、开启所需中断。
- 使能USART1。
- 编写收发代码和中断响应函数。
5.1 寄存器操作
为了便于寄存器操作,头文件stm32f10x.h中定义了与USART寄存器相关的宏,对地址进行了映射。以USART1为例,相关宏定义和地址映射如下:
#define PERIPH_BASE ((uint32_t)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define ADC3_BASE (APB2PERIPH_BASE + 0x3C00)
#define USART1 (USART_TypeDef *) USART1_BASE)
typedef struct{
__IO uint16_t SR;
uint16_t RESERVED0;
__IO uint16_t DR;
uint16_t RESERVED1;
__IO uint16_t BRR;
uint16_t RESERVED2;
__IO uint16_t CR1;
uint16_t RESERVED3;
__IO uint16_t CR2;
uint16_t RESERVED4;
__IO uint16_t CR3;
uint16_t RESERVED5;
__IO uint16_t GTPR;
uint16_t RESERVED6;
} USART_TypeDef;
欢迎大家来到IT世界,在知识的湖畔探索吧!
通过上述宏名称,可以对USART相关寄存器中的功能位进行设置。
欢迎大家来到IT世界,在知识的湖畔探索吧!//波特率115200,数据位8,停止位1,RX+TX,无奇偶校验,无硬件流控
usart1_int(void){
uint32_t temp
/* 1 使能时钟 */
RCC->APB2EN |= 0x00004004;//使能GPIOA和USART1的时钟
/* 2 配置引脚 */
temp = GPIOA->CRH;
temp &= 0xFFFFF00F; //reset
temp |= 0x000004B0; //PA9:50MHz,复用推挽;PA10:浮空输入
GPIOA->CRH = temp;
/* 3 配置USART参数 */
USART1->BRR = 0x2701; //72MHz,115200 =>39.0625
temp = USART1->CR1;
temp &= 0xFFFFE9F3;//Clear M/PCE/PS/TE/RE
temp |= 0x000C;//数据位8、无奇偶校验、收发均开启
USART1->CR1 = temp;
USART1->CR2 &= 0xFFFFCFFF;//停止位1
USART1->CR2 &= 0xFFFFCFFF;//硬件流控制nCTS,nRTS均不开启
/* 4 配置USART中断 */
/* 5 使能USART */
USART1->CR1 |= 0x01<<13;
}
5.2 标准库相关函数
标准库中USART相关的库函数共29个,在stm32f10x_usart.h中声明,stm32f10x_usart.c中定义。按函数功能大体分类,简述如下:
1. 初始化函数
- USART_DeInit(); 复位USART外设总线时钟。该函数实际访问的是RCC_APBxRSTR寄存器,先ENABLE接着DISABLE(为何要多此一举?)。
- USART_StructInit(); USART_Init( ); 这个两个函数用来初始化USART参数。可以先用USART_StructInit()用默认参数初始化一个USART_InitTypeDef结构体。默认参数为:波特率9600,字长8bit,停止位1,奇偶校验none,模式RX+TX,硬件流控None。执行此函数后,修改必要参数,再调用USART_Init()完成初始化。不用USART_StructInit(),需要逐字段输入。
typedef struct{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
USART_StructInit(){
/* USART_InitStruct members default value */
USART_InitStruct->USART_BaudRate = 9600;
USART_InitStruct->USART_WordLength = USART_WordLength_8b;
USART_InitStruct->USART_StopBits = USART_StopBits_1;
USART_InitStruct->USART_Parity = USART_Parity_No ;
USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None;
}
USART_Init()中设置的是CR1-3和BRR寄存器。波特率设置时,总线时钟是根据时钟系统设置进行计算,进而计算和设置BRR的整数和分数功能区的值。
- USART_ClockStructInit(); USART_ClockInit(); 与前述两个函数类似。这两个函数用来初始化CK引脚的时钟。可先调用USART_ClockStructInit(),生成一个用默认参数初始化的USART_ClockInitTypeDef结构体,进行必要修改后传个USART_ClockInit()完成初始化。默认参数为:CK时钟关闭,极性low,相位第1边沿,最后bit无时钟脉冲。
欢迎大家来到IT世界,在知识的湖畔探索吧!typedef struct{
uint16_t USART_Clock;
uint16_t USART_CPOL;
uint16_t USART_CPHA;
uint16_t USART_LastBit;
} USART_ClockInitTypeDef;
USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct){
/* USART_ClockInitStruct members default value */
USART_ClockInitStruct->USART_Clock = USART_Clock_Disable;
USART_ClockInitStruct->USART_CPOL = USART_CPOL_Low;
USART_ClockInitStruct->USART_CPHA = USART_CPHA_1Edge;
USART_ClockInitStruct->USART_LastBit = USART_LastBit_Disable;
}
2. 功能管理
- USART_Cmd(); 使能/禁用USART。设置CR1寄存器的UE位。
- USART_SetAddress(); 为USART分配地址。设置CR2寄存器的ADD[3:0]位。
- USART_WakeUpConfig(); 设置USART唤醒模式。设置CR1寄存器的WAKE位。
- USART_ReceiverWakeUpCmd(); 使能/禁用静默模式。设置CR1寄存器的RWU位。
- USART_DMACmd(); 使能/禁用DMA接收/发送。设置CR3寄存器的DMAR或DMAT位。
- USART_HalfDuplexCmd(); 使能/禁用半双工模式。设置CR3的HDSEL位。
- USART_OverSampling8Cmd(); 接收器一般都是16倍过采样。只有STM32F100xx系列支持8倍过采样,因为该系列最高频率只有24MHz,降低过采样可以提高波特率。
- USART_OneBitMethodCmd(); 只有低端芯片才支持的功能。
3. 接收和发送函数
- USART_SendData(); 发送数据,即将数据写入DR寄存器。虽然输入的Data为16位,但只有低9位有效。这个函数核心代码只有一行,这也是寄存器操作发送数据的典型代码:
USARTx->DR = (Data & (uint16_t)0x01FF); //取低9位
- USART_ReceiveData(); 接收数据,即将数据从DR寄存器返回。与SendData函数类似,该函数只取DR的低9位。
return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
4. 中断管理函数
- USART_ITConfig(); 配置USART中断。设置寄存器中与中断相关的8个位(前8个)。
// 所有11个中断别名
#define USART_IT_PE ((uint16_t)0x0028)
#define USART_IT_TXE ((uint16_t)0x0727)
#define USART_IT_TC ((uint16_t)0x0626)
#define USART_IT_RXNE ((uint16_t)0x0525)
#define USART_IT_IDLE ((uint16_t)0x0424)
#define USART_IT_LBD ((uint16_t)0x0846)
#define USART_IT_CTS ((uint16_t)0x096A)
#define USART_IT_ERR ((uint16_t)0x0060)
#define USART_IT_ORE ((uint16_t)0x0360)
#define USART_IT_NE ((uint16_t)0x0260)
#define USART_IT_FE ((uint16_t)0x0160)
- USART_GetITStatus(); 可分别查询10个中断(除了ERR)相关位的值,借以判别中断状态。
- USART_ClearITPendingBit(); 该函数用于清除CTS/LBD/TC/RXNE中断的中断状态位。其他中断状态位的清除方法:
- TXEIE – 读DR寄存器可清除。
- PEIE/FE/NE/ORE/IDLEIE中断状态位需要软件序列清除:先用USART_GetITStatus()读SR寄存器,接着用USART_ReceiveData()读DR寄存器。
- TC中断状态位需要软件序列清除:先用USART_GetITStatus()读SR寄存器,接着用USART_SendData()写DR寄存器。
- USART_GetFlagStatus(); 功能同USART_GetITStatus。
- USART_ClearFlag(); 功能同USART_ClearITPendingBit。
5. LIN模式相关函数
- USART_LINCmd(); 使能/禁用LIN模式。设置CR2寄存器的LINEN位。
- USART_LINBreakDetectLengthConfig(); 配置LIN模式下断开符检测时的帧长度,10或11bit。设置CR2寄存器的LBDL位。
- USART_SendBreak(); 向USARTx发送一个断开符。设置CR1寄存器的SBK位。
6. SmartCard模式相关函数
- USART_SmartCardCmd(); 使能或禁用智能卡模式。设置CR3寄存器的SCEN位。
- USART_SetGuardTime(); 设置智能卡保护时间,GTPR寄存器的高8位GT[15:8]。
- USART_SetPrescaler(); 设置智能卡分频系数,GTPR寄存器的低8位PSC[7:0]。
- USART_SmartCardNACKCmd(); 使能/禁用NACK传输。设置CR3寄存器的NACK位。
7. IrDA红外模式相关函数
- USART_IrDAConfig(); 配置红外模式。设置CR3寄存器的IRLP位。
- USART_IrDACmd(); 使能/退出红外模式。设置CR3寄存器的IREN位。
5.3 HAL库相关函数
HAL库中USART相关的常规库函数有40多个,还有多个宏函数,在stm32f1xx_hal_usart.h中声明,stm32f1xx_hal_usart.c中定义。只是比STD库多了些函数,换了个名称,功能分的更细一些而已。归根结底,也是设置的各个寄存器。仅将函数名称罗列如下,大多可以从名称看出功能。
/* 宏函数 _HANDLE_是外设参数对应的结构体,HAL库中称为外设句柄 */
__HAL_UART_RESET_HANDLE_STATE()
__HAL_UART_FLUSH_DRREGISTER()
__HAL_UART_GET_FLAG()
__HAL_UART_CLEAR_FLAG()
__HAL_UART_CLEAR_PEFLAG()
__HAL_UART_CLEAR_FEFLAG()
__HAL_UART_CLEAR_NEFLAG()
__HAL_UART_CLEAR_OREFLAG()
__HAL_UART_CLEAR_IDLEFLAG()
__HAL_UART_ENABLE_IT()
__HAL_UART_DISABLE_IT()
__HAL_UART_GET_IT_SOURCE()
__HAL_UART_HWCONTROL_CTS_ENABLE()
__HAL_UART_HWCONTROL_CTS_DISABLE()
__HAL_UART_HWCONTROL_RTS_ENABLE()
__HAL_UART_HWCONTROL_RTS_DISABLE()
__HAL_UART_ENABLE()
__HAL_UART_DISABLE()
/* Initialization/de-initialization functions **/
HAL_UART_Init();
HAL_HalfDuplex_Init();
HAL_LIN_Init();
HAL_MultiProcessor_Init();
HAL_UART_DeInit();
HAL_UART_MspInit();
HAL_UART_MspDeInit();
/* IO operation functions **/
HAL_UART_Transmit();
HAL_UART_Receive();
HAL_UART_Transmit_IT();
HAL_UART_Receive_IT();
HAL_UART_Transmit_DMA();
HAL_UART_Receive_DMA();
HAL_UART_DMAPause();
HAL_UART_DMAResume();
HAL_UART_DMAStop();
HAL_UARTEx_ReceiveToIdle();
HAL_UARTEx_ReceiveToIdle_IT();
HAL_UARTEx_ReceiveToIdle_DMA();
/* Transfer Abort functions */
HAL_UART_Abort();
HAL_UART_AbortTransmit();
HAL_UART_AbortReceive();
HAL_UART_Abort_IT();
HAL_UART_AbortTransmit_IT();
HAL_UART_AbortReceive_IT();
/* 中断与回调函数 */
HAL_UART_IRQHandler();
HAL_UART_TxCpltCallback();
HAL_UART_TxHalfCpltCallback();
HAL_UART_RxCpltCallback();
HAL_UART_RxHalfCpltCallback();
HAL_UART_ErrorCallback();
HAL_UART_AbortCpltCallback();
HAL_UART_AbortTransmitCpltCallback();
HAL_UART_AbortReceiveCpltCallback();
HAL_UARTEx_RxEventCallback();
/* Peripheral Control functions **/
HAL_LIN_SendBreak();
HAL_MultiProcessor_EnterMuteMode();
HAL_MultiProcessor_ExitMuteMode();
HAL_HalfDuplex_EnableTransmitter();
HAL_HalfDuplex_EnableReceiver();
/* Peripheral State functions **/
HAL_UART_GetState();
HAL_UART_GetError();
typedef enum{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
HAL库中将外设所有的参数和回调函数整合到一个结构体之中,称为外设的句柄,命名规则PPPP_HandleTypeDef。具体到USART,UART_HandleTypeDef的定义如下:
/* UART handle Structure definition */
typedef struct __UART_HandleTypeDef{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
__IO HAL_UART_RxTypeTypeDef ReceptionType; /*!< Type of ongoing reception */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
(* TxHalfCpltCallback)(struct __); /*!< UART Tx Half Complete Callback */
(* TxCpltCallback)(struct __); /*!< UART Tx Complete Callback */
(* RxHalfCpltCallback)(struct __); /*!< UART Rx Half Complete Callback */
(* RxCpltCallback)(struct __); /*!< UART Rx Complete Callback */
(* ErrorCallback)(struct __); /*!< UART Error Callback */
(* AbortCpltCallback)(struct __); /*!< UART Abort Complete Callback */
(* AbortTransmitCpltCallback)(struct __); /*!< UART Abort Transmit Complete Callback */
(* AbortReceiveCpltCallback)(struct __); /*!< UART Abort Receive Complete Callback */
(* WakeupCallback)(struct __); /*!< UART Wakeup Callback */
(* RxEventCallback)(struct __, uint16_t Pos); /*!< UART Reception Event Callback */
(* MspInitCallback)(struct __); /*!< UART Msp Init callback */
(* MspDeInitCallback)(struct __); /*!< UART Msp DeInit callback */
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
} UART_HandleTypeDef;
有些属性本身有是一个结构体。句柄的概念与MATLAB中的handle非常像。通过一个句柄可以管理外设对象的所有属性。
附录
USART在STM32CubeIDE中的配置过程非常简单,如下面几幅图所示:
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/53481.html