商务网站建设的主流程,宁波人流多少钱,水富县建设局网站,外贸自主建站平台STM32的中断控制体系前言STM32中断的概念中断类型中断控制常用控制函数区分中断源与中断信号配置中断优先级分组问题中断使能中断服务函数总结前言
上一篇中#xff0c;借着串口接受的问题#xff0c;简要说了一下串口中断的作用和用法#xff0c;本文将对STM32的中断控制体…
STM32的中断控制体系前言STM32中断的概念中断类型中断控制常用控制函数区分中断源与中断信号配置中断优先级分组问题中断使能中断服务函数总结前言
上一篇中借着串口接受的问题简要说了一下串口中断的作用和用法本文将对STM32的中断控制体系做个介绍。
STM32中断的概念
关于中断的概念在上一篇中已经做了介绍了说通俗点就是程序正常情况下是在while(1)内运行着相关的任务例如下图中的任务1任务2在没有中断的时候整个代码的运行流程就是完成初始化然后在while1内一直循环里面的任务此时如果任务1内有大的阻塞延时类似串口等待接收LED灯while死等延时这些都会阻塞整个while(1)的运行时间导致执行效率严重低下这种情况是不能满足日常需求的所以在实际产品中很少有使用阻塞式的延时和while死等的情况。为了解决这个问题这时就需要有中断的加入了。 加入中断后的运行流程图就变成了下图的情况首先中断是一个内核功能不属于片上外设但是使用过程中也需要初始化其次初始化后会有一个与之对应的中断服务函数上面的那些具有阻塞的功能通过中断服务函数内的各种标志位就可以实现变阻塞为不阻塞了当初始化中断对应的条件满足时就会产生一个中断信号这时CPU会停止当前任务转而去到对应的中断服务函数里面将中断服务函数内的任务先完成完成后再回来继续执行原本的任务。编程时只需要判断对应的标志位即可解决上面的阻塞问题。 需要注意的是中断是可以解决阻塞的问题但是中断服务函数的本身也不能有延时、循环、阻塞程序紧急事件是实时响应的紧急事件不能执行太久。 总的来说中断对于正常运行的CPU来说就是一个异常事件而且异常事件的优先级高于正常运行的事件的优先级发生异常必须先解决异常才可以重新回到正常运行。上一篇中的空闲中断和接收中断就是这样那么STM32的中断到底是怎么运行和管理的呢。
中断类型
首先中断的控制是在内核里面的中断的相关内容是有ARM公司设计的在处理器内部会有一个叫做嵌套向量中断控制器NVIC得中断处理器他就是专门用来管理整个STM32的中断问题的其中中断的主要来源有两个一个是处理器的内核出现了故障会触发系统异常进而进入中断二是片上外设触发了其相关的中断信号也会进入中断像上一篇的出口接收中断和空闲中断就是属于后者是外设产生的中断。
中断控制
在上一篇的配置中已经使用到了NVIC的相关控制关于这部分控制是官方封装好的函数在使用过程中调用即可。也就是说对于开发者来说中断的控制只需要调用函数就可以了这里借用上一篇调用的代码 NVIC中断控制器做配置的时候流程 第一步配置优先级分组 主函数配置 第二步合成优先级 第三步分配优先级 第四步使能对应的中断源 在对应的片上外设初始化函数中
//NVIC控制器配置
NVIC_SetPriorityGrouping(7-2);//设置中断的优先组别111-110-101-100
u32 priNVIC_EncodePriority(7-2,0,0);//设置抢占优先级为0响应优先级为0
NVIC_SetPriority(USART1_IRQn,pri); //将对应的优先级设置映射到对应的中断
NVIC_EnableIRQ(USART1_IRQn); //使能中断源常用控制函数
1.中断分组函数此函数用于对整个工程进行中断分组
void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
位置core_cm4.h------1435行
返回值空
参数uint32_t PriorityGroup 分组中需要写入的值
传参7-占先的位数
分组整个工程都要一样可以只配置一次只需要在主函数使用一次即可2.使能中断源配置函数此函数用于使能对应的中断源
void NVIC_EnableIRQ(IRQn_Type IRQn)
位置core_cm4.h------1467行
返回值空
形参IRQn_Type IRQn很明显此处形参是个结构体需要使用结构体内规定好的名称
传入对应的片上外设中断源----放中断源名字 例如串口USART1_IRQn
作用使片上外设的中断能够使用 核心级别中断使能关于此函数的形参IRQn_Type IRQn很明显此处形参是个结构体需要使用结构体内规定好的名称 需要用时直接跳转过去复制即可。 注意此处的形参编程时一定要跳转到stm32f4xx.h中找到对应的不可以自己随意修改。
3.中断优先级配置函数此函数用于设置对应中断源的中单优先级
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
位置core_cm4.h------1550行
返回值空
形参IRQn_Type IRQn, uint32_t priority
IRQn_Type IRQn中断源和上一个一样的中断源名称需要去stm32f4xx.h复制
uint32_t priority优先级占先和次级一起的优先级4. 优先级合成函数由于优先级写入时是一起写入的但是分类时又是分开计算的为了避免写入出错官方给了一个合成函数将分组、抢占优先级和响应优先级传入后此函数会返回需要写入的优先级值。
uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
位置core_cm4.h------1592行
返回值u32类型的值 优先级uint32_t priority
形参uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority
uint32_t PriorityGroup优先级分组
uint32_t PreemptPriority占先优先级
uint32_t SubPriority次级优先级用法u32 pri NVIC_EncodePriority(7-2,3,2);NVIC_SetPriority(USART1_IRQn, pri);从上面的注释中可以看出NVIC控制器的作用 ①对中断优先级做分组 ② 接收来自中断的请求 ③ 配置中断的优先级 ④ 使能外设的中断源 具体的代码在core_cm4.h中查看步骤如下图所示点击main.c前方1号框所在位置的“号,然后选择core_cm4.h”下滑就可以找到相关函数对应的函数描述就在其上方注释。
区分中断源与中断信号
仔细回想上一篇中的配置过程关于中断配置除了上面的NVIC控制器的相关操作还在USART的出事后配置中使能了接收中断和空闲中断这两个控制位那么这个使能与上面的中断源使能有什么区别呢。 中断源一个片上外设 USART1独立的中断源 USART2也是独立的中断源 中断信号指的是每一个中断源下会有多个触发条件例如串口1的接收中断和空闲中断。 也就是说中断源相当于房子里的总电闸而中断信号相当于房间里灯的开关插座的开关电视的开关。要开灯不仅要打开总闸还需要开启对应的分开关才行。 所以在中断配置过程中不仅需要配置对应的中断源使能还需要使能具体的中断信号。 知道了中断的管理方式接下来就是怎么管理的问题了。
配置中断
在上述管理的相关函数中涉及了多个中断里面的名词像分组占先优先级、次级优先级、占先位数等等看起来是有些混乱接下来就来解释一下这些东西的具体作用。
优先级
首先需要搞清楚优先级的定义对于Cortex-M处理器的异常是否能被处理器接受以及何时被处理器接受并执行异常处理是由异常的优先级和处理器当前的优先级决定的。 更高优先级的异常可以抢占低优先级的异常这就是异常/中断嵌套的情形也就是上面提及的占先优先级。 有些异常(例如复位Sys_Tick等)具有固定的优先级其优先级由负数表示这样它们的优先级就会比其他的异常高。 其他异常则具有可编程的优先级﹐范围为0~255。依据以上描述优先级被分为三类 **1.占先优先级程序员进行配置的具备抢占功能就是当一个中断正在进行时另外一个中断也产生了高抢占优先级的中断可以打断低抢占优先级的中断优先运行高优先级的运行结束后才会继续运行低优先级的。**类似下图中断1的占先优先级是1次级优先级为0中断2的占先优先级为0次级优先级为0 此时中断1已经在运行了但是由于它的占先为1优先级低于中断2的0占先优先级所以中断1会被中断2给打断优先运行中断2中断2运行完毕了才会回到中断1运行中断1运行后再回到while(1)中运行。
**2.次级优先级程序员进行配置的不具备抢占功能也就是说当一个中断正在进行时另外一个中断也产生了此时由于不具有抢占功能所以需要等当前中断运行结束后再进入后面产生的中断中运行。**如下图中断1的占先优先级为1次级优先级为1,中断2的占先优先级为1次级优先级为0 当中断1正在运行时中断2也产生了虽然此时中断2的次级优先级高于中断1的次级优先级但是其不具有抢占功能所以CPU会先运行完中断1后再去运行中断2。 次级优先级的作用在于当不同优先级的中断同时到达时CPU会优先执行次级优先级高的。 3.自然优先级系统自己配置不需要我们管这个优先级是官方给的最后的一道防线。 优先级数字越小优先级越高
分组问题
解决了优先级接下来就要高清楚分组的问题了。这个分组其实就是决定上面提到的占先优先级的在优先级控制寄存器中的位数和次级优先级在优先级控制寄存器的位数先看看M3和M4的权威指南关于分组的描述 ARM在涉及的时候一共预留了一个8位寄存器来实现优先级控制的编程理论上占先优先级和次级优先级会有2^8256种组合方式。 但是由于过多的中断优先级分组会影响单片机的性能所以ST公司在实际设计STM32芯片的时候就丢弃了LSB也就是这个八位寄存器的第四位只保留了四位用来做优先级的控制编程这样一来STM32的优先级分组就只有2的四次方种也就是16种组合。 ARM体系下优先级配置寄存器总共由8位占先和次级同时使用这个寄存器 中断的优先级共有256种 ST体系下ST公司对ARM公司的中断进行了裁剪只是用寄存器的高4位 中断的优先级共有16种。 可能还是有点没说清楚来看下表吧由于舍去了第四位占先优先级和次级优先级这两个一起瓜分这四位通过这四位来配置中断的优先级其中的配置方式如下表
写入的分组数占先在优先级寄存器中的位数次级在优先级寄存器中的位数此模式下中断的具体优先级数71110位 范围无4位范围0-1516种61101位 范围0-13位范围0-716种51012位 范围0-32位范围0-316种41003位范围0-71位范围0-116种30114位范围0-150位范围无16种20114位范围0-150位范围无16种10114位范围0-150位范围无16种00114位范围0-150位范围无16种
举几个栗子吧 1.当对分组写入101也就是5时占先优先级和次级优先级会分别占用优先级控制寄存器的两位每一个都有0-3三种组合起来一共就有16个优先等级其中00为最高优先级33位最低优先级且0x0,1,2,3可以打断1x(0,1,2,3)、2x(0,1,2,3)以及3x(0,1,2,3)的中断优先运行其他的也是依次类推。 2.假设在这个系统中我们不需要占先优先级此时就可以将占先的位置零也就是对分组写入7111让优先级控制寄存器独享四位这样的话整个系统的中断之间就不会出现打断和抢占当同一时刻有多个中断到来时会优先执行次级优先级高的中断执行完毕后才会转去下一个优先级相对高的中断此时的16组中断都不具有抢占功能最高优先级为0最低优先级为15. 3.假设我们在整个系统中需要各种中断嵌套这时就可以不为次级优先级分配优先级控制寄存器的位数让占先优先级独享四位也就是写入3011这样就可以有0-1516种中断嵌套其中优先级最高的可以打断任意中断最高优先级为0最低优先级为15。 其他的情况也就是依照上面进行类推即可这里再做两个练习吧 1.占先写入3 次级写入2 优先级分组能够是5 2.占先写入4 次级写入1 优先级分组能够是4 3.占先写入5 次级写入2 优先级分组能够是? //不能选择这种写入方式 需要注意的是一个系统只能有一个中断分组所以整个设置分组的函数也只需要在初始化时调用一次即可具体的写入方式为 写入值7-占先的位数
NVIC_SetPriorityGrouping(7-2);//设置中断的优先组别111-110-101-100
//此时写入的分组为5对应的分组占先占两位取值范围0-3次级占两位取值范围0-3上面的优先级设置函数中最终的中断优先级的参数只有一个也就是说所有的分组、占先的值次级的值都需要整合计算成一个数值写入为了减轻计算的麻烦也为了降低错误率官方给了一个优先级计算函数只需传入对应的分组、占先数和次级数即可计算出对应的优先级值
u32 pri NVIC_EncodePriority(7-2,3,2);//传入参数进行计算NVIC_SetPriority(USART1_IRQn, pri);//写入对应的优先级中断使能
在弄清楚中断优先级和中断分组后整个关于中断的操作就剩下了中断使能这最后一个步骤这里的中断使能是指的对中断源的使能官方已经给程序员提供了每个外设的中断源名称使用时只需要在stm32f4xx.h内查询即可具体的查询步骤在上面已经介绍过了想看的自己往上翻一下。 注此处只是打开了外设中断的总开关具体的中断信号配置还需要在对应的片上外设设置时打卡。
中断服务函数
再经过上面的中断配置后中断已经可以产生了那么怎么起作用呢这是就需要使用到中断服务函数了,中断服务函数就是中断产生后CPU处理异常事件的代码入口 具体执行的内容就是中断服务函数中的程序代码和前面的中断源使能一样官方也提供了对应片上外设的中断服务函数名使用时直接在startup_stm32f40_41xxx.s复制即可。 中断服务函数也分为两个大类一种是内核的中断一种是外设的中断这与中断的分类是一致的。 注意事项 1.中断服务函数必须复制不可以自己想当然的写写错了不会报错会很难查错误 2.中断服务函数不需要声明、调用也没有形参和返回值 3. 具体的使用只需要触发中断信号就进入中断服务函数 为了能够实时的响应 格式 4.中断服务函数中不能出现大量的延时和循环 尽量不使用printf尽量简短
格式void 中断服务函数名(void){//判断是哪一个中断信号{//清除标志位------防止CPU重复进入中断//紧急事件程序}//判断为另一个中断信号{//清除标志位//紧急事件}
}举个栗子 中断的执行过程 以串口1为例接收中断接收到了数据进入中断 空闲中断数据接收结束了会进入中断
void 串口1中断服务函数void
{//判断是否为接收中断{}//判断是否为空闲中断{//清除标志位}
} 总结
好了关于中断的介绍就记录到此文中如有不足欢迎指出。本文重点就是详细描述一下中断的配置过程以及中断的运行流程。