基于51单片机的流水灯实验
我们知道通过编写程序对51单片机进行控制,完成流水灯实验的方式有许多种。今天我们试通过51单片机的中断系统来完成流水灯实验。
在此之前,我们应首先清楚中断的概念。那么,什么是中断呢?中断是指:CPU在处理事件1时,发生了另一事件2,并请求CPU去处理(中断的发生)。此时,CPU暂时停止处理当前的事件1(中断响应),去处理事件2(中断服务);等到CPU将事件2处理完成之后,再回到事件1中断产生的地方继续进行处理事件1(中断返回)。这就好比当我们在吃饭的时候,突然门铃响了,我们起身去开门,然后回来继续吃我们吃了一半的馒头。
AT80C51单片机的中断系统有5个中断源,分别是外部中断0(INT0)、外部中断1(INT1)、定时/计数器0(T0)、定时/计数器1(T1)、串行口(Rx,Tx)。现在我们主要介绍外部中断,并通过外部中断实现我们今天的任务。那么,我们应该如何去使用外部中断呢?现在我们来介绍它的原理及其应用。
我们知道,操作单片机的本质就是操作或设置寄存器。我们来看下面这张图。这是中断系统的结构。
当我们在使用单片机的时候,需要设置几个寄存器:
1、中断允许寄存器IE
这个寄存器的作用是用来设置各个中断源的打开和关闭,可以位寻址,在此需要注意的是,当单片机被复位时,IE被全部清零。由上图的结构可以看出,EA的作用为总中断允许位。EA = 1,打开总中断;EA = 0,关闭总中断。ES为串行口中断允许位。ES = 1 ,打开;ES = 0,关闭。ET1(ET0)为定时/计数器的中断允许位,ET1(ET0) = 1,打开;ET1(ET0) = 0,关闭。EX1(EX0)为外部中断允许位,EX1(EX0)= 1,打开;EX1(EX0)= 0。
2、中断优先级寄存器IP
AT80C51单片机有两个中断优先级,可实现二级中断服务嵌套,需要注意的是,与中断允许寄存器相似,单片机复位时,IP被全部清零。PS是串行口中断优先级控制位。PS = 1,串行口中断为高优先级中断;PS = 0,串行口中断为低优先级中断。PT1(PT0)是定时/计数器中断优先级控制位。PT1(PT0)= 1,定义为高优先级中断;PT1(PT0)= 0,为低优先级中断。PX1(PX0)为外部中断优先级控制位。PX1(PX0) = 1,为高优先级中断;PX1(PX0) = 0,为低优先级中断。中断优先级有三条原则:1、首先响应高优先级的中断请求。2、高优先级的中断请求可打断低优先级中断。3、低优先级中断不可打断高优先级和同优先级中断。中断级别的排行:外部中断0>定时/计数器0>外部中断1>定时/计数器1>串行口。
下面我们来看外部中断,外部中断0(1),端口引脚为P3.2(P3.3),引脚符号为INT0(1)。外部中断的请求方式有两种,一种是负边沿触发,即令IT0 = 1即可;另一种是低电平触发,即令IT0 = 0即可。然后我们来设置中断允许寄存器IE,首先我们应该先打开总中断,令EA = 1。然后令EX0= 1。这样我们的IE寄存器就设置好了,之后在编写中断服务函数即可。
介绍了外部中断的原理及其应用后,我们开始完成任务。我们的任务是,按下开关,使得8个LED灯的轮流亮灭。下面来看流程。
1、我们首先需要定义端口。
sbit key = P3^2;
#define PORT = P1;
2、为了使我们更好的观察到实验效果,我们需要设置一个延迟函数。
void delay (u16 num)
{
u16 x,y;
for(x = num; x>0; x--)
for(y = 110; y>0; y--)
}
3、然后开始写我们的主函数,作用是对寄存器进行操作,进而控制单片机。
void main (void)
{
IT0 = 1; //按键开关为负边沿触发
EA = 1; //打开总中断
EX0 = 1; //打开中断允许寄存器
while(1) //做一个等待
{
;
}
}
4、最后我们来编写中断服务函数。
void ext_int 0(void) interrupt 0
{
u8 m;
PORT = 0xff; //关闭所有LED灯
if(key == 0)
{
while(1)
{
PORT = 0xfe; //使得最右面的LED先发光
delay (500); //延迟500ms,使得出现可观察到现象
for(m = 7;m > 0;m--)
{
PORT <<= 1 | 0x01;
delay(500);
}
}
}
}
下面我们看这个任务的总程序。
#include<reg52.h>
typedef unsigned char u8 ;
typedef unsigned int u16 ;
sbit key = P3^2 ;
#define PORT P1 ;
void delay(u16 num)
{
u16 x,y;
for(x = num;x>0;x--)
for(y = 110;y>0;y--);
}
void main (void)
{
IT0 = 1; //按键开关为负边沿触发
EA = 1; //打开总中断
EX0 = 1; //打开中断允许寄存器
while(1) //做一个等待
{
;
}
}
void ext_int 0(void) interrupt 0
{
u8 m;
PORT = 0xff; //关闭所有LED灯
if(key == 0)
{
while(1)
{
PORT = 0xfe; //使得最右面的LED先发光
delay (500); //延迟500ms,使得出现可观察到现象
for(m = 7;m > 0;m--)
{
PORT <<= 1 | 0x01;
delay(500);
}
}
}
}
由于本人能力有限,文中可能会有多多少少的错误,请谅解并指出对应错误。