中断
- 1、中断的引入
- 2、使用单片机外部中断来处理按键
- 2.1、外部中断
- 2.2、参考数据手册中示例代码写程序
- 2.2.1、外部中断0的测试程序
- 2.2.2、完整程序
1、中断的引入
任务:独立数码管循环显示0-9,同时按键控制LED1亮灭。
代码如下:
#include <REGX51.H>
sbit K1 = P1^0;
sbit LED1 = P2^0;
void delay(void)//延迟函数
{
unsigned char a,b;
for(a=200 ;a>0 ;a--)
for(b=200 ;b>0 ;b--)
;
}
void main(void)
{
unsigned char val[10]= {0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90};//0~9的数码表
while(1)
{
unsigned char i;
for(i=0 ;i<=9 ;++i)
{
P0 = val[i];//数码管不断循环显示0到9
delay();
}
if(K1 == 0) //K1按下时
LED1 = 1;//LED1亮
else
LED1 = 0;
}
}
分析能否实现:实践证明可以实现功能,但是按键监测控制LED这边非常不灵敏。
分析原因:单片机在不断循环执行此代码,当执行到下列这段代码时,
unsigned char i;
for(i=0 ;i<=9 ;++i)
{
P0 = val[i];//数码管不断循环显示0到9
delay();
}
所消耗的时间是很长的,假如执行一句代码的时间为1,则执行此段代码的时间是10次循环时间*延迟函数的时间,大约为10x200x200。
而当执行下列这段代码时:
if(K1 == 0) //K1按下时
LED1 = 1;//LED1亮
else
LED1 = 0;
只需要大约4的时间,所以时间非常短的。
按键监测控制LED这边非常不灵敏:当我们按下K1时,可能CPU还在执行上面循环代码,而没有执行下列判断代码,所以导致LED能马上亮灭。所以我们要引入中断。
中断的思路
(1)“主线任务”为常规任务(执行时间长),默认运行
(2)中断发生后CPU暂停主线任务转去处理中断任务,完成后再回来接着执行主线任务
中断的意义
(1)中断处理能力让CPU可以全力处理主线任务而不用担心会错过中断任务(举例:看电影和收快递)
(2)中断式比轮询式更适合处理异步事件,效率更高。
(3)中断中处理的事件的特点是:无法预料、处理时间短、响应要求急。
2、使用单片机外部中断来处理按键
2.1、外部中断
(1)何为外部中断。中断源来自于单片机外部就叫外部中断,51支持4个外部中断。分别对应4个引脚。每一个外部中断都对应一个特定的单片机IO引脚(譬如INT0对应P3.2,这个是单片机在设计时候定好的,是无法改变的)。我们软件只需要对P3.2做一些相关配置,P3.2就可以响应外部的中断事件。当硬件产生了一个外部中断时CPU就会收到一个中断信号,从而转去执行外部中断对应的处理程序(这个处理程序也是我们软件需要去编写提供的)。
2.2、参考数据手册中示例代码写程序
2.2.1、外部中断0的测试程序
IT0,EX0,EA其实都是在51头文件里面用sbit定义好了的
IT0这一位用来设置中断的触发模式:下降沿触发(Falling)或者低电平触发(low level)。
EX0这一位是INT0的开关。如果EX0等于0则外部中断在单片机内部被关闭,此时CPU无法收到INT0的中断信息所以不会处理INT0;如果需要使用INT0就一定要设置为1。
EA是全局的中断开关。EA如果关掉则整个CPU不能响应中断,所有中断都被关了。光EA打开也不一定能响应中断,还得具体的中断开关打开才行。
exint函数里面执行的时中断程序。
2.2.2、完整程序
#include <REGX51.H>
sbit K1 = P3^2;//K1接线到中断0的引脚
sbit LED1 = P2^0;
void delay(void)//延迟函数
{
unsigned char a,b;
for(a=200 ;a>0 ;a--)
for(b=200 ;b>0 ;b--)
;
}
void delay10ms(void) //消抖的延迟函数
{
unsigned char a,b,c;
for(c=5;c>0;c--)
for(b=4;b>0;b--)
for(a=248;a>0;a--);
}
/***********中断函数执行次线任务********/
void ZongDuang() interrupt 0
{
if(LED1 == 0)//判断LED灯灭着的
{
if(K1 == 0)//k1按下
{
delay10ms();//消抖
if(K1 == 0)//K1真的按下
{
LED1 = 1;//让LED1亮
delay();
}
}
}
else//LED1灯是亮着的
{
if(K1 == 0)//
{
delay10ms();
if(K1 == 0)
{
LED1 = 0;//让LED1灯熄灭
delay();
}
}
}
}
void main(void)
{
unsigned char val[10]= {0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90};//0~9的数码表
IT0 = 1;
EX0 = 1;
EA = 1;
while(1)
{
unsigned char i;
for(i=0 ;i<=9 ;++i)//主线任务
{
P0 = val[i];//数码管不断循环显示0到9
delay();
}
}
}