相关文章:
敏矽微电子Cortex-M0学习笔记02——Cortex-M0开发环境的建立及调试
敏矽微电子Cortex-M0学习笔记03——时钟系统设计例程
敏矽微电子Cortex-M0学习笔记04——GPIO详解及应用实例
1、目的
本篇学习笔记我们主要来了解ME32F030的中断系统,首先通过对ME32F030终端系统和中断控制存器进行学习,最后通过实际的GPIO端口中断实例掌握中断函数的编程实现来加深掌握ME32F030中断系统的编程方法。
2、ME32F030中断概述
中断是单片机系统重要的组成部分,使单片机能够快速的对事件请求做出响应。ME32F030靠内部的嵌套向量中断控制器(NVIC)来进行中断的调度,它是 Cortex™-M0 内核的一部分。它可以让 CPU 以最短的时间对中断作出反应。主要的特征有:
• 较短的中断响应延迟.
• 处理系统异常和外设中断.
• 支持 32 个中断向量.
• 四种可编程的中断响应优先级别.
• 产生软件中断.
• 可配置的不可屏蔽中断源会有详细的说明。
3、ME32F030嵌套向量中断控制器(NVIC)
嵌套向量中断控制器(NVIC)负责着整个MCU的中断管理,除了管理我们常用的外设中断源,还包括非屏蔽中断源的管理。具体管理的中断源及其中断序号,其实在CMSDK_CM0.h中定义好了,通过程序定义对具体管理的中断源一目了然,定义的内容如下图所示。
中断源
ME32F030的中断系统是由一系列的NVIC寄存器组成的,这些寄存器可用于中断 IRQ0~IRQ31, 包括中断使能,等待和优先级等操作。如果中断被允许,并且相应中断挂起被设置,NVIC 将会根据中断优先级触发中断。反之,中断被禁止,中断源只会改变中断挂起状态,而 NVIC 不会对中断源信号采取任何动作,不论任何中断优先级。具体的NVIC寄存器组如表格所示:
NVIC寄存器列表
2-1 中断允许寄存器
中断允许寄存器(ISER)用于使能中断设置,同时可返回当前允许中断设置。需要注意的是,对该寄存器写0是无效的,是不能禁止中断的。要禁止中断,就需要下面介绍的中断禁止寄存器。
2-2 中断禁止寄存器
有使能中断的设置,相应的就会有禁止中断设置,这就是中断禁止寄存器的作用。对寄存器进行写1操作,就可以禁止中断设置。。需要注意的是,对该寄存器写0是无效的。对寄存器进行读操作,同返回当前禁止中断设置。
2-3 中断挂起寄存器
当有中断事件发生时,中断挂起寄存器(ISPR)中对应的中断位就会置位 。此时读取寄存器就可以判断具体的中断源。同时我们也可以向寄存器的中断位写1,来强制中断进入挂起状态。
2-4 清除中断挂起寄存器
当MCU响应了中断请求,并且执行完对应的中断子程序后,MCU便会返回断点处继续运行。但在返回前需要通过清除中断挂起寄存器(ICPR),来清除对应的中断挂起,这样当次的中断流程算是完整结束。
2-5 中断优先级寄存器
如同我们做事情有轻重缓急之分,单片机对中断的处理也有“轻重缓急”。具体就是靠8组中断优先级寄存器IPR0~7来实现。每组寄存器对应4个中断源的优先级。这样刚好决定了中断0~中断31的优先级。
每一组的中断优先级寄存器IPRn的每个字节最高两位决定优先级,因此有0~3共4个优先级可以选择,越低的值表示优先级越高,当优先级更高的中断发生时,高优先级的中断会打断低优先级中断。如果是同优先级中断,则并不会打断当前中断,而是依次响应中断。中断优先级寄存器IPRn如图所示:
这里介绍个快速的方法来计算中断 M 的 IPR 寄存器号:
• 计算对应的 IPR 寄存器号, N, N = M / 4
• 计算 IPR 寄存器内的字节偏移量 M % 4, 其中:
– 字节偏移量 0 对应寄存器的位 7:0
– 字节偏移量 1 对应寄存器的位 15:8
– 字节偏移量 2 对应寄存器的位 23:16
– 字节偏移量 3 对应寄存器的位 31:24
4、ME32F030端口中断例程
本篇中我们首先讲解了ME32F030的GPIO中断系统,然后又介绍了嵌套向量中断控制器(NVIC)的原理。
最后,我们还是要通过具体的实例来把我们学到的理论知识应用到实际的例子中。我们将两者结合起来做个小实验,测试程序的代码如下:
unsigned int uiCnt = 0;//端口反转次数 int main(void) { PA->DIR_b.DIR0 = 1; //PA_0 设置为输出口 PA->IS_b.ISENSE0 = 0; //PA_0 设置为沿触发 PA->IBE_b.IBE0 = 1; //PA_0 上升沿和下降沿都触发中断 PA->IC_b.CLR0 =1 ; //PA_0 中断标志位清除 PA->IE_b.MASK0 = 1; //PA_0 中断使能 PB->DIR_b.DIR9=1; //PB_9 设置为输出口 NVIC_EnableIRQ(PA_IRQn); //使能PA_IRQ中断 lcd_init(); //LCD液晶初始化 while (1) { uiCnt++; //端口反转次数加1 PA->NOT_b.NOT0=1; //PA_0 输出取反 SYS_DelaymS(500); if(uiCnt == 20) //当反转20次时 { PA->IE_b.MASK0 = 0; //PA_0 中断关闭 } } } //PA_IRQ中断子程序 void PA_IRQHandler(void) { PB->NOT_b.NOT9=1; //PB_9(LED灯)输出取反 PA->IC_b.CLR0 =1 ; //清除PA_0中断位 //LCD显示中断发生的次数 LCD->MEMMAP1 = lcd[uiCnt/10] | (lcd[uiCnt%10]<<16); }
测试程序是通过PA_0端口输出反转,来产生下降沿和上升沿。但同时它的端口中断功能是被使能的,因此可以通过输出电平来“触发”自己的中断。在中断服务子程序中,LED小灯端口输出取反来进行点亮和熄灭,同时加入了LCD段码液晶来显示中断发生的次数。在程序全速运行的过程中,当端口输出反转20次之后,会关闭端口的中断功能。接下来下载并仿真例程来进行说明。
程序下载并仿真后,先在程序这两处打上断点。然后用快捷键F5全速运行,程序首先会运行到第78行处的断点,这时端口还没有进行输出反转。接下来用快捷键F10单步运行观察。
仿真1
F10单步运行后,发现程序已经跳转到了PA_IRQ中断服务子程序中,继续F10单步运行并观察执行每一步的现象,直到把中断服务子程序走完。
仿真2
中断服务子程序内的代码全部运行后的效果如图所示,首先LED小灯的端口输出取反,把LED小灯给点亮后(下次再进中断会输出取反熄灭,依次往复)。LCD段码液晶显示01,这说明发生了1次中断。
仿真结果
通过单步仿真我们清楚了中断发生后的处理流程,接下来就可以把之前打的两个断点取消掉,然后在83行的位置打上一个断点,随后F5全速运行程序,等待程序停到断点处。在等待的过程中,LED小灯保持闪烁,LCD段码液晶上的数字一直在自加。当程序停到断点处后,LCD段码液晶显示为20。继续单步运行后,端口PA_0的中断功能就被关闭了。
仿真3
关闭中断后,再次全速运行程序。我们发现小灯不再闪烁了,段码液晶显示的数字也不再自加。这是因为我们已经把端口中断关闭掉了,虽然uiCnt还在自加。但是已经进不了中断子程序去更新显示。因此依旧停留显示在20。我们不妨把uiCnt添加到Watch窗口中来看一下,添加方法如图所示。双击ucCnt变量名,选中后右键选择“Add uiCnt to”,“Watch 1”,这样就添加到Watch1窗口中了。
仿真4
通过Watch1窗口看到端口已经反转37次了,但LCD液晶已经停留在20。这也说明中断确实被关闭了,因此液晶一直没能更新显示。
仿真5
仿真结果2
来源:敏矽MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。