STM32F40xx/STM32F41xx 的 92 个中断里面, 包括 10 个内核中断和 82 个可屏蔽中断,具
有 16 级可编程的中断优先级, 而我们常用的就是这 82 个可屏蔽中断。
ISER[8]: ISER 全称是: Interrupt Set-Enable Registers,这是一个中断使能寄存器组。
有用的就是三个(ISER[0~2]]),总共可以表示 96 个中断。而 STM32F4 只用了其中的前 82 个。 ISER[0]的 bit0~31 分别对应中断
0~31; ISER[1]的 bit0~32 对应中断 32~63; ISER[2]的 bit0~17 对应中断 64~81;
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 将中断分为 5 个组,组 0~4。该分组
的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。具体的分配关系如表 5.2.6.1 所示:
组 AIRCR [10: 8] [ 7: 4]分配情况 分配结果
0 111 0: 4 0 位抢占优先级, 4 位响应优先级
1 110 1: 3 1 位抢占优先级, 3 位响应优先级
2 101 2: 2 2 位抢占优先级, 2 位响应优先级
3 100 3: 1 3 位抢占优先级, 1 位响应优先级
4 011 4: 0 4 位抢占优先级, 0 位响应优先级
例如组设置为 3,那么此时所有的 82 个中断,每个中断的中断优先寄存器的高四位中的最高 3 位是抢占优先级,低 1 位是响应优先级
每个中断, 你可以设置抢占优先级为 0~7,响应优先级为 1 或 0。
数值越小所代表的优先级就越高
只有抢占不同才可以打断。
假定设置中断优先级组为 2,然后设置中断 3(RTC_WKUP 中断)的抢占优先级为 2,响应优先级为 1。中断 6(外部中断 0)的抢占优先级为 3,响应优先级为 0。中断 7(外部中断 1)的抢占优先级为 2,响应优先级为 0。那么这 3 个中断的优先级顺序为:中断 7>中断 3>中断 6。
上面 中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互打断!
MY_NVIC_Init函数
//设置 NVIC 分组
//NVIC_Group: NVIC 分组 0~4 总共 5 组
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
//设置 NVIC
//NVIC_PreemptionPriority: 抢占优先级
//NVIC_SubPriority : 响应优先级
//NVIC_Channel : 中断编号
//NVIC_Group : 中断分组 0~4
//注意优先级不能超过设定的组的范围!否则会有意想不到的错误
//组划分:
//组 0: 0 位抢占优先级, 4 位响应优先级
//组 1: 1 位抢占优先级, 3 位响应优先级
//组 2: 2 位抢占优先级, 2 位响应优先级
//组 3: 3 位抢占优先级, 1 位响应优先级
//组 4: 4 位抢占优先级, 0 位响应优先级
//NVIC_SubPriority 和 NVIC_PreemptionPriority 的原则是, 数值越小, 越优先
void MY_NVIC_Init(u8 NVIC_PreemptionPriority, u8 NVIC_SubPriority, u8 NVIC_Channel,u8 NVIC_Group)
外部中断的设置,配置相关寄存器
STM32F4 的 23 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB OTG FS 唤醒事件。
线 19:连接到以太网唤醒事件。
线 20:连接到 USB OTG HS 唤醒事件。
线 21:连接到 RTC 入侵和时间戳事件。
线 22:连接到 RTC 唤醒事件。
IMR:中断屏蔽寄存器。这是一个 32 寄存器。但是只有前 23 位有效。当位 x 设置为 1 时,
则开启这个线上的中断,否则关闭该线上的中断。
EMR:事件屏蔽寄存器,同 IMR,只是该寄存器是针对事件的屏蔽和开启。
RTSR:上升沿触发选择寄存器。该寄存器同 IMR,也是一个 32 为的寄存器,只有前 23
位有效。位 x 对应线 x 上的上升沿触发,如果设置为 1,则是允许上升沿触发中断/事件。否则,
不允许。
FTSR:下降沿触发选择寄存器。同 RTSR,不过这个寄存器是设置下降沿的。下降沿和上
升沿可以被同时设置,这样就变成了任意电平触发了。
SWIER:软件中断事件寄存器。通过向该寄存器的位 x 写入 1,在未设置 IMR 和 EMR 的
时候,将设置 PR 中相应位挂起。如果设置了 IMR 和 EMR 时将产生一次中断。被设置的 SWIER
位,将会在 PR 中的对应位清除后清除。
PR:挂起寄存器。当外部中断线上发生了选择的边沿事件,该寄存器的对应位会被置为 1。
0,表示对应线上没有发生触发请求。通过向该寄存器的对应位写入 1 可以清除该位。在中断服
务函数里面经常会要向该寄存器的对应位写 1 来清除中断请求。
GPIOA~GPIOI的[15: 0]分别对应中断线 15~0。这样每个中断线对应了最多 9 个 IO 口
EXTICR[0]~ EXTICR[3]对应EXTICR1~ EXTICR 4
Ex_NVIC_Config//外部中断配置函数
//只针对 GPIOA~I;不包括 PVD,RTC,USB_OTG,USB_HS,以太网唤醒等
//参数:
//GPIOx:0~8,代表 GPIOA~I
//BITx:需要使能的位;
//TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
//该函数一次只能配置 1 个 IO 口,多个 IO 口,需多次调用
//该函数会自动开启对应中断,以及屏蔽线
/*首先得开启 SYSCFG 的时钟,然后根据 GPIOx 的位得到中断寄存器组的编号,即 EXTICR 的编号,在 EXTICR 里面配置中断线应该配置到 GPIOx 的哪个位。然后使能该位的中断,最后配置触发方式。这样就完成了外部中断的配置了。
*/
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)