NVIC配置
1.中断的使能与禁止
此处的中断使能与禁止,主要是针对片上外设240路中断的控制,使能是向SETENA寄存器对应位写1,禁止是向CLRENA寄存器对应位写1。SETENA/CLRENA寄存器组如表1所示。
表1 SETENA/CLRENA寄存器组

在STM32F1系列的MCU中,外设中断源如表2所示。
表2 STM32F1系列MCU外设中断源

续表

续表

有8对寄存器用于控制240路外设中断的使能与禁止,向其中的对应位写1可以使能相应的中断,中断使能设置寄存器0的位0对应外部中断0号(WWDG中断),位1对应外部中断1号(PVD中断),以此类推。
例如,要使能外设中断编号IRQ#3的操作,程序如下。

2.中断的挂起与解挂
当中断发生时,如果正在处理同级或高优先级异常,或者中断被掩蔽,则中断不能立即得到响应。此时中断被挂起。中断的挂起状态可以通过中断设置挂起寄存器(SETPEND)和中断解挂寄存器(CLRPEND)来读取,还可以写它们来手动挂起中断。挂起寄存器和解挂寄存器也有8对,其用法与前面介绍的使能寄存器和禁止寄存器完全相同,SETPEND/CLRPEND寄存器组如表3所示。
表3 SETPEND/CLRPEND寄存器组

续表

3.活动状态
每个外部中断都有一个活动状态位。在处理器执行了其ISR的第一条命令后,它的活动状态位就被置1,并且直到ISR返回时才硬件清零。由于支持嵌套,允许高优先级异常抢占某个ISR,然而哪怕中断被抢占,其活动状态位也依然为1。活动状态寄存器的定义与前面讲的使能、禁止和挂起、解挂寄存器相同,只是不再成对出现。它们也能按字、半字、字节访问,但它们是只读的。活动状态寄存器如表4所示。
表4 活动状态寄存器

4.优先级
使用优先级寄存器将0~255个优先级分别分配给各个中断。0代表最高优先级,255代表最低优先级。
优先级寄存器首先存放最高位。当优先级为3位时,存放在字节的位[7∶5]中。这也意味着某个应用即使不知道可能含有多少个优先级,也可以正常工作。
从0xE000_E400开始的地址里,每一个字节对应一个外部中断,例如,0xE000_E400对应外部中断WWDG,这个字节可以设置WWDG的中断优先级;0xE000_E401对应外部中断PVD,这个字节可以设置PVD的中断优先级,依次类推。优先级寄存器如表5所示。
表5 优先级寄存器

设置STM32F1系列微处理器外部中断优先级:外部#2中断>外部#12中断>外部#7中断>外部#4中断,并且#4中断的优先级为最低,程序如下。

系统部分异常也可以编程实现优先级设置,系统异常优先级寄存器如表6所示。
表6 系统异常优先级寄存器

例如,要设置系统异常PendSV优先级为7,用汇编方法实现,程序如下。

5.异常屏蔽寄存器
异常屏蔽寄存器包括PRIMASK、FAVLTMASK、BASEPRI、PRIMASK用于禁止在NMI和硬异常之外的所有异常,它有效地把当前优先级改为0(可编程优先级中的最高优先级)。该寄存器可以通过MRS和MSR,以下面的方式访问。(https://www.daowen.com)
(1)关中断。

(2)开中断。

FAULTMASK把当前优先级改为-1。这么一来,连硬异常都被掩蔽了。其使用方法与PRIMASK相似。但要注意的是,FAULTMASK会在异常退出时自动清零。
BASEPRI主要屏蔽优先级等于和低于某一个数值的异常。
6.其他异常的配置寄存器
用法异常、总线异常以及存储器管理异常都是特殊的异常,因此给它们“开了小灶”。它们的使能控制是通过系统Handler控制及状态寄存器SHCSR(地址为0xE000_ED24)来实现的。各种异常的挂起状态和大多数系统异常的活动状态也都在该寄存器中,系统异常控制及状态寄存器SHCSR如表7所示。
表7 系统异常控制及状态寄存器SHCSR

中断控制及状态寄存器ICSR(地址为0xE000_ED04)如表8所示。对于NMI、SysTick以及PendSV,可以通过此寄存器手工挂起它们。另外,在该寄存器中,有好多位段都用于调试。在大多数情况下,它们对于应用程序都没有什么用处,只有挂起位对应用程序比较有参考价值。
表8 中断控制及状态寄存器ICSR

中断控制与状态寄存器31位、28位、26位写1可分别挂起NMI、PendSV、SysTick中断,比如在FreeRTOS、μC/OS-Ⅱ、μC/OS-Ⅲ中,任务切换实际就是靠触发一次PendSV来完成,程序如下。
汇编语言实现方式:

C语言实现方式:

7.软件触发中断寄存器
软件中断包括手工产生的普通中断,这种中断能以多种方式产生。最简单的方式就是使能相应的SETPEND寄存器,而更专业、更快捷的作法则是通过使用软件触发中断寄存器STIR(地址为0xE000_EF00)。软件触发中断寄存器STIR如表9所示。
表9 软件触发中断寄存器STIR

例如,通过软件触发一次外设RTC中断,触发程序和中断服务程序如下。

8.节拍定时器SysTick
节拍定时器SysTick被捆绑在NVIC中,用于产生SysTick异常(异常号为15)。一般情况下,RTOS都必须用一个硬件定时器来产生需要的时钟节拍,作为整个系统的时基。节拍中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赋予特定的任务等;操作系统提供的各种定时功能都与这个节拍定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还能让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。
SysTick是一个24位定时器,该定时器的时钟源可以是内部时钟或是外部时钟。SysTick能产生中断,CM3为它专门开出一个异常类型,并且分配在向量表中。它使操作系统和其他系统软件在CM3器件间的移植变得简单。因为在所有CM3产品中,SysTick的处理方式都是相同的。SysTick有4个寄存器控制完成定时功能的配置,它们分别是控制与状态寄存器(地址为0xE000_E010)、重装初值寄存器(地址为0xE000_E014)、当前值寄存器(地址为0xE000_E018)和校准值存器(地址为0xE000_E01 C),这些寄存器分别如表2.10~表2.13所示。
表2.10 SysTick控制及状态寄存器

表2.11 SysTick重装初值寄存器

表2.12 SysTick当前值寄存器

校准值寄存器提供了这样一个解决方案:它使系统即使在不同的CM3产品上运行,也能产生恒定的SysTick中断频率。最简单的作法就是直接把TENMS的值写入重装初值寄存器,这样一来,只要没突破系统的“弹性极限”,就能做到每10 ms产生一次SysTick异常。若需要其他的SysTick异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下,CM3芯片可能无法准确地提供TENMS的值(比如CM3的校准输入信号被拉低)。所以,为保险起见,最好在使用TENMS前检查器件的参考手册。
表2.13 SysTick校准值寄存器

SysTick除能服务于操作系统之外,还能用于其他目的,比如作为一个闹铃,用于测量时间等。要注意的是,如果处理器在调试期间被喊停(halt),SysTick也将暂停运作。
在FreeRTOS、μC/OS中,系统要求定时器间隔1~100 ms产生中断,调用节拍函数以完成操作系统的正常运行,程序如下。
