首先,要理清楚,什么是中断。
中断的意思是,比如CPU是主角,他正在工作,忽然间GPIO口跟他讲,这件事需要他来做。CPU就只能停止自己手头的工作,去办GPIO口分配的事情。办完了,再去做自己的事情。等到GPIO口又有事了,CPU再停下工作,来完成GPIO口送来的事情。
每一次CPU停止工作的时候都叫做中断,GPIO口叫他做的事情叫做中断源。
这次外部中断实验的目的是:
使开发板上的三个按钮能控制开发板上灯泡的亮灭。按KEY0键,LED0亮,按KEY1键,LED1亮,按WK_UP键,LED0和LED1的状态就翻转一次。
就是我们要拿GPIO口做外部中断输入。就是我们按下按键的时候,就会产生一个中断,本来主函数里面运行得好好的,一产生中断,主函数就跳到子函数里面执行让灯亮的程序。然后就一直在中断函数里面不出来了,所以灯会一直亮着。再按下按键的时候,应该就是结束中断,回到主函数里面。(个人理解)
这个跟按键输入实验的结果一模一样。原理有什么不同呢?
按键输入实验
目的:
通过按键来控制灯泡的亮灭。 这个实验有头文件,按键源文件,灯源文件还有main函数。
头文件:
用位带操作,给控制灯泡的GPIO口起了一个别名,比如LED0,LED1等等。给将要控制灯泡亮灭的按键起了一个别名,比如KEYO,KEY1等等。读取灯泡和按键的GPIO口的状态,我们可以用到一个读取函数GPIO_ReadInputDataBit()读取它。然后再各个按键按下的时候取个别名。比如:
除了这个,头文件里面还要有一个按键扫描函数和一个配置按键参数的函数。
接着是KEY的配置函数方面,就是,开启GPIO口所对应的时钟,然后配备GPIO口的模式,速度以及端口号。如下图
这个函数用于禁用JTAG,使用SWD,因为我们要用到的一个GPIO口PA15占用了JTAG的一个IO,所以要禁止JTAG,使PA15作为普通的IO输入。
除了一个函数,KEY文件里还有一个按键扫描函数。如下图。
这个意思应该是,以KEY0为例,读取KEY0时返回0,则表示按键就是按下了,所以返回按键按下的标志KEY_PRES。
接下来就是主函数。首先初始化延时函数,灯函数,KEY函数,然后进入switch循环。当是KEY0按下的标志时,就是LED0=!LED0,从而实现按键控制灯的亮灭的功能。
然后,外部中断也是实现了这个功能。
STM32的每一个GPIO口都可以作为中断输入口。然后,中断控制器支持19条中断/控制请求。分别是:
0-15:分别对应响应的GPIO口;
16:对应PVD输出
17:对应RTC闹钟事件
18:对应USB唤醒事件
因为STM32供GPIO口使用的中断线只有16条,而GPIO口不止16个。所以,用GPIOX.0-GPIOX.15(X=ABCDEFG)分别对应中断线的15-0。下图就是GPIO口跟中断线的映射关系图。如果我们要哪个GPIO口对应到中断线上,我们就需要配备。
配置GPIO与中断线的映射关系的函数是
使用方法如下图
这样子就把GPIOE和中断线2联系起来了。但是这个IO口的中断是通过什么方式触发的,还不知道,因为这个需要我们去初始化中断的一些参数。初始化中断的函数名如下。
例如我们可以这样配备这个函数
这个初始化函数有几个变量,首先我们要配置他是在哪一条线上。(选择范围有EXTI_Line0-EXTI_Line15。)接着配置他的模式,有两种模式:中断(EXTI_Mode_Interrupt)和事件(EXTI_Mode_Event)既然是中断实验我们肯定选择中断模式的。然后我们再来配备他的触发方式,有三种模式,一种是上升沿触发,一种是下降沿触发,或者是任意电平(上升沿和下降沿触发)。最后就使能中断。
关于上升沿下降沿的说法,如下图
因为是外部中断,所以就要设置中断优先级。因为输入的外部中断那么多,总得告诉单片机哪一个先哪一个后吧。不然挤在一起,谁也没本事中断他。设置中断优先级的函数是NVIC_Init()。这个函数有几个变量,我们可以设置如下图。
配置完中断优先级后,指定了条中断线先之后,就该确定这中断线是要走去哪里的了。也就是我们应该编写中断服务函数。中断服务函数名在MDK里面已经有事先定义了。一共有六个。
分别对应中断线0,1,2,3,4,5-9,10-15。
但在编写中断服务函数之前,我们还应该确定一下,中断线上是否产生了中断。(标志是否置位)判断中断线上的状态的函数是
这个函数中还要用到一个中断标志位清除函数。如下
另外,有两个函数:EXTI_GetFlagStatus()和EXTI_ClearStatus()两个函数跟上面两个函数的作用是差不多的。但是EXTI_GetFlagStatus()要先判断这个中断是否已经使能,再去判断他的中断标志位是否置位。而EXTI_ClearStatus()是直接判断他的状态标志位。
使能中断=允许产生中断。
这两个中断的使用方法如下图:
所以,外部中断总共有五步。
1.将所有的GPIO口都配置为输入
2.开启GPIO口复用时钟,然后将GPIO口和中断线的映射关系安排好
3.初始化外部中断,设置触发条件
4.设置中断分组(NVIC),中断事件那么多,总得先排好队才好提高打断效率。
5.编写中断服务函数。
这个和按键输入实验不一样的一点就是,按键输入实验是用按键扫描函数检测按键的状态(是否按下),这个是靠中断实验检测按键是否已经按下。
中断的代码是:首先是各种头文件,写了一大堆,比如,exti.h,delay.h等等。然后,就是开始EXTIX_Init()的编写了。
说简单其实也特别简单因为里面就只有几个个小函数,第一个是配置中端线的函数EXTI_Init(),分别初始化出三条中断通道来,但是总得先知道中断通道是哪个吧。所以就用到了一个函数:GPIO_EXTILineConfig()来给GPIO口牵中断线。
因为三个按键分别对应三个通道,分别是
EXTI0_IRQHandler()和EXTI9_5IRQHandler()和EXTI15_10IRQHandler()
然后分别给这三个通道设置中断优先级,所以,控制器NVIC。将每个通道分组后,这个大函数就成立了。
然后另辟函数,名字叫做中断服务函数,给每个中断通道都分一个。然后是这样的,先延时10ms,防抖。
单片机:亮灯,请给我10ms的时间。
然后就判断了,如果按下了哪个键,就哪个灯亮,到最后,还一定要清除中断标志位。不然的话,这个,按键就控制不了等,他就要屹立不倒,常亮不衰了。
具体代码如下图
然后再调用一个主函数。就可以了。