一、嵌套向量中断控制器(NVIC)
它属于内核的外设,在HAL库中,如何使用配置NVIC可在_cortex.c后缀的文件中找到。
它管理着中断向量表中的中断,而它同样是由各种寄存器所组合而成的。
① ISER[8]: "Interrupt Set-Enable Registers",一个中断使能寄存器。
②ICER[8] : "Interrupt Clear-Enable Registers",中断除能寄存器。
③ISPR[8] : "Interrupt Set-Pending Registers", 中断挂起控制寄存器,通过置1,将正在进行的中断挂起,执行优先级更高的中断,写0无效。
④ICPR[8] : “Interrupt Clear-Pending Registers”, 中断解挂控制寄存器,作用与ISPR相反。写一解除挂起,写0无效。
⑤IABR[8] : “Interrupt Active Bit Registers ”,中断激活标志位寄存器,对应的位和ISER一样,这是个只读寄存器,可通过它知道正在执行中断的是哪一个,中断结束后由硬件自动清零。
⑥ **IP[240] : "Interrupt Priority Registers ",是一个中断优先级控制的寄存器。优先级:先看抢占优先级,若同级再看响应优先级。(都是数字越小优先级越高)(PS:若都相同,则有硬件优先标识符决定)
那么我们既然了解了nvic的寄存器组成,用hal库该怎样去配置呢?
1.先进行中断优先级的分组
使用 " HAL_NVIC_SetpriorityGrouping()函数 "
//函数定义
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
NVIC_SetPriorityGrouping(PriorityGroup);
}
PS:如果使用CuneMax生成代码,那么这个会放在HAL_Init()函数中,并且该函数所需参数已经宏定义完成,我们只需按照此仿照即可(NVIC_PRIORITYGROUP_4),这个为默认值。
2.设置抢占优先级和响应优先级
中断分组设置完成后,要开始对组内的优先级进行设置。每个分组有各自的抢占优先级和响应优先级的位数。
之后我们再对使能中断通道。
//用来设置单个优先级的抢占优先级和响应优先级的值
void HAL_NVIC_SetPriority(IRQn_Type IRQn,uint32_t PreemptPriority, uint32_t SubPriority);
//用来使能某个中断通道
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
//用来清除某个中断使能的,也就是中断失能
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
二、EXTI--外部中断/事件控制器
实际在使用HAL库开发时,nvic大多被软件配置完成,我们只需配置EXTI部分即可。
但我们本着学习的态度,还是要了解exti的相关寄存器。
如图所示,EXTI经检测后会传递给NVIC,由其在进行相关处理。
1.外部中断/事件线路映像(即I/O口对应的中断线)
PA0 -- PG0都对应EXTI0......其他的类似(到EXTI15截止)。
而EXTI16-19也作为EXTI外设的输入线,如图:
但这么多的中断线并不是都有独立的中断服务函数,只能使用7个中断服务函数
其各自对应的中断服务函数名可以在启动文件中找到,如:EXTI0_IRQHandler......
2.EXTI功能框图
只有输入给NVIC后,中断才会被处理,上升沿和下降沿触发选择寄存器在设置时,选择其一或全选都行。其中的事件屏蔽寄存器和软件中断事件寄存器很少进行操作,默认置1。
脉冲发生器那块不需要cpu处理,因为运行速度很快,由硬件自动完成。此脉冲一般用来触发TIM或ADC.
3.EXTI各个寄存器描述
①上升沿/下降沿触发选择寄存器(EXTI_RTSR/FTSR)
②中断/事件屏蔽寄存器 (EXTI_IMR/EMR)
③软件中断事件寄存器(EXTI_SWIER)
④挂起寄存器(EXTI_PR)
在认识了这些寄存器后,我们该在HAL库中如何使用函数来实现这个功能呢?
首先初始化中断的GPIO为EXTI模式,有中断就有中断服务函数,然后我们有两步处理中断的方法,①直接跳转到指定的中断服务函数中,然后执行中断服务函数,再执行外部中断通用处理函数,其中调用了外部中断回调函数,然后在最后判断并清除中断标志。(我们可以再中断通用处理函数那里面直接写需求,这样可以不用写回调函数了)
②在main.c中直接重新写一个外部中断回调函数。(好用)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch (GPIO_Pin)
{
case GPIO_PIN_0:
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
break;
case GPIO_PIN_1:
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
break;
case GPIO_PIN_2:
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
break;
default :
break;
}
}