NVIC
NVIC Nested Vectored Interrupt Controller 嵌套向量中断控制。在STM32的标准外设库和MDK定义的中断相关的变量和结构体类型,大多都是以NVIC开头的,例如 NVIC_InitTypeDef 。
NVIC_Type
NVIC寄存器结构体。在MDK380a中,这个结构体是定义在stm32f10x_map.h中,具体的定义如下
typedef struct
{
vu32 ISER[2];
u32 RESERVED0[30];
vu32 ICER[2];
u32 RSERVED1[30];
vu32 ISPR[2];
u32 RESERVED2[30];
vu32 ICPR[2];
u32 RESERVED3[30];
vu32 IABR[2];
u32 RESERVED4[62];
vu32 IPR[15];
} NVIC_TypeDef;
ISER Interrupt Set-Enable Register 中断使能寄存器组,两个字,共63位,用了60位,一个位对应一个中断,写1中断有效,写0无意义。
ICER Interrupt Clear-Enable Register 中断除能寄存器组,也是两个字,和上面的使能寄存器组功能刚好相反,写1中断失效,写0无意义。
ISPR Interrupt Set-Pending Register 中断挂起控制寄存器组。用了60个位,对应60个中断。写1有效,可以将正在运行的中断挂起,从而执行同级别或者更高级别的中断。写0 无意义。
ICPR Interrupt Clear-Pending Register 中断解挂寄存器组。和上面的挂起寄存组功能刚好相反。写1有效,写0无意义。
IABR Interrupt Active Bit Register 中断激活标志位寄存器组。这是一个只读寄存器,通过读这个寄存器,可以知道那个中断正在被执行,对应的位会被置1。中断执行完后对应位清零。
IPR Interrupt Priority Register 中断优先级寄存器 15个字,共60个字节,每个字节对应一个中断,每个字节只用到了高四位,剩余四位保留。这有效4位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据SCB->AIRCR中中断分组的设置来决定。
SCB->AIRCR
STM32的中断分组:STM32将中断分为5个组,组0~4。该分组的设置是由SCB->AIRCR寄存器的bit10~8来定义的。具体的分配关系如下表所示: 组 |
AIRCR[10:8] |
bit[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位响应优先级 |
通过这个表,我们就可以清楚的看到组0~4对应的配置关系,例如组设置为3,那么此时所有的60个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。每个中断,你可以设置抢占优先级为0~7,响应优先级为1或0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
这里需要注意2点:
1,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行。
2,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
而在老版本的STM32标准外设库中也是有这样一个stm32f10x_map.h文件的。定义和上面的差不多,不同地方可能就是长度不同。
我现在手里拿的是最新的STM32标准外设库(3.5版),里面已经没有了stm32f10x_map.h这个文件了,要知道stm32f10x_map.h这个文件中定义了所有外设寄存器的结构和内存映射,像各个寄存器的结构体,基址,地址等等。
在新版的STM32的标准外设库中,将这些文件分开定义了,去掉了stm32f10x_map.h这个头文件后,新加入了stm32f10x.h 和core_cm3.h两个头文件。
在core_cm3.h中,定义了:
1. NVIC_Type ,
2. SCB_Type,
3. ITM_Type,
4. InterruptType_Type,
5. MPU_Type,
6. CoreDebug_Type。
在stm32f10x.h ,定义了
7. ADC_TypeDef,
8. BKP_TypeDef,
9. CAN_TxMailBox_TypeDef,
10. CAN_FIFOMailBox_TypeDef,
11. CAN_FilterRegister_TypeDef,
12. CAN_TypeDef,
13. CEC_TypeDef,
14. CRC_TypeDef,
15. DAC_TypeDef,
16. DBGMCU_TypeDef,
17. DMA_Channel_TypeDef,
18. DMA_TypeDef,
19. ETH_TypeDef,
20. EXTI_TypeDef,
21. FLASH_TypeDef,
22. OB_TypeDef,
23. FSMC_Bank1_TypeDef,
24. FSMC_Bank1E_TypeDef,
25. FSMC_Bank2_TypeDef,
26. FSMC_Bank3_TypeDef,
27. FSMC_Bank4_TypeDef,
28. GPIO_TypeDef ,
29. AFIO_TypeDef,
30. I2C_TypeDef,
31. IWDG_TypeDef,
32. PWR_TypeDef,
33. RCC_TypeDef,
34. RTC_TypeDef,
35. SDIO_TypeDef,
36. SPI_TypeDef,
37. TIM_TypeDef,
38. USART_TypeDef,
39. WWDG_TypeDef
而在stm32f10x_map.h中定义了34个类型,和stm32f10x.h 基本相似。
EXTI_TypeDef
外部中断的设置,还需要配置相关寄存器才可以。下面就介绍外部中断的配置和使用。
STM32的EXTI控制器支持19个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32的19个外部中断为:
线0~15:对应外部IO口的输入中断。
线16:连接到PVD输出。
线17:连接到RTC闹钟事件。
线18:连接到USB唤醒事件。
对于外部中断EXTI控制MDK定义了如下结构体:
typedef struct
{
vu32 IMR;
vu32 EMR;
vu32 RTSR;
vu32 FTSR;
vu32 SWIER;
vu32 PR;
} EXTI_TypeDef;
在新的标准外设库中,这个结构体的定义位于10x.h中。
IMR:中断屏蔽寄存器。这是一个32寄存器。但是只有前19位有效。当位x设置为1时,则开启这个线上的中断,否则关闭该线上的中断。
EMR:事件屏蔽寄存器,同IMR,只是该寄存器是针对事件的屏蔽和开启。
RTSR:上升沿触发选择寄存器。该寄存器同IMR,也是一个32为的寄存器,只有前19位有效。位x对应线x上的上升沿触发,如果设置为1,则是允许上升沿触发中断/事件。否则,不允许。
FTSR:下降沿触发选择寄存器。同PTSR,不过这个寄存器是设置下降沿的。下降沿和上升沿可以被同时设置,这样就变成了任意电平触发了。
SWIER:软件中断事件寄存器。通过向该寄存器的位x写入1,在未设置IMR和EMR的时候,将设置PR中相应位挂起。如果设置了IMR和EMR时将产生一次中断。被设置的SWIER位,将会在PR中的对应位清除后清除。
PR:挂起寄存器。当外部中断线上发生了选择的边沿事件,该寄存器的对应位会被置为1。0,表示对应线上没有发生触发请求。通过向该寄存器的对应位写入1可以清除该位。在中断服务函数里面经常会要向该寄存器的对应位写1来清除中断请求。
IO复用里的外部中断配置寄存器EXTICR
EXTICR在AFIO的结构体中定义,如下:
typedef struct
{
vu32 EVCR;
vu32 MAPR;
vu32 EXTICR[4];
} AFIO_TypeDef;
在新的标准外设库中,这个结构体的定义位于10x.h中。
这个结构体存在的原因是 STM32的每个IO都可以配置成中断输入口。但是线0~15:对应外部IO口的输入中断。只有16个。资源就不足了。为了确定是那一组IO的哪个口配置成中断,用到了EXTICR[4]。这虽然是一个32位的数组,但是只用到了16位,四位分成1组,这样就有了16组,从低到高,对应16个IO口,每组的四位数从0-6组成7种状态,对应A—G。
例如,我要设置PA3口为外部中断输入,EXTICR就要这样设置:首先PA3对应的是 EXTICR[0] ,它管口0-3,口3对应的是 EXTICR[0]的15-12位;要设置成PA,对应的就是xx xx xx xx (高16保留) 00 xx xx xx (xx表示4bit).
具体步骤是 :
1. 中断分组,确定系统要使用什么样的中断系统,为后面的整个设置定下基调。落实到寄存器就设置SCB-AIRCR.
2. 设置中断优先级。分完组定下基调就是该设置优先级了。落实到寄存器级别就是设置vu32 IPR[15] 这个数组了。上面提到了,8bit 表示一个中断设置,但是只用到了4个bit, 而且从低到高是对应中断的从低到高。此时你要开启的中断Channel也基本就确定了。设置完成后就确定这个中断的抢占优先级和响应优先级。
3. 开启对应的中断。落实到寄存器就是ISER[2]。60bit从低到高依次排开。至此,嵌套向量中断控制基本设置完成。但是中断还是不能用。因为还没有设置外部中断。
4. 设置外部中断。STM32支持19个外部中断。外部中断占据整个中断系统的低19个位。落实到寄存器就是设置EXTI_TypeDef结构体中的IMR(负责开启事件中断),EMR(负责屏蔽时间中断) RTSR 和FTSR (负责中断方式)。这样设置完后外部中断还是不能用。因为还没有映射到具体IO口。
5. 映射到具体IO口。STM32的设计是每一个IO口都可以充当中断引脚,这一点和51内核的单片机有很大的区别。16个外部中断对应每个端口的16个IO,但是端口可能是A-G,如何确定映射到哪个IO就成了问题。CM3的解决方法是 AFIO_TypeDef结构体中的EXTICR[4]数组来确定。具体思路就是 用这个数组4个元素的低16位,每四位对应一个IO,从低到高一一对应,四位同时变换出7种状态对应端口的A-G。这样IO就确定下来了。
更为严谨步骤是设置完成最后开启中断。剩下的工作就是编写中断服务函数了。
设置完这四个结构体,外部中断就可以用了。
上一篇:STM32外设库文件分析(V3.5)
下一篇:stm32变更外部晶振时如何配置时钟、以及HSI的使用
推荐阅读最新更新时间:2024-03-16 15:11