51单片机中断及定时计数详解
目录
一、51单片机的中断
1.中断是什么
2.单一外中断实验示例
3.两个外中断实验示例
4.中断嵌套实验示例
二、定时器
1.51单片机定时器结构
2.定时器0.5s中断实现以及在keil示波器上验证
3.计数器中断控制LED
一、51单片机的中断
1.中断是什么
中断技术主要用于实时监测与控制,要求单片机能及时地响应中断请求源提出的服务请求,并快速响应与及时处理。
当中断请求源发出中断请求时,如中断请求被允许,单片机暂时中止当前正在执行的主程序,转到中断服务处理程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。
2.单一外中断实验示例
题目:在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
简化题目,要求P1端口8个LED灯常亮,在P3.2引脚设置一个按钮,按下按钮时P1端口的8个LED灯会变成高四位的LED和低四位的LED来回闪烁5次,最后返回常亮状态,
实现代码如下:
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
unsigned int j;
for(;i > 0;i--)
for(j=0;j<333;j++)//晶振为12MHz,j和i越大延时越久
{;} //空操作,用来消耗时间达到延时效果
}
void main( )
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
IT0=1; //选择外部中断0为跳沿触发方式
while(1) //循环
{ P1=0;} // P1口的8只LED全亮
}
void int0( ) interrupt 0 using 0 //外中断0的中断函数
{
uchar m;
EX0=0; //禁止外部中断0中断
for(m=0;m<5;m++)//交替闪烁5次
{
P1=0x0f; //低4位LED灭,高4位LED亮
Delay(400); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
}
EX0=1; //中断返回前,打开外部中断0中断
}
接下来我们在Proteus上进行实验
Proteus连接图如下:
3.两个外中断实验示例
题目:在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接有一只按钮开关K1。在外部中断1输入引脚(P3.3)接有一只按钮开关K2。要求K1和K2都未按下时,P1口的8只LED呈流水灯显示,仅K1(P3.2)按下再松开时,上下各4只LED交替闪烁10次,然后再回到流水灯显示。如果按下再松开K2(P3.3)时,P1口的8只LED全部闪烁10次,然后再回到流水灯显示。设置两个外中断的优先级相同。
本题用到了两个中断源,这两个中断源优先级是相同的,也就是一个中断源不会中断另一个中断源,我们只需要在上一道题一个中断源的基础上再加一个中断源就行了。
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
uchar j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main( )
{
uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f};
unsigned int a;
for(;;)
{
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
IP=0;
for(a=0;a<9;a++)
{
Delay(500);
P1=display[a];
}
}
void int0_isr(void) interrupt 0 using 1//中断0的中断函数
{
uchar n;
for(n=0;n<10;n++)
{
P1=0x0f;
Delay(500);
P1=0xf0;
Delay(500);
}
}
void int1_isr (void) interrupt 2 using 2//中断1的中断函数
{
uchar m;
for(m=0;m<10;m++)
{
P1=0xff;
Delay(500);
P1=0;
Delay(500);
}
}
Proteus图如下:
4.中断嵌套实验示例
题目:设计一中断嵌套程序:要求K1和K2都未按下时,P1口8只LED呈流水灯显示,当按一下K1时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下K2时,产生一个高优先级的外中断1请求(跳沿触发),进入外中断1中断服务程序,使8只LED全部闪烁。当显示5次后,再从外中断1返回继续执行外中断0中断服务程序,即P1口控制8只LED,上、下4只LED交替闪烁。设置外中断0为低优先级,外中断1为高优先级。
这题较上题涉及到了优先级,因此我们需要设置高优先级和低优先级。
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i)
{
uchar j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main( )
{
uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f};
unsigned int a;
for(;;)
{
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
PX0=0; //中断源0低优先级
PX1=1; //中断源1高优先级
for(a=0;a<9;a++)
{
Delay(500);
P1=display[a];
}
}
}
void int0_isr(void) interrupt 0 using 1
{
uchar n;
for(n=0;n<10;n++)
{
P1=0x0f;
Delay(500);
P1=0xf0;
Delay(500);
}
}
void int1_isr (void) interrupt 2 using 2
{
uchar m;
for(m=0;m<10;m++)
{
P1=0xff;
Delay(500);
P1=0;
Delay(500);
}
}
下面是Proteus演示:
二、定时器
1.51单片机定时器结构
AT89S51定时器/计数器结构见下图,定时器/计数器T0由特殊功能寄存器TH0、TL0构成,T1由特殊功能寄存器TH1、TL1构成。
T0、T1都有定时器和计数器两种工作模式,两种模式实质都是对脉冲信号进行计数,只不过计数信号来源不同。
计数器模式是对加在T0(P3.4)和T1(P3.5)两个引脚上的外部脉冲进行计数。
定时器模式是对系统时钟信号经12分频后的内部脉冲信号(机器周期)计数。由于系统时钟频率是定值,可根据计数值计算出定时时间。两个定时器/计数器属于增1计数器,即每计一个脉冲,计数器增1。
T0、T1具有4种工作方式 ,特殊功能寄存器TMOD用于选择定时器/计数器T0、T1的工作模式和工作方式。
2.定时器0.5s中断实现以及在keil示波器上验证
代码实现如下:
#include<reg51.h>
char i=100;
void main ()
{
TMOD=0x01;
TH0=0xee;
TL0=0x00;
P1=0x00;
EA=1;
ET0=1;
TR0=1;
while(1);
{
;
}
}
void timer0() interrupt 1
{
TH0=0xee;
TL0=0x00;
i--;
if(i<=0)
{
P1=~P1;
i=100;
}
}
我们打开keil软件,使用keil软件自带的虚拟逻辑示波器功能可以得到P1端口波形变化
效果图如下:
100次中断时间间隔差不多在0.5s左右,可以看到,误差是很小的。
3.计数器中断控制LED
题目:T1采用计数模式,方式1中断,计数输入引脚T1(P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1口的8只LED闪烁不停。
这里我们可以用计数器。
代码如下:
#include <reg51.h>
void Delay(unsigned int i)
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main( ) //主函数
{
TMOD=0x50; //设置定时器T1为方式1计数
TH1=0xff; //向TH1写入初值的高8位
TL1=0xfc; //向TL1写入初值的低8位
EA=1;
ET1=1; //定时器T1中断允许
TR1=1; //启动定时器T1
while(1) ; //无穷循环,等待计数中断
}
void T1_int(void) interrupt 3 //T1中断函数
{
for(;;) //无限循环
{
P1=0xff; //8位LED全灭
Delay(500) ; //延时500ms
P1=0; //8位LED全亮
Delay(500); //延时500ms
}
}
Proteus仿真如下:
作者:建筑玩家