外部中断是一个硬件设备所必有的功能,也是在单片机学问里必学的一项操作。
什么是外部中断?
外部中断是单片机实时地处理外部事件的一种内部机制。当某种外部事件发生时,单片机的中断系统将迫使CPU暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后.又返回被中断的程序处,继续执行下去。
在我们自己的代码世界里,可以理解成突然有一个优先级特别特别高的线程请求CPU处理,CPU必须要先处理这个线程,处理完再返回做之前做的事。
例如,我们按下了一个物理按钮,制造了一个中断事件,按钮的功能在事件内实现,这就是外部中断的作用。
在书写外部中断前,要学习几个中断使能寄存器
EA 是总中断使能 它管理着单片机是否执行中断的最大的开关 0为关 1为开
当EA打开时,才会去处理中断函数,否则芯片可不睬你的中断请求
接着是组中断使能
在之前的学习中,我们知道CC2530标准芯片有40个外接引脚。
其中P0_0到P0_7称为P0组,共有8个脚,
P1_0到P1_7称为P1组,共有8个脚。
P2_0到P2_4共有5个脚,称为P2组。
每个组各自也各有一个组中断开关,来控制该组是否允许执行中断请求。
分别由 P0IE,P1IE,P2IE 3个使能位来控制。这3个就是组中断使能
之后总中断和组中断打开之后,引脚上还有一个中断开关 存于PnIEN使能寄存器中
在P0中,针对P0_0~P0_7成为P0IEN,从低到高对应P0_0到P0_7。以此类推还有P1IEN,P2IEN。
P2IEN比较特殊,第5位是对应5个脚。第6位成为USB D+中断使能位,用于检测USB挂起状态下的USB恢复事件。当USB控制器没有挂起时不设置该标志。 第6位其实我还没理解,但是日常使用不到它
如果说iocc2530.h比较老的话,可能不包含P1IEN和P2IEN的地址定义。
IEN2 |= 0x 10; 这是P1组的中断设置方式 P1在IEN2寄存器的第5位
IEN2 |= 0x 02; 这是P2组的中断设置方式 P2在IEN2寄存器的第2位
存于PICTL寄存器中
低位第1位控制着P0组的中断触发条件
低位第2位控制着P1组的P1_0到P1_3
低位第3位控制着P1_4到P1_7 (至于为什么分成两份,我也不知道了。不过官方寄存器这么定义,就照着做吧)
低位第4位控制着P2组
以上是中断触发条件的设置 0为上升沿 1为下降沿 那什么是上升沿与下降沿呢?之后再说~先看完寄存器定义吧
高位的123都是没用的位
高位第4位控制着I/O口驱动能力,选择输出驱动能力增强来补偿引脚DVDD的低I/O电压,确保在较低的电压下的驱动能力和较高电压下相同。0为最小驱动能力增强。1为最大驱动能力增强。 这个位我也没怎么设过,基本上默认情况下不大会出现电压不稳的情况。
那什么是上升沿和下降沿呢?
要知道,在数据的世界里,万物由0和1构成。0就是低电平信号,1就是高电平信号。
像LED,通过将引脚放到低电平来点亮它,放到高电平来熄灭它。其中肯定有电平信号的高低变化
从低电平到高电平的变化 叫上升沿
从高电平到低电平的变化 叫下降沿
而在PICTL的前4位就存储这种触发时机。 0为上升沿 1为下降沿
好,到这为止所有的与中断相关的寄存器都已经出现了,来顺一下制造中断的流程
- 设置普通IO口 输入 输入状态
- 打开总中断
- 打开组中断
- 打开IO口中断
- 设置触发条件
我们以一个按钮按下 取反LED灯状态的栗子来上上手。
在开始前我们还要明白一个硬件知识。
物理的微动按钮,在按下的一瞬间几毫秒里,电平会有抖动,这几毫秒内的信号是不可信的,需要抛掉,几毫秒之后再确认电平信号状态来确定真正的按钮状态。我们可以通过一个简单的延时来处理掉这几个毫秒时间。
CPU在进入正常工作状态后,每一个机器周期会检查组中断标志位IFG和组总中断标志位IF。当有某个中断位为1时,就会进入中断触发。出中断时一定要将相应标志位回0,否则会无限中断出不来。
下方就是一个外部中断小案例的代码
#include
//这是一段瞎写的延时代码,只要达到延时目的就行
void delay(){
int i,j;
for(i=0;i<1000;i++)
for(j=0;j<30;j++)
}
void main(){
P0SEL &= 0xDF;//1101 1111 P0_5 普通IO口模式
P0DIR &= 0xDF;//1101 1111 P0_5 输入模式
P0INP &= 0xDF;//1101 1111 P0_5 上下拉输入
P0INP &= 0xDF;//1101 1111 P0_5 上拉
EA = 1;//打开总中断
P0IE = 1; //打开组中断
P0IEN |= 0x20; //打开P0_5中断
PICTL |= 0x01; //P0组下降沿触发
while(1);
}
//#pragma vector=PxINT_VECTOR 中断函数关键字 x为组 这是cc2530已经定义好的宏,不能乱改
#pragma vector=P0INT_VECTOR
__interupt void fn()//中断函数fn.fn可改
{
if(P0IFG & 0x20)
{//这里确定是由P0_5发出的中断 P0IFG是P0组的中断标志位,记录了每个引脚是否有中断请求,如果为1则要中断
delay();//延时
if(0 == P0_5)
{
//延时后P0_5依旧低电平,表示确实是按下了,上方是消抖操作
P1SEL &= 0xfe; //1111 1110 P1_0 普通IO口模式
P1DIR |= 0x01; //设置P1_0为输出模式
P1_0 ^= 1; //自己与1 异或 若为1 1异或1为0 若为0 0异或1为1。可以达到取反效果
}
}
P0IFG &= 0x DF;//1101 1111 P0_5 把P0_5的中断位消除,表示中断任务结束,不消除会死循环这个中断
P0IF=0; //组中断标识也要擦一下
}
搜噶。卡萨撒哈密达~
定时开关机好像是程序控制主板断电的。逻辑差不多
定时开关机也是这个原理吗 定点自动断流~