北京市轨道交通建设管理有限公司网站,天津专门做企业网站公司,公众号免费套用模板,济南网站seo技术前言
在stm32中姑且可以认为#xff0c;异常就是中断
单片机上电之后#xff0c;首先执行启动文件#xff0c;开辟堆栈之后#xff0c;开始初始化中断向量表。
NVIC
NVIC
NVIC是嵌套向量中断控制器#xff0c;控制着整个芯片中断相关的功能#xff0c;它跟内核紧密耦…前言
在stm32中姑且可以认为异常就是中断
单片机上电之后首先执行启动文件开辟堆栈之后开始初始化中断向量表。
NVIC
NVIC
NVIC是嵌套向量中断控制器控制着整个芯片中断相关的功能它跟内核紧密耦合是内核里面的一个外设。
####三个寄存器ISER、ICER 和IP NVIC 结构体定义来自固件库头文件core_cm3.h 在配置中断的时候我们一般只用 ISER、ICER 和IP 这三个寄存器ISER 用来使能中断ICER 用来失能中断IP 用来设置中断优先级。 ISER[8]Interrupt Set Enable Registers这是一个中断使能寄存器组。是个u32类型的数组成员有8个。 CM3、4 内核支持 256 个中断这里用 8 个 32 位寄存器来控制每个位控制一个中断。根据单片机生产厂商的设计不一定会全部使用到。 ICER[8]全称是Interrupt Clear Enable Registers是一个中断除能寄存器组。该寄存器组与 ISER 的作用恰好相反是用来清除某个中断的使能的。其对应位的功能也和 ISER 一样。这里要专门设置一个 ICER 来清除中断位而不是向 ISER 写 0 来清除是因为 NVIC 的这些寄存器都是写 1 有效的写 0 是无效的。 IP [240]全称是Interrupt Priority Registers是一个中断优先级控制的寄存器组。这个寄存器组相当重要STM32F407 的中断分组与这个寄存器组密切相关。IP 寄存器组由 240 个 8bit的寄存器组成每个可屏蔽中断占用 8bit这样总共可以表示 240 个可屏蔽中断。而 STM32F407只用到了其中的 82 个。IP[81]-IP[0]分别对应中断 81~0。而每个可屏蔽中断占用的 8bit 并没有 全部使用而是只用了高 4 位。这 4 位又分为抢占优先级和子优先级。抢占优先级在前子优先级在后。而这两个优先级各占几个位又要根据 SCB-AIRCR 中的中断分组设置来决定。
//----------以上是常用的NVIC寄存器对NVIC的配置实际上就是配置这几个寄存器----------//
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则表示该位所对应的中断正在被执行。这是一个只读寄存器通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。
优先级的定义
1.优先级只有主优先级和子优先级 2.所谓的优先级分组是决定了IP寄存器的高4bit其中哪几位代表主优先级几位代表子优先级 3.数值越小所代表的优先级就越高 4.抢占优先级抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。 5.响应优先级抢占优先级相同响应优先级高的中断不能打断响应优先级低的中断。
还有一种情况就是当两个或者多个中断的抢占式优先级和响应优先级相同时那么就遵循 自然优先级看中断向量表的中断排序数值越小优先级越高。 先比较主优先级再比较sub优先级再按中断向量表的优先级序号比较 中断优先级寄存器 NVIC_IPRx用来配置外部中断的优先级IPR 宽度为 8bit原则上每个外部中断可配置的优先级为 0~255数值越小优先级越高。但是绝大多数CM3芯片都会精简设计以致实际上支持的优先级数减少在F103中只使用了高 4bit。而这高4bit也会根据CB-AIRCR 寄存器的 bit10~8 的配置来决定主优先级占几位子优先级占几位。 优先级的分组由内核外设 SCB 的应用程序中断及复位控制寄存器 AIRCR 的PRIGROUP[10:8]位决定也就是说用于表达优先级的这4bit还需要根据优先级分组的配置再进行主优先级和子优先级的配置。
优先级分组的设置是由 SCB-AIRCR 寄存器的 bit10~8 来定义的.
举个例子_设置优先级
设置优先级设置优先级分组之后再设置主优先级和子优先级 1.设置优先级分组 2.设置主优先级 3.设置sub优先级
例如SCB-AIRCR 寄存器的 bit10~8将优先级分组设置为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 却不可以相互打断
NVIC 中断相关的库函数都在库文件 misc.c 和 misc.h 中
中断编程要点
一般情况下不使用库函数封装好的函数
编程时主要进行三步
1.使能中断
使能外设某个中断比如USART的传输完成中断接受完成中断等这些由相关外设的控制寄存器进行控制配置控制寄存器进行使能。这边是允许外设的具体某个中断还需要在NVIC操作 NVIC_ISER 和 NVIC_ICER 这两个寄存器进行中断的使能
2.配置NVIC
初始化 NVIC_InitTypeDef 结构体 2.1 设置中断源 2.2设定主优先级和sub优先级
2.3中断使能ENABLE或者失能DISABLE操作的是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。
3.编写中断服务函数
启动文件 startup_stm32f10x_hd.s 中预先定义了中断服务函数可以在里面进行编写。
NVIC 相关函数
NVIC 中断相关的库函数都在库文件 misc.c 和 misc.h 中(stm32f1系列) 把 core_cm4.h 文件的 NVIC 相关函数封装到 stm32f4xx_hal_cortex.c 文件中(stm32f4系列)
以外部中断EXTI为例
代码差不多就是这个意思具体使用时需要修改 配置GPIO PA0引脚作为外部中断的流程
1 使能 IO 口时钟。
使用 GPIO 之前必须开启 GPIO 端口的时钟用到 EXTI 必须开启 AFIO 时钟。
GPIO_InitTypeDef GPIO_InitStructure;//
EXTI_InitTypeDef EXTI_InitStructure;//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//打开GPIO的时钟打开AFIO的时钟2配置中断优先级NVIC
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置 NVIC 为优先级组 1 所有82个中断源都属于优先级组1主优先级0-1子优先级0-7*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置中断源exti1 */
NVIC_InitStructure.NVIC_IRQChannel EXTI0_IRQn;/* 配置抢占优先级1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1;/* 配置子优先级1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority 1;/* 使能中断通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;
NVIC_Init(NVIC_InitStructure);
3 设置 IO 口模式触发条件设置 IO 口与中断线的映射关系并使能中断。
# 设定GPIO模式
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;#浮空输入
GPIO_Init(GPIOA, GPIO_InitStructure);#设定EXTI触发条件
/* 选择 EXTI 的信号源 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);EXTI_InitStructure.EXTI_Line EXTI_Line0;
/* EXTI 为中断模式 */
EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt;
/* 上升沿中断 */
EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Rising;
/* 使能中断 */
EXTI_InitStructure.EXTI_LineCmd ENABLE;
EXTI_Init(EXTI_InitStructure);4 编写中断服务函数。
void EXTI0_IRQHandler(void){//确保是否产生了 EXTI Line 中断if (EXTI_GetITStatus(EXTI_Line0) ! RESET){//TodoEXTI_ClearITPendingBit(EXTI_Line0);}
}