zoukankan      html  css  js  c++  java
  • STM32 串口/中断

    串口最基本的设置,就是波特率的设置。 STM32F4 的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应 IO 口的模式,然后配置一下波特率,数据位长度,奇偶校验位
    等信息,就可以使用了 。

    1,串口时钟使能。串口作为 STM32F4 的一个外设,其时钟由外设时钟使能寄存器控制,这里我们使用的串口 1 是在 APB2ENR 寄存器的第 4 位。 APB2ENR 寄存器在之前已经介绍过
    了,这里不再介绍。只是说明一点,就是除了串口 1 和串口 6 的时钟使能在 APB2ENR 寄存器,其他串口的时钟使能位都在 APB1ENR 寄存器。

    2,串口波特率设置。 每个串口都有一个自己独立的波特率寄存器 USART_BRR,通过设置该寄存器就可以达到配置不同波特率的目的。其各位描述如图 5.3.2.1 所示:

     STM32F4 的分数波特率概念,其实就是在这个寄存器(USART_BRR) 里面体现的。 USART_BRR 的最低 4 位(位[3:0],当 OVER8=0 时) 用来存放小数部分 DIV_Fraction
    紧接着的 12 位(位[154]) 用来存放整数部分 DIV_Mantissa,最高 16 位未使用。

    这里,我们简单介绍一下波特率的计算, STM32F4 的串口波特率计算公式(OVER8=0)如下:

    上式中, f是给串口的时钟(PCLK1 用于 USART2~5PCLK2 用于 USART1 USART6); USARTDIV 是一个无符号定点数。我们只要得到 USARTDIV 的值,就可以得到串
    口波特率寄存器 USART1->BRR 的值,反过来,我们得到 USART1->BRR 的值,也可以推导出USARTDIV 的值。但我们更关心的是如何从 USARTDIV 的值得到 USART_BRR 的值,因为一
    般我们知道的是波特率,和 PCLKx 的时钟,要求的就是 USART_BRR 的值。
    下面我们来介绍如何通过 USARTDIV 得到串口 USART_BRR 寄存器的值。 假设我们的串口 1 要设置为 115200 的波特率,而 PCLK2 的时钟(即 APB2 总线时钟频率) 为 84M。这样,
    我们根据上面的公式有:

    USARTDIV=84000000/(115200*16)=45.572

     那么得到:
    DIV_Fraction=16*0.572=9=0X09;
    DIV_Mantissa=45=0X2D;

    这样,我们就得到了 USART1->BRR 的值为 0X2D9。只要设置串口 1 BRR 寄存器值为0X2D9 就可以得到 115200 的波特率。

    3,串口控制。 STM32F4 的每个串口都有 3 个控制寄存器 USART_CR1~3,串口的很多配置都是通过这 3 个寄存器来设置的。这里我们只要用到 USART_CR1 就可以实现我们的功能了,
    该寄存器的各位描述如图 9.1.1 所示:

    STM32F4 多了一个接收器过采样设置位: OVER8 位,该位在USART_CR1 寄存器里面设置,当 OVER8=0 的时候,采用 16 倍过采样,可以增加接收器对时
    钟的容差。当 OVER8=1 的时候,可以获得更高的速度。简单说,就是 OVER8=0 时精度高,容错性好, OVER8=1 的时候,容错差,但是速度快。 这里我们一般设置 OVER8=0,以得到更
    好的容错性,以下皆以 OVER8=0 进行介绍。关于 OVER8 的详细介绍,请看《STM32F4xx 中文参考手册》第 26.3.3 节。

    该寄存器的高16位没有用到,低16位用于串口的功能设置。OVER8为过采样模式设置位,我们一般设置位 0,即 16 倍过采样已获得更好的容错性; UE 为串口使能位,通过该位置 1
    以使能串口; M 为字长选择位,当该位为 0 的时候设置串口为 8 个字长外加 n 个停止位,停止位的个数(n)是根据 USART_CR2 [13:12]位设置来决定的,默认为 0PCE 为校验使能位,
    设置为 0,则禁止校验,否则使能校验; PS 为校验位选择位,设置为 0 则为偶校验,否则为奇校验; TXIE 为发送缓冲区空中断使能位,设置该位为 1,当 USART_SR 中的 TXE 位为 1 时,
    将产生串口中断; TCIE 为发送完成中断使能位,设置该位为 1,当 USART_SR 中的 TC 位为 1时,将产生串口中断; RXNEIE 为接收缓冲区非空中断使能,设置该位为 1,当 USART_SR
    ORE 或者 RXNE 位为 1 时,将产生串口中断; TE 为发送使能位,设置为 1,将开启串口的发送功能; RE 为接收使能位,用法同 TE
    其他位的设置,这里就不一一列出来了,大家可以参考《STM32F4XX 中文参考手册》第714 页有详细介绍,在这里我们就不列出来了。

     

     

     

    4,数据发送与接收。 STM32F4 的发送与接收是通过数据寄存器 USART_DR 来实现的,这 是一个双寄存器,包含了 TDR RDR。当向 DR 寄存器写数据的时候,实际是写入 TDR,串
    口就会自动发送数据; 当收到数据, 读 DR 寄存器的时候,实际读取的是 RDRTDR RDR对外是不可见的,所以我们操作的就只有 DR 寄存器, 该寄存器的各位描述如图 9.1.2 所示:

     可以看出,虽然是一个 32 位寄存器,但是只用了低 9 位(DR[8:0]),其他都是保留。DR[8:0]为串口数据,包含了发送或接收的数据。由于它是由两个寄存器(TDR RDR)
    成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能。 TDR 寄存器提供了内部总线和输出移位寄存器之间的并行接口。 RDR 寄存器提供了输入移位寄存器和内部
    总线之间的并行接口。

    当使能校验位(USART_CR1 PCE 位被置位)进行发送时,写到 MSB 的值(根据数据的长度不同, MSB 是第 7 位或者第 8 )会被后来的校验位取代。当使能校验位进行接收时,读到

    MSB 位是接收到的校验位。

    5,串口状态。串口的状态可以通过状态寄存器 USART_SR 读取。 USART_SR 的各位描述如图 9.1.3 所示:

    这里我们关注一下两个位,第 56 RXNE TC
    RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将
    该位清零,也可以向该位写 0,直接清除。TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如
    果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写USART_DR2)直接向该位写 0
    通过以上一些寄存器的操作外加一下 IO 口的配置,我们就可以达到串口最基本的配置了,关于串口更详细的介绍,请参考《STM32F4XX 中文参考手册》第 676 页至 720 页,通用同步
    异步收发器这一章节。

    *************************************************************************************************

    中断

    STM32F40xx/STM32F41xx 92 个中断里面, 包括 10 个内核中断和 82 个可屏蔽中断,具有 16 级可编程的中断优先级, 而我们常用的就是这 82 个可屏蔽中断。

     

     

     

     ISER[8]ISER 全称是: Interrupt Set-Enable Registers,这是一个中断使能寄存器组。CM4 内核支持 256 个中断,这里用 8 32 位寄存器来控制,每个位控制一个中断。但是
    STM32F4 的可屏蔽中断最多只有 82 个,所以对我们来说,有用的就是三个(ISER[0~2]]),总共可以表示 96 个中断。而 STM32F4 只用了其中的前 82 个。 ISER[0]bit0~31 分别对应中断
    0~31ISER[1]bit0~32 对应中断 32~63ISER[2]bit0~17 对应中断 64~81;这样总共 82 个中断就分别对应上了。 你要使能某个中断,必须设置相应的 ISER 位为 1,使该中断被使能(
    里仅仅是使能,还要配合中断分组、屏蔽、 IO 口映射等设置才算是一个完整的中断设置)

     ICER[8]:全称是: Interrupt Clear-Enable Registers,是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反,是用来清除某个中断的使能的。其对应位的功能,也和 ICER 一样。
    这里要专门设置一个 ICER 来清除中断位,而不是向 ISER 0 来清除,是因为 NVIC 的这些寄存器都是写 1 有效的,写 0 是无效的。
    ISPR[8]:全称是: Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和 ISER 是一样的。通过置 1,可以将正在进行的中断挂起,而执行同级或更高级别
    的中断。写 0 是无效的。
    ICPR[8]:全称是: Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。其作用与 ISPR 相反,对应位也和 ISER 是一样的。通过设置 1,可以将挂起的中断接挂。写 0 无效。
    IABR[8]:全称是: Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和 ISER 一样,如果为 1,则表示该位所对应的中断正在被执行。这是一个只读寄
    存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。

    IP[240]:全称是: Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要! STM32F4 的中断分组与这个寄存器组密切相关。 IP 寄存器组由 240 8bit
    的寄存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。 而 STM32F4只用到了其中的 82 个。 IP[81]~IP[0]分别对应中断 81~0。 而每个可屏蔽中断占用的 8bit 并没有
    全部使用,而是 只用了高 4 位。这 4 位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据 SCB->AIRCR 中的中断分组设置来决定。

    这里简单介绍一下 STM32F4 的中断分组: STM32F4 将中断分为 5 个组,组 0~4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。具体的分配关系如表 5.2.6.1 所示:

    通过这个表,我们就可以清楚的看到组 0~4 对应的配置关系,例如组设置为 3,那么此时所有的 82 个中断,每个中断的中断优先寄存器的高四位中的最高 3 位是抢占优先级,低 1 位是
    响应优先级。每个中断, 你可以设置抢占优先级为 0~7,响应优先级为 1 0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。

    这里需要注意两点: 第一, 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二, 高优先级的抢占优先级是可以打断正在进行的低抢占优先级
    中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。

     通过前面的介绍,我们知道 STM32F4 5 个分组是通过设置 SCB->AIRCR BIT[10:8]来实现的,而通过 5.2.3 的介绍我们知道 SCB->AIRCR 的修改需要通过在高 16 位写入 0X05FA
    这个密钥才能修改的,故在设置 AIRCR 之前,应该把密钥加入到要写入的内容的高 16 位,以保证能正常的写入 AIRCR。在修改 AIRCR 的时候,我们一般采用读写的步骤,来实现
    不改变 AIRCR 原来的其他设置。以上就是 MY_NVIC_PriorityGroupConfig 函数设置中断优先级分组的思路。

     中断服务函数:比如void USART1_IRQHandler(void)函数是串口 1 的中断响应函数,当串口 1 发生了相应的中断后,就会跳到该函数执行。
    中断相应函数的名字是不能随便定义的,一般我们都遵循MDK 定义的函数名。这些函数名字在启动文件 startup_stm32f40_41xxx.s 中可以找到。
    中断服务函数里面的代码分为:判断是否为该中断(判断相应中断发生标志位),之后是中断服务程序,最后清除对应中断标志位。

  • 相关阅读:
    c++下使用邮槽实现进程间通信
    c++下基于windows socket的多线程服务器(基于TCP协议)
    C++实现线程同步的几种方式
    c++多线程编程:实现标准库accumulate函数的并行计算版本
    c++多线程在异常环境下的等待
    c++下基于windows socket的服务器客户端程序(基于UDP协议)
    c++下基于windows socket的单线程服务器客户端程序(基于TCP协议)
    C++解决error C4996报错
    Python读取UTF-8编码文件并使用命令行执行时输出结果的问题
    P4655 [CEOI2017]Building Bridges 题解
  • 原文地址:https://www.cnblogs.com/caiya/p/15078763.html
Copyright © 2011-2022 走看看