中断与定时计数原理及应用

目录

  • 概念介绍
  • 1.完成按键中断控制流水灯
  • (1)示例1
  • (2)示例2
  • 2.用Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察
  • 3.采用计数器中断实现 按4次按钮开关后,P1口的8只LED闪烁不停
  • 4.代码优化
  • 目的:深入了解51单片机中断原理。掌握外部中断、定时器/计数器中断的编程方式;了解中断响应、中断优先级、中断标志位复位等原理,掌握二级中断、中断嵌套的具体应用编程; 了解定时器/计数器的工作原理,掌握计数器初值计算方法,定时/计数中断服务的编程开发。

    使用软件以及硬件:keil、Proteus、普中8051单片机板

    概念介绍

    知道下列一些概念以后可以让我们读懂本次实验的一系列代码,当然你也可以直接跳过此处,遇到看不懂的部分再返回查找。

    中断:在计算机科学和硬件设计中,是一种处理机制,当计算机系统检测到一个需要立即处理的外部或内部事件时,它会暂停当前正在执行的任务并转而去执行一段专门处理该事件的程序代码,完成中断服务后CPU(中央处理器)会恢复先前被打断的任务,从暂停的地方继续执行。

    定时器:在8051系列单片机中,定时器是16位的,由TH1(高8位)和TL1(低8位)两个寄存器组成;当定时器启动后,它会从预设的初值开始递增计数,每过一个机器周期加1

    自动重装与定时器中断:当TL1(低8位)计满(从0x00计到0xFF)会发生溢出,此时硬件会自动将TH1的值装载到TL1中,同时TH1的内容不变,如果TH1也被计满且再次溢出,那么通常会有中断发生(如果中断已启用的话),并在中断服务程序中重新装载新的定时初值

    我们采取寄存器编程所以在编程前,我们要了解51系列单片机的一些寄存器和关键字:

    EA:设置全局中断使能位, 设置为1表示允许CPU响应所有可屏蔽中断。

    EX0和EX1:分别代表外部中断0和外部中断1的使能位。设置为1表示开启对应的外部中断功能。

    IT0和IT1:用于设置外部中断0和中断1的工作模式。当IT0/IT1=1时,对应中断设置为边沿触发方式(下降沿触发)即当指定引脚上的电平从高变低时会触发中断请求;若为0,则会被配置为低电平触发,即只要该引脚保持在低电平状态,就会一直请求中断,直到该引脚变为高电平为止。

    IP寄存器:用于设置中断优先级。每个中断源都可以独立设置优先级

    interrupt 0: 这是一个关键字或者修饰符,指定中断函数是作为外部中断0的中断服务程序。也就是说,当外部中断0触发时,CPU将暂停当前正在执行的任务并跳转到中断函数去执行中断处理代码

    using 1:这意味着中断服务程序将使用工作寄存器组1

    ET1:当ET1=1时启用定时器1中断,即当定时器1计数溢出时,会产生中断请求

    TR1:当TR1=1时启动定时器1,开始进行定时或计数操作

    TH1:设置定时器1的高8位初值

    TL1: 设置定时器1的低8位初值

    TMOD:是定时器/计数器模式控制寄存器,这个8位寄存器用于配置单片机内部的两个定时器/计数器(Timer 0 和 Timer 1)的工作模式和功能

    1.完成按键中断控制流水灯

    (1)示例1

    **实验要求:**在单片机P1口上接有8只LED.在外部中断0输入引脚接一只按钮开关K1.要求将外部中断0设置为电平触发。程序启动时,P1 上的8只LED全亮。每按一次按钮开关K1, 使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮

    电路图:

    代码部分:

    #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++)
    {;}
    }
     void main()
    {
    	EA=1;//允许中断
    	EX0=1;//使能中断0
    	IT0=1;//设置中断0的工作模式为下降沿触发
     while (1)
    {P2=0;}//主程序是led灯全亮(P1.0~P1.8均为低电平)
    }
     void int0() interrupt 0 using 0//中断0触发使用工作寄存器组0                         	  
    {
    	uchar m ;
    	EX0=0;//清除中断
     for( m =0; m <5; m ++)//执行中断程序
    {
    	P2=0x0f;//对应二进制为:00001111,实现了D1~D4亮,D5~D8灭
    	Delay (400);//延时
    	P2=0xf0;//对应二进制为:11110000,实现了D1~D4灭,D5~D8亮
    	Delay (400);
    	EX0=1;
    }
    
    }
    

    Proteus仿真效果:
    请添加图片描述
    普中开发板效果如下:

    (2)示例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次,然后再回到流水灯显示。设置两个外中断的优先级相同。

    电路图:

    代码部分:

    #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 int0_isr(void) interrupt 0 using 1//中断1
    {
    	uchar a;
    	for(a=0;a<10;a++)//
    	{
    		P2=0x0f;
    		delay(500);
    		P2=0xf0;
    		delay(500);
    	}
    }
    void int1_isr(void) interrupt 2 using 2//中断2
    {
    	uchar m;
    	for(m=0;m<10;m++)
    	{
    		P2=0xff;//LED全灭
    		delay(500);
    		P2=0;//LED全亮
    		delay(500);
    	}
    }
    void main()//主程序流水灯
    {
    	uchar display[9]={0xff,0xfe,0xfb,0xf7,0xef,0xdf,0x7f};
    	unsigned int a;
    	while(1)
    	{
    		EA=1;
    		EX0=1;
    		EX1=1;
    		IT0=1;
    		IT1=1;
    		IP=0;
    		for(a=0;a<9;a++)
    		{
    			delay(500);
    			P2=display[a];
    		}
    	}
    }
    

    仿真效果:

    请添加图片描述

    普中开发板效果如下:

    2.用Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察

    虚拟逻辑仪对LED管脚进行波形观察步骤:

    1.Debug按钮,进入调试界面

    2.选择Logic Analyzer

    3.点击Setup…

    4.添加并设置引脚和串口

    5.点击左上角的Run按钮,全速运行


    由于硬件仿真能更真实地反映电路运行状态,因此其测量的周期数会比纯软件循环的方式更为准确,但在实际情况中,如果软件循环的时钟精度足够高且无其他中断干扰,两者可能相差不大

    3.采用计数器中断实现 按4次按钮开关后,P1口的8只LED闪烁不停

    实验要求:T1采用计数模式,方式1中断,计数输入引脚T1 (P3.5)上外接按钮开关,作为计数信号输入。按4次按钮开关后,P1 口的8只LED闪烁不停。

    可以查看普中51单片机开发手册第二十一章(计时器中断),第十九章(中断),第十三章(独立按键)

    链接:https://pan.baidu.com/s/1MLQqkSWsm1Ibt1R8i6HS-w
    提取码:9962




    从上图中可以看出,4 个独立按键的控制管脚连接到 51 单片机的 P3.0-P3.3 脚上。其中 K1 连接在 P3.1 上,K2 连接在 P3.0 上,K3 连接在 P3.2 上,K4 连接 在 P3.3 上。4 个按键另一端全部连接在 GND,当按键按下后,对应 IO 口即为低 电平。

    代码部分:

    #include<reg51.h>
    void delay(unsigned int)
    {
    	unsigned int j;
    	for(;i>0;i--)
    	for(j=0;j<125;j++)
    	{;}
    }	
    void T1_int(void) interrupt 3
    {
    	while(1)
    	{
    		P1=0xff;
    		delay(500);
    		P1=0;
    		delay(500);
    	}
    }	
    void main()
    {
    	TMOD=0x50;//表示定时器1(T1)被设置为8位自动重载定时器模式
    	TH1=0xff;
    	TL1=0xfc;
    	EA=1;
    	ET1=1;
    	TR1=1;
    	while(1);
    	
    }
    

    电路图:

    仿真效果:
    请添加图片描述
    通过查表发现无论是计数器T1还是T0都无法受到独立按键和矩阵按键的控制,由于模块固定所以这与仿真自己搭电路是有所区别,所以我就对代码进行了修改:设置一个变量K来记录,按键被按下的次数,如果K=4,就让P1口的8只LED闪烁不停(自己写一个计数器)

    #include<reg51.h>
    unsigned int k;//记录按钮按下的次数
    void delay(unsigned int i)
    {
    	unsigned int j;
    	for(;i>0;i--)
    	for(j=0;j<125;j++)
    	{;}
    }	
     void int0() interrupt 0 using 0
    {
    	k++;
    }	
    void main()
    {
    	EA=1;
    	EX0=1;
    	IT0=1;
    	k=0;//初始化为0
    	while(1)
    	{
    	  if(k==4){
    		while(1)
    		{
    		P2=0xff;
    		delay(500);
    		P2=0;
    		delay(500);
    		}
    	}
      }
    }
    

    实验现象如下:

    4.代码优化

    存在的问题:中断函数中要尽量避免使用执行时间较长(耗时)的代码,以避免中断服务影响到主程序代码的执行效率,但是在上面外部中断的实验中,中断函数采用了软件延时函数去控制LED亮灭的间隔周期

    优化方案:可以在main函数中写好几种亮灯模式代码和对应的模式标志位,按键中断发生后,中断服务程序只改变模式标志位,不做其他处理;由主程序根据模式标志,选择不同的亮灯模式

    以示例2为例子进行优化代码:

    #include<reg51.h>
    #define uchar unsigned char
    unsigned int p=1;//全局变量用于标志led的运行模式,默认为模式1
    void delay(unsigned int i)
    {
    	uchar j;
    	for(;i>0;i--)
    	for(j=0;j<125;j++)
    	{;}
    }
    void int0_isr() interrupt 0 using 1//中断0,启用模式2
    {	
    
    p=2;
    
    }
    void int1_isr() interrupt 2 using 2//中断1,启用模式3
    {
    	p=3;
    }
    void main()
    {
    	uchar display[9]={0xff,0xfe,0xfb,0xf7,0xef,0xdf,0x7f};
    	unsigned int a;
    	while(1)
    	{
    		EA=1;
    		EX0=1;
    		EX1=1;
    		IT0=1;
    		IT1=1;
    		IP=0;
    		switch(p)
    		{	
    		case 1://模式1
    			for(a=0;a<9;a++)
    		{
    			delay(500);
    			P1=display[a];
    		}
    		break;
    		case 2://模式2
    		for(a=0;a<10;a++)
    	{
    		P1=0x0f;
    		delay(500);
    		P1=0xf0;
    		delay(500);
    	}
    	p=1;//切换回模式1
    	break;
    	case 3://模式3
    		for(a=0;a<10;a++)
    	{
    		P1=0xff;
    		delay(500);
    		P1=0;
    		delay(500);
    	}	
    	p=1;//切换回模式1
    	break;
    	default:;
    	break;
    	}
    	}
    }
    

    效果如下:
    请添加图片描述
    参考资料:观察信号波形——Keil仿真调试 / SaleaeLogic16逻辑仪_keill的逻辑分析仪可以观察曲线-CSDN博客

    作者:落笔太慌张~

    物联沃分享整理
    物联沃-IOTWORD物联网 » 中断与定时计数原理及应用

    发表评论