中断

正常情况下,CPU根据代码顺序执行指令。遇到紧急事件就要停下来处理,处理完毕后回到暂停的地方继续执行。这个紧急事件就叫作中断或异常。

CPU内部的紧急事件叫异常,比如非法指令(除0),地址访问越界。来自CPU外部的片上外设产生的紧急事件叫中断,比如GPIO引脚电平变化,定时器溢出。

异常和中断都叫做中断也没有问题。

M3内核又256种中断,1-15为系统异常,15-255为外部中断。

Reset、NMI、优先级固定,值为负数。

CM3权威指南7、8、9章有详细介绍。

中断很多,就会有嵌套和优先级问题。这对这个,M3内核有个专门管理中断的外设NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)。NVIC是个总的中断控制器,无论是内核异常还是外设中断都统一管理。

Reset、NMI、HardFault优先级固定,为负数,其他的都可以通过修改NVIC的寄存器调整优先级。

M3内核里,把优先级分为抢占优先级子优先级。每个中断都需要指定这两个。高优先级中断可以打断低优先级中断,实现嵌套。在寄存器层面,应用中断和复位控制寄存器(Application Interrupt and Reset Control Register, AIRCR)的bit[10:8]将表示优先级的一个Byte分割成了两个部分,PRIGROUP实际上就是用来表示子优先级的bit数。NVIC_PRIORITYGROUP_3表示bit[3:0]用作子优先级,bit[7:4]用作抢占优先级,因此抢占优先级数为16,子优先级数也为16。

抢占优先级决定了是否可以打断,子优先级决定了同时中断情况下的先后顺序。

在程序一开始就设置中断优先级分组,此后就不应该再修改了。在使用HAL库时,初始化函数HAL_Init()里设置了中断分组:

void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);

调用这个函数来设置两个优先级:

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);

对于具体的中断,中断服务函数为:

然后在这个中断服务函数里调用HAL库的中断处理函数

这个函数处理的是中断状态为的读取与清除,最后有个回调函数,这个回调函数是我们最终使用的,处理业务的代码。事实上,回调函数在库里是有定义的,只不过声明为weak形式,但是我们一般都会自己重写一下。

总结使用中断服务的步骤:

  • 1.中断处理函数调用HAL库的中断

  • 2.HAL库中的中断处理函数处理状态位,调用一个回调函数

  • 3.回调函数实现具体功能

最后更新于