陈阿炳意思是异常是由某些能够生成异常的指令(例如:SVC)或者是响应外部中断、内存冲突、对齐或总线错误、调试等系统行为导致的。
所以,在ARM架构里,中断指的是外设产生的需要系统优先处理的事件,是异常的一种。异常由NVIC(Nested Vectored Interrupt Controller)模块统一管理。
关于中断和异常的工作原理,在ARM架构下的工作方式等这里不做展开,需要复习这些知识点的建议找ARM内核架构的文档去看。这里主要以HAL库中STM32F7的串口中断响应过程为例,来看一下中断到底是怎么工作的,为什么能够提高系统运行效率。
需要说明的是,ARM的中断优先级分为抢占式优先级和子优先级,STM32采用4个优先级位,也即4个优先级位都为抢占式优先级(FreeRTOS就是这样处理的)时,总共有16个优先级别,数值越小优先级越高。这里默认就行。
在生成的工程里Core->
Src目录下,会多一个usart.c的源文件,里边有下面三个函数,把代码注释写出来:
这是串口1 的中断服务程序,通过调用HAL库的串口中断处理程序HAL_UART_IRQHandler完成中断响应。这个中断服务程序完全可以针对该串口完成的具体功能自己去写,效率更高。调用HAL库完成中断处理更简单方便,可移植性更好。
另外要注意的是,调用HAL库完成中断处理的话,还需要自己重写中断处理的回调函数,HAL库里的回调函数是一个弱函数,本身并没有实现任何功能。这也很好理解,每个应用的需求都不同,不可能写出一个通用的中断处理函数。而且有一个回调用的弱函数在,就算是用户程序没有实现,也不会导致程序出错。
假设要实现一个最简单的情况,串口每接收到一个字节的数据,非n则计数器RxCounter加1,否则计数器清零。为了方便观察,我们按下边这样实现。
在main.c中定义两个全局变量,并申明usart.c中定义的串口1的句柄,如下:
并在main函数的while循环前加如下代码,实现串口1每接收一个字节产生中断,接收的数据存放在Uart1RxBuff中。
好了,到此就完成了一个简单的串口接收中断处理的任务。能够判断接收的有效字符数。
串口1接收到一个字节的数据后,USART_ISR寄存器的RXNE位置1,如果对应的接收中断使能的话,则会向NVIC产生一个中断请求,NVIC根据中断源(USART1)去中断向量表相应的地址上找到中断向量(中断服务程序的入口地址),执行串口1的中断服务程序。
由上图可以看出,USART1的中断向量偏移地址为0x000000D4,默认是从零地址开始偏移,所以实际地址也为0x000000D4。中断向量表这个地址上存储的中断向量是中断服务程序USART1_IRQHandler的入口地址。看过之前文章关于启动代码的分析就应该知道,在启动代码里定义好了中断向量表,中断向量地址是由链接器生成符号地址后装入中断向量表的。
基于HAL库的串口中断的基本流程就是这样,但是并没有深入去查看相关库函数的实现过程,想全面掌握的话还需要去仔细阅读库函数源码。
|