本帖最后由 MouseesuoM 于 2015-1-24 20:36 编辑
先给代码吧
编译环境是Keil5.0以上
烧写方式:JLINK
今天很累啊,上午码了好多字结果一下子删除了,就找不到了。今天主要想说说GPIO外部中断。
外部中断主要有两个问题没弄清楚,就是GPIO控制寄存器中PE PS PFE都要置位(不过仔细想想上拉使能不管什么样中断还是都能实现的)。因为自己也是新手,有些方面不是很清楚,如果那哪里说得不清楚或者不对,还希望指出。
(一)
上来首先说一下引脚中断配置问题吧,这还要看PORTx_PCRn寄存器
ISF:中断状态标志位,只读,1:检测到引脚中断,写1清零
一般是在进入中断后写1清零
IRQC:中断配置位,就是说具体这个引脚配置成什么中断是上升沿还是下降沿 低电平还是高点平
我写的程序中用的是下降沿1010(上升沿是1001)
MUX:外部中断用的普通GPIO的
通用输入功能,所以这里设置成001
PE:IO口内部上拉或者下拉电阻使能位,和PS一块使用,这里设置为1
PS:感觉PE=1时,该位才有效 1:选择上拉电阻 0:选择下拉电阻,这里设置为1
PFE:无源滤波使能位。这里设置为1:开启无源滤波
在mux中提到通用输入功能,所以就涉及到到GPIOx_PDDR寄存器,设置相应的引脚为0,一般默认就是0(输入)。
我么可以通过GPIOx_PIDR寄存器读取相应中断引脚的输入电平。
那么中断引脚设置完毕了。(实验中用的是PTD0作为外部中断触发的引脚)
(二)
NVIC寄存器,其实数据手册中只讲解了关于优先级设置的寄存器,关于中断使能和中断禁止的寄存器讲的很少(这部分的内容大家可看一下《Cortex™-M0 DevicesGeneric User Guide》)。
那么关于中断分为内核和非内核共48个。内核的占据16个,其余32个是非内核的,也就是我们常常会用到的32个。
从数据手册不难看出,在32个中断类型中,只有端口A和D是支持外部普通GPIO引脚中断的。所以我才选择D端口为中断引脚的
(1)那么怎么设置D端口的优先级?
上图说明的是,这个cpu支持的优先级有四个级别,所以只需要 2bits 就可以决定一个中断的优先级。
上图是用IPR0来举例的,不难发现IPR0只能决定四个中断的优先级,可是我们一共有32个中断,
所以决定中断优先级的寄存器共有8个分别是 NVIC_IPR0——NVIC_IPR7,其中每个寄存器决定四个中断的优先级,正好4*8=32个中断。
那么端口D的优先级是怎么确定的,在上图中
红框圈中的 IRQ 表示中断的序号,
NVIC IPR register number 表示该中断所在的 中断优先级寄存器
不难发现端口D的是7(其实是IRQ/4算出来的),所以决定端口D中断优先级的寄存器是NVIC_IPR7,而这个寄存器决定四个寄存器的中断优先级,那么到底是那两位决定端口D中断的优先级呢?
这里有一个公式 8*(IRQ mod 4)+6 (不要问为什么,因为数据手册是这么写的 哈哈)
那么端口D的 就是 8*(31%4)+6=8*3+6=30,所以决定端口D中断的优先级是NVIC_IPR[31:30],我的程序中设置为11,最大优先级。
那么优先级我们知道了,那么怎么使能该中断哪?
(2)使能中断
我们先看一下NVIC的寄存器
不难发现其实NVIC一共有12个寄存器,NVIC_IPR0-NVIC_IPR7,我们都已经了解了。
NVIC_ISER:中断使能寄存器
这个寄存器可读可写,不过写的只有写1有效,那么写1就表示中断使能。
那么端口D中断序号是31,所以在NVIC_ISER的31位写1即可。写0不产生任何影响。
NVIC_ICER:中断禁止寄存器
那么我们已经开启了端口D的中断怎么禁止了?那就需要这个寄存器,我们只要在相应的位(31位)写入1就可以禁止端口D的中断了。这个寄存器也是可读可写的,也是写入0没有效果。
还有两个寄存器:
NVIC_ISPR中断挂起寄存器,NVIC_ICPR解挂寄存器
中断挂起寄存器主要是说,如果我们想让某个中断暂时不执行,我们就可以NVIC_ISPR寄存器中相应位写1,那么这个中断就暂时不会执行被挂起来了,这个中断处于等待被执行的状态。
那么如果我们想让挂起的中断恢复正常,就可以往解挂寄存器(NVIC_ICPR)寄存器写入1就可以了,那么挂起的中断就可以正常执行了。
这两个寄存器读写和中断使能寄存器一样的。
(三)中断函数怎么写?
在.S的启动文件中已经帮我们定义好了每个中断发生时,会调用的函数名,我们只要在工程中实现这个中断函数就可以了。
其中不难发现端口D发生中断函数时,就会调用 “void PORTD_IRQHandler(); ”这个函数。那么我们在工程中实现这个函数中即可,我是在main.c文件中实现的,其实在哪里都可以,关键是你一定要定义这个函数就行。
差不多就这些吧。
我程序大致思路是如果蓝灯是开着的进入中断就关闭,反之就打开。(由于存在抖动现象不是很明显,大家自己修改修改,如果发现问题真心希望提出来,共同探讨解决)。
1.开启端口D时钟,初始化PTD1引脚控制三色led蓝灯,配置PTD0这个引脚的中断。
2设置端口D的优先级
3使能端口D中断
4编写中断函数