一、概念简述
1、中断
中断是指计算机系统中发生的一种事件,可以打断正常的程序执行流程。中断可以由硬件或软件触发,用于处理紧急事件、外部设备请求、错误处理等。在中断发生时,当前正在执行的程序会被暂停,系统会转而执行中断处理程序来响应中断事件,处理完毕后再返回到原程序继续执行。这种机制可以提高系统的响应速度和效率。
2、定时器
定时器是计算机系统中的一种重要组件,用于在特定的时间间隔或特定时间点触发事件。定时器可以用于各种用途,例如调度任务、测量时间间隔、生成时钟信号等。
在计算机系统中,定时器通常由硬件和/或操作系统提供支持。硬件定时器是一个计数器,可以在每个时钟周期递增,当计数器达到预设的值时触发中断。操作系统也可以通过软件定时器来实现类似的功能,通过编程设置定时器的计时器和中断处理程序来实现定时功能。
定时器在计算机系统中有着广泛的应用,例如在操作系统中用于任务调度、在网络通信中用于超时处理、在实时系统中用于实时任务的处理等。定时器的准确性和稳定性对系统的性能和可靠性都有着重要的影响。
二、按键中断控制流水灯
1、单一外中断
实验原理:
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
Proteus原理图:
C语言代码:
#include <reg51.h>
#define uchar unsigned char
// 延时函数Delay( ),i形式参数,不能赋初值
void Delay(unsigned int 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全亮
}
}
// 外中断0的中断服务函数
void int0() interrupt 0 using 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仿真效果图:
开发板效果:
2、双外中断
实验原理:
在单片机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次,然后再回到流水灯显示。设置两个外中断的优先级相同。
Proteus原理图:
C语言代码:
#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); // 延时
}
}
Proteus仿真效果图:
开发板效果:
3、嵌套中断
实验原理:
中断嵌套只发生正执行一个低优先级中断,此时又有一高优先级中断产生,就会去执行高优先级中断服务程序。高优先级中断服务程序完成后,再继续执行低优先级中断程序。
设计一中断嵌套程序:要求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为高优先级。
Proteus原理图如双中断所示
C语言代码:
#include <reg51.h>
#define uchar unsigned char
// 延时函数
void Delay(unsigned int i) // Delay function
{
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显示
}
}
}
// 外中断0中断函数
void int0_isr(void) interrupt 0 using 0
{
for(;;)
{
P1=0x0f; // 低4位LED灭,高4位LED亮
Delay(400); // 延时
P1=0xf0; // 高4位LED灭,低4位LED亮
Delay(400); // 延时
}
}
// 外中断1中断函数
void int1_isr (void) interrupt 2 using 1
{
uchar m;
for(m=0; m<5; m++) // 8位LED全亮全灭5次
{
P1=0; // 8位LED全亮
Delay(500); // 延时
P1=0xff; // 8位LED全灭
Delay(500); // 延时
}
}
Proteus仿真效果图:
开发板效果:
4、定时器控制
实验原理:
定时器控制LED灯每隔1s周期性亮灭,并用Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察,测量真实的周期数,并与上次采用软件循环进行周期定时的精度进行对比,看哪一种方式更加精准。
Proteus原理图:
C语言代码:
#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; // 重置循环次数
}
}
Proteus仿真效果图:
开发板效果:
Keil波形图:
5、计数器控制
实验原理:
T1采用计数模式,方式1中断,计数输入引脚T1(P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1口的8只LED闪烁不停。
Proteus原理图:
C语言代码:
#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
}
}
Proteus仿真效果图: