作者:junziyang
(注:如非特別声明,以下笔记内容均针对STM32F103ZET6而言。不同型号,细节可能存在差别。)
USART全称为Universal synchronous asynchronous receiver transmitter,意为通用同步异步收发器。顾名思义,该模块可以同步或异步方式,实现数据的接收或发送。USART是一种常用的串行(数据按一定的格式按位排队发送)通信接口,堪称万能接口。主要功能和特点如下:
STM32F103ZET6共有3个USART和2个UART,UART功能与USART类似,只是仅支持异步通信。同步通信和异步通信的本质区别在于,通信时是否需要时钟同步。平时常用的串口通讯基本都是UART。
图1. USART 框图
图1所示为USART的框图。左下角是波特率发生器,通过配置BRR寄存器,设置波特率分频系数,对PCLKx进行分频,产生接收器时钟,再经16分频,产生发送控制器时钟。两路时钟分别送往接收控制器(Receiver control)和发送控制器(Transmit control)。两个控制器汇总中部5个寄存器中的设置,将控制信号分别发往两个移位寄存器和中断控制器。
USART共有6个功能引脚,双向通信时至少需要2个引脚(RX和TX)。各引脚功能简述如下:
USART通信是一种串行通信,数据以帧(Frame)为单元,按位依次发送,低位优先。USART通信过程中共涉及3种帧结构:
图2所示为9位字长和1位停止位的帧结构和时序,8位字长时不包括Bit8。时钟信号来自波特率发生器,一个时钟周期发送1个bit的数据。显然,为了正确解析信息,收发双方必须采用相同的波特率,波特率越高数据发送速度越快。
图2. USART的帧结构与时序
从图中可以看出,起始位期间TX引脚为低电平,而停止位期间PX引脚为高电平。停止位后是下一帧的起始位,依此次序按帧将数据发送到TX引脚。
发送和接收受同一个波特率发生器驱动,通过将接收器或发送器的使能位置1,来产生各自的时钟。异步通信并不是不需要同步,只是通过发送同步信号和约定波特率,收发双方可以使用各自的本地时钟,不需要一个共同的时钟来进行同步。
根据CR1寄存器中M位的设置,发送器可以发送8位或9位字长的数据。发送使能位(CR1的TE位)被设置后,发送移位寄存器中的数据被依次输出到TX引脚,相应的时钟脉冲被输出到CK引脚。每个数据包包含一个字节,低位优先,每个字节前有一个起始位(长度为1个位周期的低电平)来作为前导,其后用一个停止位来结尾。
1. 发送端停止位的设置
停止位的长度可以在CR2寄存器中(STOP[1:0])进行配置,USART支持长度为0.5,1,1.5和2个周期的停止位。整数对应正常模式,小数对应智能卡模式。详情如下:
2. 发送器的配置步骤
下面来看一下常规USART模式下,发送数据的基本过程:
数据从总线传入,依次经TDR和移位寄存器被发送出去。当向DR寄存器写入数据时,如果有数据正在传输,数据会被写入TDR缓存,在当前数据传输完毕,数据会被复制到移位寄存器。TDR与移位寄存器间数据是并行传输的。若写入数据时没有数据正在传输,则数据将会被直接写入移位寄存器。数据的传输状态可以通过查询相关的寄存器来获知。
3. 数据的发送
与发送过程密切相关的寄存器位有4个:TXE(Transmit data register empty)、TC(Transmision complete)、TXEIE(TXT interrupt enable)、TCIE(TC interrupt enable)。
图3. 数据发送过程中相关寄存器的时序变化
图3所示为数据发送过程中相关寄存器的时序变化:软件使能USART时,TXE为高电平,第一个数据被软件写入DR寄存器,TEX被拉低;空闲帧发送完毕,stop bit下降沿触发第一帧数据F1被移入移位寄存器;因DR为空,TXE被拉高,软件检测到TXE=1将第二帧F2迅速写入DR,TEX又被拉低;重复此过程直到最后一个数据包被写入DR;软件开始等待TC=1;最后一个数据包被移入移位寄存器后,TXE开始持续为高电平;最后一帧发送完毕,在其stop bit下降沿因TXE=1,硬件将TC置1,传输过程结束。
从上述工作过程可以看出:
空闲字符和断开字符的发送通过软件设置寄存器来实现。向CR1寄存器的SBK位写入1,会在完成当前传输后在TX发送一个断开字符。在断开字符的stop bit,硬件会将SBK位重置为0。USART会在最后一个断开字符的尾部添加一个逻辑1位,来确保对下一帧start bit的正确识别。空闲字符的发送通过设置CR1寄存器的TE位实现,发送第一个数据帧之前需要发送给一个空闲帧,来实现接收器的唤醒或同步。
接收器接收的数据字长可以为8位或9位,也是由CR1寄存器中M位进行设置。异步通信模式下,收发双方的波特率、字长、停止位必须一致。
1. 接收器的配置步骤
接收器配置过程的前5步与发送器配置过程完全一致。
2. 起始位的检测原理
如前所述,每个数据包是以起始位(低电平)开始和停止位(高电平)结束的,识别起始位是正确接收和解析数据的前提。
图4. 起始位检测原理
起始位的检测原理如图4所示。USART接收器的采样频率是发送器波特率的16倍(参见图1)。自前一个包(数据帧或空闲帧)下降沿,到下一个包起始位结束,共有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. 数据的接收
如图1所示,接收数据时数据先是存入接收移位寄存器(Receive Shift Register),然后再转入接收数据寄存器(RDR,receive data register)的,低位优先。移位寄存器与RDR间数据是并行传输的。与接收过程相关的关键寄存器位有2个:RXNE和RXNEIE。
空闲字符会被当作正常字符来接收,如果设置了IDLEIE中断,接收到空闲字符时会触发该中断。断开字符则会被当作帧错误来处理。USART可以识别3种接收错误并根据设置触发相应的中断。
4. 噪声错误
为了区分有效的输入数据和噪声,异步USART接收器中采用了过采样技术。RX线上的输入电平会被以波特率的16倍进行采样。这样1个数据位中会有16个采样点。USART会用每个位中间的3次(第8,9,10次)采样值确定数据位的电平并判断数据是否有效。
图5. 取样数据的噪声检测
如前所述,在找到有效起始位时会设置RXNE为1,在RNXE的上升沿会同时会设置NE位。如图5所示,如果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寄存器,接着读取DR寄存器,可以复位ORE标志位。
6. 帧错误
由于同步出错或因噪声太多,导致在预期的时间没有识别到停止位,就会产生帧错误。如前所述,当接收到断开帧时也会当作帧错误来处理。当检测到帧错误时:硬件会将SR寄存器的FE(Frame error)位置1。后续处理与噪声错误类似,但字节通信时也可以在RXNE相关的中断中进行检查。
通过读取SR寄存器,接着读取DR寄存器,可以复位FE标志位。
7. 接收端对停止位的处理
接收端停止位设置与发送端相同,也是通过CR2寄存器中STOP[1:0]位来设置。但由于接收端是过采样,要分情况处理:
1. 计算公式
USART的接收器和发送器的波特率是通过对外设总线的时钟频率分频得到的,计算公式如下:
其中fCK为USART所在外设总线的时钟频率,USARTDIV为分频系数,由USART_BRR寄存器进行设置。从上述公式可以看出,USART的最高波特率为外设总线APBx频率的1/16,原因在于接收端要16倍过采样来接收数据,采样频率不可能高于APBx频率。如图1右下角所示,USART的接收器和发射器的波特率是通过同一个寄存器进行配置的。为了支持分数波特率,BRR寄存器的低16位被分成了两部分:0-3位设置分数部分,4-15位设置整数部分。二者共同定义分配因子USARTDIV。
根据BRR寄存器的设置,USARTDIV的计算规则如下:
反之,根据系统时钟频率和要求的波特率,BRR寄存器的整数和分数部分分别按下列公式计算:
例如:APB2总线频率72MHz,要求波特率115200。计算结果:UrtDIV=39.0625,IntDIV=0d39(0x27),FrcDIV=0d01(0x01)。
受USARTDIV取值的限制,不是所有的波特率都可以精确的配置出来。波特率设置值与实际值之间有时会存在误差。图6所示即为常用波特率设置值与实际值之间的相对误差情况。
图6. 波特率误差分析
对STM32F1系列芯片而言,APB1总线的最高频率为36MHz,APB2总线的最高频率为72MHz。除了USART1挂载在APB2总线上外,其余USART/UART均挂载与APB1总线。从图1可以看出,常用的波特率设置115200,在36MHz情况下就会有0.15%的相对误差。通常时钟频率越低,具体波特率的精度也会越低。USART1的最高波特率可达4.5M bps。
2. 接收器时钟公差
异步通讯中,只有整个时钟系统的误差小于USART接收器容许的公差时数据才能被正确接收。误差的主要来源包括:
为保证数据能被正确接收,上述4种误差总和必须小于USART接收器的公差。而公差又与三个因素有关:字长,即CR1寄存器的M=0或1;分数波特率,即BRR寄存器的低4位是否全为0;噪声帧的处理,忽略还是当作错误。根据这三个因素的不同,公差表分别如图7所示:
图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. 空闲总线检测
图8. 空闲总线检测静默-唤醒示意图
空闲总线检测静默-唤醒示意图如图8所示。当WAKE=0时,通过向RWU(Receiver wakeup)位写入1可使USART进入静默模式。进入静默模式后,接收器停止接收数据,但仍会检测RX引脚上的输入信号,如果检测到空闲帧,硬件会清除RWU,USART被唤醒开始正常接收数据(RXNE位开始变化)。
2. 地址标记检测
图9. 地址标记总线检测静默-唤醒示意图
地址标记检测静默-唤醒示意图如图9所示。这种模式下通常将字长设置为9,最高位(MSB)用来作为数据和地址的标识符。当MSB=1时,数据包被解析为地址;而当MSB=0时,则解析为数据。地址包的低4位存储一个地址标记,USART收到地址包后会与CR2寄存器的ADD[3:0]中的地址进行比较。如果地址不匹配,硬件将RWU置1,进入/保持静默模式,RXNE不会被设置,也不会有中断产生;如果地址匹配,硬件将RWU置0,唤醒USART,在地址包中Stop bit的下降硬件会设置RXNE,后续字符会被正常接收。
奇偶校验是一种校验代码传输正确性的方法。根据被传输的一组二进制代码中“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)开启,则会产生中断。
USART可以以同步模式工作。向CR2寄存器的CLKEN(Clock enable)写入1即可开启同步模式。同步模式下,数据在TX引脚输出的同时,发送器时钟从CK引脚输出,但在数据包的起始位和停止位CK引脚上无时钟脉冲。
发射器的运作在同步模式下和异步模式下完全相同。只是TX引脚上的数据是与CK引脚上的时钟同步发出的。
接收器的运作在同步模式下与异步模式下不同。由于有同步时钟,因此不需要不需要进行过采样。而是在RE=1使能接收器后,数据在CK的上升沿或下降沿被直接采样。但必须重视建立时间(setup time)和保持时间(hold time)。
图10所示是USART同步通信的时序示意图。图示是M=1,即9位字长的情况,8位字长与此类似。
图10. USART同步通信时序图
从图10可以看出,CPOL=0时,闲时电平为低电平,而CPOL=1时,闲时电平为高电平;CPHA=0时,第一个时钟沿采样,而CPHA=1时,第二个时钟沿采样。LBCL(Last bit clock)控制的是最后一个数据是否产生输出时钟脉冲。
单线通信的最大好处是只占一根线,通过分时收发(半双工)来实现通信。通过将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寄存器,就会被发送出去。
图11. 硬件流控制工作原理
所谓硬件流控制,是指通过硬件发送控制信号来控制数据流的一种方式,相当于一种握手协议。主要是为了避免因双方处理速度不匹配或USART网络中多个发送器同时向一个接收器发送数据导致接收端溢出错误和数据丢失。硬件流控制的基本原理图如图11所示,在两个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来独立开启。
图12. RTS流控过程
图12所示为RTS流控过程示意图。如前所述,接收器接收数据时,数据先通过移位寄存器接收,当接收到Stop bit后,数据会被存入缓存RDR,RXNE=1。如果使能了RTS,在RXNE=1期间,接收器停止接收数据,nRTS输出高电平1,向发送器发出停止发送请求,发送器应当在当前帧发送结束后会暂停发送,直至收到新的发送请求。
数据被从RDR读取后,RXNE=0。如果使能了RTS,nRTS输出低电平0,向发送器发出新的发送请求。如果数据传输通畅,RXNE=1的时间很短,数据几乎是连续发送。如果发生特殊情况耽误了RDR中数据的读取(比如发生中断),nRTS=1,停止发送,防止丢失数据。
图13. CTS流控过程 图13. CTS流控过程
图13所示为CTS流控过程示意图。使能CTS后,发送器在发送下一帧前会检查nCTS输入端口的电平。如果nCTS有效(低电平)且TXE=0(TDR非空),则下一帧被发送;反之,则不会进行发送。如果nCTS在数据发送期间失效(变为了高电平),当前帧传输完成后会停止发送。如图13中所示,Data2发送期间CTS失效,Data3虽已被移入TDR,但Data2发送后会停止发送,等待CTS=0再开始发送Data3。从图13还可以看到,在Stop bit后,Data2被移入移位寄存器,TDR中有个短暂的empty期,即TXE=0的间隙。
使能CTS后,只要nCTS电平发生跃变,硬件就会自动将SR寄存器中的CTS状态位置1。如果设置了CR3寄存器的CTSIE位,则会产生中断。
STM32F103ZET6共有3个USART和2个UART。3个USART支持所有的模式,但2个UART只支持部分模式,而且两个UART支持的模式也存在差别。具体配置如图14所示。
图14. USART模式配置
图15. USART相关中断
图15所示为USART相关中断事件和标志位。共有11个中断标志和8个相关中断,其中前3个为发送器相关中断,其余为接收器相关中断。通过设置相关的控制位使能中断。USART的所有中断都连接到同一个中断向量。
STM32F103ZET6中与USART相关的寄存器共有7个,地址映射与复位值表如图16所示。可以看出,这些寄存器虽然都是32bit寄存器,但功能位没有超过16bit的。所以这些寄存器允许按半字或全字访问。
图16. 寄存器地址映射与复位值
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。
USART_DR为数据寄存器(Data Register),用以容纳接收或发送的数据。该寄存器由两个寄存器构成:TDR和RDR。二者均为9位,共用地址(软件读取时用RDR、写入时用TDR),与配套的寄存器间并行通信。若开启了奇偶校验,MSB位会被校验位取代。
USART_BRR为波特率寄存器(Baud Rate Register),用以配置分数波特率发生器的分频系数USARTDIV。该寄存器共占用16位,分为两个功能区:
DIV_Mantissa[15:4]:配置USARTDIV整数部分;
DIV_Fraction[3:0]:配置USARTDIV分数部分。
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会发生一个断开符。 |
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在传输过程中禁止修改。
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中断 |
USART_GTPR为保护时间和预分频寄存器(Guard Time and Prescaler Register)。该寄存器共占16位,分为两个功能区:
GT[15:8]:用于设置智能卡模式下的保护时间,单位为波特率时钟个数,保护时间过后才会设置TC标志位。
PSC[7:0]:用于设置智能卡和IrDA低功耗模式下的波特率预分频系数。IrDA低功耗模式下,
初始化USART的基本步骤如下:
为了便于寄存器操作,头文件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;通过上述宏名称,可以对USART相关寄存器中的功能位进行设置。
//波特率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中断 */ 待补充2021.9.7
/* 5 使能USART */
USART1->CR1 |= 0x01<<13;
}标准库中USART相关的库函数共29个,在stm32f10x_usart.h中声明,stm32f10x_usart.c中定义。按函数功能大体分类,简述如下:
1. 初始化函数
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的整数和分数功能区的值。
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. 功能管理
3. 接收和发送函数
USARTx->DR = (Data & (uint16_t)0x01FF); //取低9位
return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
4. 中断管理函数
// 所有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)
5. LIN模式相关函数
6. SmartCard模式相关函数
7. IrDA红外模式相关函数
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中的配置过程如下面几幅图所示
TODO:LIN模式、智能卡模式、IrDA模式暂时不深究,用到时再学习;USART利用DMA连续通信,留待学习DMA时一并学习。
| 留言与评论(共有 0 条评论) “” |