外部中断与内部中断原理与使用

1.解释
计算机执行某一程序时,发生了紧急事件或者有特殊请求,CPU暂停某程序的执行,转而去处理上述事件,处理完毕后再重新执行原来被打断的程序。
2.步骤
中断请求>中断响应>中断处理>中断返回
外部中断与内部中断原理与使用_第1张图片
3.51的中断源
有五个中断源
外部中断源2个
1.INT0 — 由P3.2端口控制引入,低水平或者下降沿引起。(下降沿就是给5V后给0V形成下降电压)
2.INT1 —由P3.3端口控制引入,低水平或者下降沿引起。
(这两个中断源标志与中断方式由特殊功能寄存器TCON的低四位控制)
内部中断源3个
1.T0 —定时器/计数器0中断,由T0回0溢出引起。
2.T1 —定时器/计数器1中断,由T1回0溢出引起。
3.T1/RI —串行I/O口中断,串行端口完成一帧字符发送引起。
(由TCON和SCON控制)
4.51内部结构图
外部中断与内部中断原理与使用_第2张图片

要运用那个中断就要打开对应的开关,首先EA(总开关)要打开,假设要打开外部中断0,就需要再控制IT0与EX0与PX0。
5.如何使用中断
(1.打开对应的中断开关)
EA —总开关,EA打开CPU接受中断请求;EA关闭,CPU屏蔽任何中断请求。
外部中断开关
EX1 —EX1打开,外部中断1打开,反之。
EX0 —EX0打开,外部中断0打开,反之。
内部中断打开
ET0打开,T0的溢出中断打开,反之。
ET1 —ET1打开,T1的定时器/计数器溢出中断打开,反之。
ET2 —ET2打开,T2的定时器/计数器溢出中断打开,反之。
ES —ES打开,串行口一中断打开,反之。请添加图片描述
也可以按上表,8位2进制赋予IE打开对应开关。
(2.配置中断方式(触发对应中断的条件))
外部中断方式控制
IT0 —IT0为1,为下降沿触发方式。TT0为1,低电平触发方式。(控制在3.2脚)
IT1 —IT1为1,为下降沿触发方式。TT1为1,低电平触发方式。(控制在3.3脚)
内部中断方式控制
TR1 —定时器1的运行控制位。
TR0 —定时器0的运行控制位。
TF0 —T0溢出中断标志,TO被允许开始计数时,从初值加一开始运算,当溢出时,硬件自动命TF0为1,引发T0中断,当执行完,硬件自动清0。
TF1—T1溢出中断标志,T1被允许开始计数时,从初值加一开始运算,当溢出时,硬件自动命TF1为1,引发T1中断,当执行完,硬件自动清0。

内部中断模式位
外部中断与内部中断原理与使用_第3张图片
外部中断与内部中断原理与使用_第4张图片
想要打开内部中断0与1什么模式就命对应TMOD为什么值,如果我需要定时器0的定时功能,TMOD=0000 0001=0x01。如果需要定时器0计数,需要把C/T打开,就是TMOD=00000101=0x05。

(3.触发优先级)
当多个中断同时发生,按下面顺序
注意:优先级高的中断可以打断优先级低的中断
外部中断与内部中断原理与使用_第5张图片
(4.中断处理函数)
外部中断与内部中断原理与使用_第6张图片
步骤总结
1.打开对应的中断开关
2.控制对应中断执行的条件
3.写中断函数

以下是各个中断的函数示例(4个)

外部中断1函数实例(外部中断0同样是这样用)

#include "reg52.h"			 
sbit key1=P3^1;	    
sbit flag = P3^3;
void delay(unsigned int i)
{
	while(i--);	
}
void lnt1init()
{
	EA = 1;          //总开关打开
	EX1 = 1;          //外部中断开关打开
	IT1 = 1;          //触发方式(下降沿)
}
void int1() interrupt 2  //外部中断函数,interrupt后面的数字根据优先级那个图有个入口数字
{
	P2 = ~P2;       //由亮变无或由无变亮
}
void keypros()
{
	if(key1==0)		 //独立按键被按下
	{	   
		delay(100);
		if(key1==0)	  //按键消抖
		{
			   flag = 1;//产生下降沿,就会进入到中断函数
		       flag = 0;
			  while(!key1);   //松手检测
		} 
	}		
}

void main()
{	
	lnt1init();
	P2 = 0x00;    //先取全部亮
	while(1)
	{	
		keypros(); 	
	}		
}

内部中断0的软件中断(用作计时器)
注意这里不是中断函数的使用,而是运用定时器0,故它的函数开关不需要打开

#include "reg52.h"			 
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4;
sbit  key2 = P3^0; 
unsigned char smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(unsigned int z)    
{
	unsigned int x,y;
	for(x=z;x>0;x--)
	   for(y=120;y>0;y--);
}
void timefrist()
{
	TR0 = 1;                 //打开定时器0开关
	TMOD = 0x01;             //定义模式
	TH0 = 0x4B;              //定义初始值后不断加1,每加1为1.085us,从到19453到65535共46085次,共50ms
	TL0 = 0xfd;              //前面那个值为19453的16进制的前2位,这个为它的后2位。19453 = 4Bfd
}
unsigned char miao=0;        //秒
unsigned char fen=0;         //分
void DigDisplay()
{
	LA=1;LB=1;LC=1;        //位选,这里用的是转码器3个2进制可以控制8个七段码那个亮
	P0 = smgduan[fen];     //段选,同样是动态规划的思想
	delay(5);
	
	LA=0;LB=1;LC=1;       
	P0 = smgduan[miao];
	delay(5);
}
void main()
{	
	unsigned char text=0;
	timefrist();
	while(1)
	{	
		if(TF0==1)          //当定时器0溢出了,即经过50ms,TF0自动设置为1;
		{
			TF0 = 0;        //归0
			TH0 = 0x4B;     //每次使用都要重新定义为50ms
	        TL0 = 0xfd;  
			text++;
			if(text==20)   //当它进行了20次,20*50ms=1s
			{
				text =0;  //归0,之后继续加
				miao++;   //秒加1
			}
			if(miao==10)  //秒为10的时候就可以进位了
			{
				miao = 0;  //归0
				fen++;     //秒十位+1
			}
		}
    DigDisplay();	      //上面执行很快,所以一直都是动态显示	
	}
}

内部中断定时器0与按键
独立按键1可以实现数值+1,独立按键2实现数值-1
解释:因为按键有个按键消抖与松手检测会影响动态显示。特别是松手检测,如果你不松手会一直停在那里,不松手就无法动态显示。所有我们用定时器0直接控制,当经过5ms就用一次显示函数,就算不松手也是有中断自动执行显示函数。

#include "reg52.h"
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4;
sbit  key1 = P3^0;     //按键1
sbit  key2 = P3^1;     //按键2
unsigned char smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(unsigned int z)    
{
	unsigned int x,y;
	for(x=z;x>0;x--)
	   for(y=120;y>0;y--);
}
void timefrist()
{
	EA = 1;          //打开总开关
	ET0 = 1;         //中断函数0的开关
	TR0 = 1;         //打开定时器0开关
	TMOD = 0x01;      //模式一,定时模式
	TH0 = 0xED;       //这里改值了,到上限就5ms
	TL0 = 0xFF;
}
unsigned char miao=0;
void DigDisplay(unsigned char h)
{
	unsigned char a=h%10;                //个位
	unsigned char b=h/10//十位
	static unsigned char wei=0;         //静态变量,就是函数执行完也不会抹去这个变量的值,在次使用函数值可以用
	switch(wei)                        //这里重新布局,我们这里不断交换显示,用一次函数就显示一个,当快速多显示就动态显示
	{
		case 0: LA=1;LB=1;LC=1;P0 = smgduan[b];break;      //wei值0与1不断交换,就动态显示
		case 1:	LA=0;LB=1;LC=1;P0 = smgduan[a];break;  
	}
	wei++;                                            //用过之后++
	if(wei==2)                                 //我们只要1与0不断交换,为2时就重新回0
	{
		wei = 0;
	}
}
void timer0() interrupt 1
{
	 TH0 = 0xED;         //重新定义5ms初始值
	 TL0 = 0xFF;
	 DigDisplay(miao);   //显示,不断5ms显示就是动态显示
}
void main()
{	
	timefrist();
	while(1)
	{
		if(key1==0)  //为0,按键被按下
		{
			delay(20);
			if(key1==0)   //按键消抖
			{
				miao++;    //全局miao加1,显示就会加1了
				while(!key1);   //松手检测
			}
		}
		if(key2==0)          //同理
		{
			delay(5);
			if(key2==0)
			{
				miao--;
				while(!key2); 
			}
		}
   }
}

内部中断定时器与计数器同时使用
内部中断0用作计数(就是3.4口有电压波动TH0与TL0的总值就会加1,由于TH0为后2位,加不到,后面就为TL0加一),内部中断1用作定时器
思想:定时器1到时间就使LED电压反转(亮与不亮),然后该LED的与P3.4口连在一起,当LED灯不断闪烁,电压不断变化,3.4口就会感受电压波动自动使TL0加1,然后把TL0值传递显示,就可以观察TL0变化。

#include "reg52.h"			 
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4;
sbit  key2 = P3^0; 
sbit LED = P2^0;
unsigned char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(unsigned int z)    
{
	unsigned int x,y;
	for(x=z;x>0;x--)
	   for(y=120;y>0;y--);
}
void timefrist0()
{
	TR0 = 1;               //打开计数器1
	TMOD |= 0x05;          //模式值为5
	TH0 = 0;               //计数功能,设为0
	TL0 = 0;
}
void timefrist1()
{
	EA = 1;          
	TR1 = 1;           //中断1的开关
	TMOD |= 0x10;      //0001 0000
	TH1 = 0x4b;        //铁打的50ms
	TL1 = 0xfd;
}
void DigDisplay(unsigned char miao)
{
	LA=1;LB=1;LC=1;        //8动态显示函数
	P0 = smgduan[miao];
	delay(5);
	
	LA=0;LB=1;LC=1;       //6
	P0 = smgduan[miao/10];
	delay(5);
}
void main()
{	
	unsigned char text=0;
	timefrist0();    //中断0与1的初始定义
	timefrist1();
	LED = 0;
	while(1)
	{	
		if(TF1 == 1)  //定时器0溢出,50ms过
		{
			TF1 = 0;
			TH1 = 0x4b;
	        TL1 = 0xfd;
			text++;
			if(text==10)  //经过 0.5s
			{
				text = 0;
				LED = ~LED;   //变化一次,形成电压给P3.4
			}
		}
    DigDisplay(TL0);    //上面动作很快,动态显示一直在执行
	}
}

你可能感兴趣的:(51清翔笔记,单片机,嵌入式)