51单片机中断系统与定时计数的应用实验【Proteus】【普中51开发板】
Proteus仿真实验
1. 单一外中断的应用
单片机对外设中断服务请求的整个中断响应和处理过程如下图。
实验电路
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
该电路的Proteus电路图如下。
实验程序
该电路的C程序如下。在Keil中编译以下程序,生成hex文件。
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( ),i形式参数,不能赋初值
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<333;j++) //晶振为12MHz,j选择与晶振频率有关
{;} //空函数
}
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中断
}
}
实验结果
将生成的hex文件导入Proteus电路中的单片机并仿真运行,结果如下。
2. 两个外中断的应用
当需要多个中断源时,只需增加相应的中断服务函数即可。
实验电路
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接有一只按钮开关。在外部中断1输入引脚(P3.3)接有一只按钮开关。要求两只开关都未按下时,P1口的8只LED呈流水灯显示,仅开关P3.2按下再松开时,上下各4只LED交替闪烁10次,然后再回到流水灯显示。如果按下再松开开关P3.3时,P1口的8只LED全部闪烁10次,然后再回到流水灯显示。设置两个外中断的优先级相同。
该电路的Proteus电路图如下。
实验程序
该电路的C程序如下。在Keil中编译以下程序,生成hex文件。
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( ),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; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
IP=0; //两个外部中断均为低优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P1=display[a]; //将已经定义的流水灯显示数据送到P1口
}
}
}
void int0_isr(void) interrupt 0 using 1//外中断0的中断服务函数
{
uchar n;
for(n=0;n<10;n++) //高、低4位显示10次
{
P1=0x0f; //低4位LED灭,高4位LED亮
Delay(500); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(500); //延时
}
}
void int1_isr (void) interrupt 2 using 2//外中断1中断服务函数
{
uchar m;
for(m=0;m<10;m++) //闪烁显示10次
{
P1=0xff; //全灭
Delay(500); //延时
P1=0; //全亮
Delay(500); //延时
}
}
实验结果
将生成的hex文件导入Proteus电路中的单片机并仿真运行,结果如下。
3. 两级中断嵌套的应用
中断嵌套只发生正执行一个低优先级中断,此时又有一高优先级中断产生,就会去执行高优先级中断服务程序。高优先级中断服务程序完成后,再继续执行低优先级中断程序。两级中断嵌套的过程如下图。
实验电路
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接有一只按钮开关。在外部中断1输入引脚(P3.3)接有一只按钮开关。要求两只开关都未按下时,P1口的8只LED呈流水灯显示,当按一下开关P3.2时,产生一个低优先级外中断0请求(跳沿触发),进入外中断0中断服务程序,上下4只LED交替闪烁。此时按一下开关P3.3时,产生一个高优先级的外中断1请求(跳沿触发),进入外中断1中断服务程序,使8只LED全部闪烁。当显示5次后,再从外中断1返回继续执行外中断0中断服务程序,即P1口控制8只LED,上、下4只LED交替闪烁。设置外中断0为低优先级,外中断1为高优先级。该电路的Proteus电路图如下。
实验程序
该电路的C程序如下。在Keil中编译以下程序,生成hex文件。
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( )
{
unsigned int j;
for(;i > 0;i--)
for(j=0;j<125;j++)
{;} //空函数
}
void main( ) //主函数
{
uchar display[9]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯显示数据组
uchar a;
for(;;)
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
PX0=0; //外部中断0为低优先级
PX1=1; //外部中断1为高优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P1=display[a]; //流水灯显示数据送到P1口驱动LED显示
}
}
}
void int0_isr(void) interrupt 0 using 0 //外中断0中断函数
{
for(;;)
{
P1=0x0f; //低4位LED灭,高4位LED亮
Delay(400); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
}
}
void int1_isr (void) interrupt 2 using 1 //外中断1中断函数
{
uchar m;
for(m=0;m<5;m++) //8位LED全亮全灭5次
{
P1=0; //8位LED全亮
Delay(500); //延时
P1=0xff; //8位LED全灭
Delay(500); //延时
}
}
实验结果
将生成的hex文件导入Proteus电路中的单片机并仿真运行,结果如下。
4. 定时器的应用
实验电路
在AT89C51的P1口上接有8只LED,采用T0方式1的定时中断方式,使P1口外接的8只LED每0.5s闪亮一次。该电路的Proteus电路图如下。
实验程序
T0工作在方式1,应使TMOD寄存器的M1, M0=01;应设置C/T*=0,为定时器模式;对T0的运行控制仅由TR0来控制,应使相应的GATE位为0。定时器T1不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x01。
设定时时间5ms(即5000µs),设T0计数初值为X,假设晶振的频率为11.0592MHz,由公式定时时间=(216−X)×12/晶振频率,得定时时间为(216−X)×12/11.0592,解得X=60928,转换成十六进制为0xee00,其中0xee装入TH0,0x00装入TL0。
本例由于采用定时器T0中断,因此需将IE寄存器中的EA、ET0位置1。将定时器控制寄存器TCON中的TR0=1,则启动定时器T0;TR0=0,则停止定时器T0定时。
综上,该电路的C程序如下。在Keil中编译以下程序,生成hex文件。
#include<reg51.h>
char i=100;
void main ()
{
TMOD=0x01; //定时器T0为方式1
TH0=0xee; //设置定时器初值
TL0=0x00;
P1=0x00; //P1口8个LED点亮
EA=1; //总中断开
ET0=1; //开T0中断
TR0=1; //启动T0
while(1); //循环等待
{
;
}
}
void timer0() interrupt 1 //T0中断程序
{
TH0=0xee; //重新赋初值
TL0=0x00;
i--; //循环次数减1
if(i<=0)
{
P1=~P1; //P1口按位取反
i=100; //重置循环次数
}
}
实验结果
将生成的hex文件导入Proteus电路中的单片机并仿真运行,结果如下。
在Keil中开启调试,使用波形图对信号P2监测,得波形图如下。波形图的每个周期时长约为0.47s,略低于0.5s.
5. 计数器的应用
实验电路
在AT89C51的P1口上接有8只LED,T1采用计数模式,方式1中断,计数输入引脚T1(P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1口的8只LED闪烁不停。该电路的Proteus电路图如下。
实验程序
T1工作在方式1,应使TMOD寄存器的M1, M0=01;应设置C/T*=1,为计数器模式;对T0的运行控制仅由TR0来控制,应使GATE0=0。定时器T0不使用,各相关位均设为0。所以,TMOD寄存器应初始化为0x50。
由于每按1次按钮开关,计数1次,按4次后,P1口的8只LED闪烁不停。因此计数器初值为65536−4=65532,将其转换成十六进制后为0xfffc,所以,TH0=0xff,TL0=0xfc。
本例由于采用T1中断,因此需将IE寄存器的EA、ET1位置1。将寄存器TCON中TR1=1,则启动T1计数;TR1=0,则停止T1计数。
综上,该电路的C程序如下。在Keil中编译以下程序,生成hex文件。
#include <reg51.h>
void Delay(unsigned int i) //定义延时函数Delay( ),i是形式参数,不能赋初值
{
unsigned int j;
for(;i>0;i--) //变量i由实际参数传入一个值,因此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
}
}
实验结果
将生成的hex文件导入Proteus电路中的单片机并仿真运行,结果如下。
普中51开发板实验
普中51开发板资料:https://pan.baidu.com/s/1t4M7p-WfYE7tDi36qqa-cQ?pwd=1234 提取码:1234
普中51开发板如下图所示。开发板软件的使用方法见:https://blog.csdn.net/cqjtu_pengzifu/article/details/136992942
普中51开发板上的8个LED接在单片机的P2接口上。开发板的左下角有4个黑色按钮K1, K2, K3, K4, 分别接在单片机的P3.1, P3.0, P3.2, P3.3接口上。因此每个实验需将其实验程序中的P1改为P2,并在程序中加入以下语句:
sbit LED1=P2^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
实验时,连接普中51开发板与电脑,将生成的hex文件下载至普中51开发板的单片机即开始运行。
1. 单一外中断的应用
实验程序
#include <reg51.h>
#define uchar unsigned char
sbit LED1=P2^0;
sbit KEY3=P3^2;
void Delay(unsigned int i) //延时函数Delay( ),i形式参数,不能赋初值
{
unsigned int j;
for(;i>0;i--)
for(j=0;j<333;j++) //晶振为12MHz,j选择与晶振频率有关
{;} //空函数
}
void main( ) //主函数
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
IT0=1; //选择外部中断0为跳沿触发方式
while(1) //循环
{P2=0;} // P2口的8只LED全亮
}
void int0( ) interrupt 0 using 0 //外中断0的中断服务函数
{
uchar m;
EX0=0; //禁止外部中断0中断
for(m=0;m<5;m++) //交替闪烁5次
{
P2=0x0f; //低4位LED灭,高4位LED亮
Delay(400) ; //延时
P2=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
EX0=1; //中断返回前,打开外部中断0中断
}
}
实验结果
2. 两个外中断的应用
实验程序
![VID_20240407144107 -small-original](E:\13352\Pictures\动图\VID_20240407144107 -small-original.gif)#include <reg51.h>
#define uchar unsigned char
sbit LED1=P2^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
void Delay(unsigned int i) //延时函数Delay( ),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; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
IP=0; //两个外部中断均为低优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P2=display[a]; //将已经定义的流水灯显示数据送到P2口
}
}
}
void int0_isr(void) interrupt 0 using 1//外中断0的中断服务函数
{
uchar n;
for(n=0;n<10;n++) //高、低4位显示10次
{
P2=0x0f; //低4位LED灭,高4位LED亮
Delay(500); //延时
P2=0xf0; //高4位LED灭,低4位LED亮
Delay(500); //延时
}
}
void int1_isr (void) interrupt 2 using 2//外中断1中断服务函数
{
uchar m;
for(m=0;m<10;m++) //闪烁显示10次
{
P2=0xff; //全灭
Delay(500); //延时
P2=0; //全亮
Delay(500); //延时
}
}
实验结果
3. 两级中断嵌套的应用
实验程序
#include <reg51.h>
#define uchar unsigned char
sbit LED1=P2^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
void Delay(unsigned int i) //延时函数Delay( )
{
unsigned int j;
for(;i > 0;i--)
for(j=0;j<125;j++)
{;} //空函数
}
void main( ) //主函数
{
uchar display[9]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯显示数据组
uchar a;
for(;;)
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
PX0=0; //外部中断0为低优先级
PX1=1; //外部中断1为高优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P2=display[a]; //流水灯显示数据送到P2口驱动LED显示
}
}
}
void int0_isr(void) interrupt 0 using 0 //外中断0中断函数
{
for(;;)
{
P2=0x0f; //低4位LED灭,高4位LED亮
Delay(400); //延时
P2=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
}
}
void int1_isr (void) interrupt 2 using 1 //外中断1中断函数
{
uchar m;
for(m=0;m<5;m++) //8位LED全亮全灭5次
{
P2=0; //8位LED全亮
Delay(500); //延时
P2=0xff; //8位LED全灭
Delay(500); //延时
}
}
实验结果
4. 定时器的应用
实验程序
#include<reg51.h>
sbit LED1=P2^0;
char i=100;
void main ()
{
TMOD=0x01; //定时器T0为方式1
TH0=0xee; //设置定时器初值
TL0=0x00;
P2=0x00; //P2口8个LED点亮
EA=1; //总中断开
ET0=1; //开T0中断
TR0=1; //启动T0
while(1); //循环等待
{
;
}
}
void timer0() interrupt 1 //T0中断程序
{
TH0=0xee; //重新赋初值
TL0=0x00;
i--; //循环次数减1
if(i<=0)
{
P2=~P2; //P2口按位取反
i=100; //重置循环次数
}
}