基于C51单片机的中断和定时器实验

51单片机学习知识请看:[https://pan.baidu.com/s/1Z16EDr5AyUfDpsbtRw-fLQ?pwd=kzs1]
提取码:kzs1
使用的软件平台:Keil和Proteus。

一、中断与定时器简介

1.中断

中断技术主要用于实时监测与控制,要求单片机能及时地响应中断请求源提出的服务请求,并快速响应与及时处理。当中断请求源发出中断请求时,如中断请求被允许,单片机暂时中止当前正在执行的主程序,转到中断服务处理程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。
在这里插入图片描述

2.定时器

C51单片机的定时器原理是通过内部的时钟信号对寄存器进行自动加一操作,当达到设定值时触发溢出中断,从而实现定时功能。具体来说,C51单片机内部有一个由晶振决定的时钟周期,这个时钟周期通常由外部晶振频率决定,例如使用12MHz晶振,其时钟周期为1/12MHz。在这个基础上,一个机器周期通常包含12个时钟周期,因此如果晶振是12MHz的话,一个机器周期就是1μs。51单片机拥有两组定时器/计数器(定时器0和定时器1),它们是独立于CPU运行的,也就是说它们的执行不需要CPU的直接参与,这样设计是为了提高单片机的效率,让CPU去处理更加复杂的事情。在定时模式下,每当经过一个机器周期,定时器的计数寄存器(THx和TLx)就会自动加1。当计数器从设定的初值开始计数到达最大值后,会触发一个溢出,此时相应的溢出中断标志位会被置位,如果使能了中断,则会向CPU发出中断请求。用户可以通过设置这些寄存器的初值来控制定时的时间长度,以及通过编程中断服务程序来定义定时器溢出后要执行的操作。

二、实现

1.LED中断实验

1.1单一外中断

具体效果:在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
电路图
在这里插入图片描述
KeilC语言代码

##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中断
}		

Proteus仿真效果

中断1

1.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  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); 				//延时
  	}
  }

仿真结果

中断2

1.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为高优先级。
电路图
在这里插入图片描述
代码:

#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);			//延时
  }
}

仿真结果

中断3

2.定时器延时实验

2.1 P1口控制8只LED每0.5s闪亮一次

具体要求:在AT89S51的P1口上接有8只LED,原理电路见图7-13。采用T0方式1的定时中断方式,使P1口外接的8只LED每0.5s闪亮一次。
电路图
在这里插入图片描述
代码

#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;
	TH1=0xff;
	TL1=0xfc;
	EA=1;
	ET1=1;
	TR1=1;
	while(1);
	
}

仿真效果

定时器延时一秒

用Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察
步骤:
1.打开Keil,打开需要查看波形的工程,点击右上的Debug按钮,进入调试界面。
在这里插入图片描述
2.选择Logic Analyzer。
在这里插入图片描述
3.点击Setup,添加端口。
在这里插入图片描述
在这里插入图片描述

4.点击close,再点击Run查看波形图。
在这里插入图片描述
在Keil仿真环境中,使用虚拟逻辑仪测量周期数的精度相对较高,并且通常比软件循环进行周期定时的方式更为精准。

2.2计数器的应用

具体要求: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;			
	TH1=0xff;			
	TL1=0xfc;			
	EA=1;  
	 	ET1=1;   			 
 	TR1=1;   			
 	while(1) ;		  	
 }

void T1_int(void)  interrupt 3  	
{
	for(;;)				
 	{	
		P1=0xff;			
 		Delay(500) ;		
 		P1=0;			
 		Delay(500); 		 
	}							
}

实验结果

计数延时

代码优化

在中断函数中使用延时循环是一种不好的编程实践,因为它会占用CPU资源,降低主程序的执行效率。一种更好的方式是在主程序中预先定义好几种LED亮灯模式,并使用一个模式标志位来选择当前应执行的模式。当按键中断发生时,中断服务程序只需要改变这个模式标志位,而不需要做其他处理。这只是一种思路,可以根据具体情况改变灯亮的模式函数。

#include <reg51.h>

// 定义LED灯的引脚
sbit LED = P2^0;

// 定义按键的引脚
sbit KEY = P3^2;

// 定义模式标志位
unsigned char mode = 0;

// 定义几种LED亮灯模式
void mode0() {
    LED = 0; // LED灯关闭
}

void mode1() {
    LED = 1; // LED灯常亮
}

void mode2() {
    LED = ~LED; // LED灯闪烁
}

// 按键中断服务程序
void key_isr() interrupt 0 {
    mode = (mode + 1) % 3; // 改变模式标志位
}

// 主程序
void main() {
    IT0 = 1; // 设置外部中断0为下降沿触发
    EX0 = 1; // 使能外部中断0
    EA = 1; // 使能全局中断

    while(1) {
        switch(mode) {
            case 0:
                mode0();
                break;
            case 1:
                mode1();
                break;
            case 2:
                mode2();
                break;
        }
    }
}

在这个代码中,定义了三种LED亮灯模式:关闭、常亮和闪烁。主程序在一个无限循环中根据模式标志位选择对应的亮灯模式。当按键中断发生时,中断服务程序只改变模式标志位,而不做其他处理。这样,我们就可以避免在中断函数中使用延时循环,提高主程序的执行效率。

三、总结

本次进行了C51单片机的中断和计时器的实验,深入了解51单片机中断原理。学习了外部中断、定时器/计数器中断的编程方式;学习了中断响应、中断优先级、中断标志位复位等原理,了解了定时器/计数器的工作原理。

  • 43
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C51单片机中断单片机应用中的重要部分,可以提高程序的响应速度和实时性。下面是C51单片机中断实验的总结: 1. 中断的概念和作用 中断是指在程序执行过程中,由硬件或软件发起的一种特殊事件。中断可以打断程序的正常执行,转而执行中断服务程序(ISR),处理该事件后返回到原来的程序执行位置。中断可以提高程序的实时性和响应速度。 2. 中断的分类 C51单片机中断可以分为外部中断定时器中断两种。外部中断是由外部设备(如按键、传感器等)产生的中断信号,而定时器中断则是由定时器模块产生的中断信号。 3. 中断的使用方法 在C51单片机中,中断的使用需要注册中断服务程序,并设置中断优先级和中断向量。具体步骤如下: (1)编写中断服务程序,命名为“中断向量号+中断服务程序名”,例如“INT0_ISR”。 (2)在主程序中设置中断优先级和中断向量,如下所示: ```c EA = 1; // 允许中断 EX0 = 1; // 允许外部中断0 IT0 = 1; // 设置外部中断0为下降沿触发 ``` (3)在中断服务程序中处理相应的中断事件,如下所示: ```c void INT0_ISR(void) interrupt 0 { // 处理外部中断0事件 } ``` 4. 中断实验的设计 中断实验可选用外部中断定时器中断。例如,设计一个按键控制LED的实验,当按下按键时,LED亮起;松开按键时,LED熄灭。实验过程如下: (1)连接电路,将按键和LED分别连接到P3.2和P1.0口。 (2)编写中断服务程序,处理外部中断0事件: ```c void INT0_ISR(void) interrupt 0 { if (P3_2 == 0) // 检测按键是否按下 { P1_0 = 1; // 点亮LED } else { P1_0 = 0; // 熄灭LED } } ``` (3)在主程序中设置中断优先级和中断向量,如下所示: ```c EA = 1; // 允许中断 EX0 = 1; // 允许外部中断0 IT0 = 1; // 设置外部中断0为下降沿触发 ``` (4)启动程序,按下按键时,LED亮起;松开按键时,LED熄灭。 5. 中断实验的注意事项 (1)中断服务程序中应尽量避免使用延时函数和循环语句,以免影响程序的实时性。 (2)在编写中断服务程序时,应注意保存现场和恢复现场,以保证程序的正确执行。 (3)在使用多个中断时,应注意设置中断优先级,以保证高优先级中断能够及时响应。 6. 总结 C51单片机中断是提高程序实时性和响应速度的重要手段,掌握中断的使用方法和注意事项对于单片机应用开发具有重要意义。在实际应用中,应根据具体情况选择合适的中断类型并合理设置中断优先级,以确保程序的正确执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值