51单片机的中断系统

一、中断的概念
中断是指:CPU在处理某一事件A时,发生了另一事件B,请求CPU迅速去处理(中断发生);CPU暂时停止当前的工作(中断响应),转去处理事件B(中断服务);待CPU将事件B处理完毕后,再回到原来事件A被中断的地方继续去处理事件A(中断返回)。(就是我在打麻将的时候来了一个快递,我就停止打麻将去拿快递,拿完快递又接着打麻将了。拿快递的过程就是中断)
在这里插入图片描述
二、中断系统
80C51的中断系统有5个中断源(80C52有 6个) ,2个优先级,可实现二级中断嵌套 。(而80C52单片机有四个中断优先级,即可实现四级中断服务嵌套)下图可以看出EA是中断的总开关。如果此开关取0,就会强行屏蔽所有的中断,因此,只要用到中断,此开关必须取1。ET0是专门针对定时器0中断的局部开关。如果此开关取0,则会屏蔽定时器0的中断,如果取1则允许定时器0中断。如果要定时器0能产生中断,那么总开关EA与ET0必须同时都打开(都取1),两者缺一不可。图上几个寄存器在下面介绍,介绍的时候对比着这张图更容易理解。
在这里插入图片描述
在使用单片机时,要设置两个与单片机有关的寄存器:
1、中断允许寄存器IE
用来设定各中断源的打开和关闭,控制所有中断以及某个中断源的开放和屏蔽。可进行位寻址,单片机复位时IE被全部清0。(52单片机第五位是ET2,第六位是无效位)
在这里插入图片描述
EA:全局中断允许位。EA=1,打开全局中断;EA=0,关闭全部中断。
ES:串行口中断允许位。ES=1,打开串行口中断;ES=0,关闭串行口中断。
ET1(0):定时器/计数器1(0)中断允许位。ET1(0)=1,打开T1(0)中断;ET1(0)=0,关闭T1(0)中断。
EX1(0):外部中断1(0)中断允许位。EX1(0)=1,打开外部中断1(0)中断;EX1(0)=0,关闭外部中断1(0)中断。
2、中断优先级寄存器IP
用来设定各中断源中属于两(四)级中断中的哪一级,可进行位寻址,单片机复位时IP被全部清0。80C51单片机有两个中断优先级,即可实现二级中断服务嵌套。每个中断源的中断优先级都是由中断优先级寄存器IP中的相应位的状态来规定的 。而80C52单片机有四个中断优先级,即可实现四级中断服务嵌套。每个中断源的中断优先级由中断优先级寄存器IP和IPH中的相应位的状态来规定的 。
在这里插入图片描述
PS:串行口中断优先级控制位。PS=1,串行口中断定义为高优先级中断;PS=0,串行口中断定义为低优先级中断。
PT1(0):定时器/ 计数器1(0)中断优先级控制位。PT1(0)=1,定时器/ 计数器1(0)中断定义为高优先级中断;PT1(0)=0,定时器/ 计数器1(0)中断定义为低优先级中断。
PX1(0):外部中断1(0)中断优先级控制位。PX1(0)=1,外部中断1(0)中断定义为高优先级中断;PX1(0)=0,外部中断1(0)中断定义为低优先级中断。
中断优先级的三个原则:
CPU同时接收到几个中断时,首先响应优先级别最高的中断请求。若是同级别的,在没有设置中断优先级的情况下,按照默认中断级别响应中断;在设置中断优先级后,则按设置顺序确定响应的先后顺序。
正在进行的中断过程不能被新的同级或低优先级的中断请求所中断。
正在进行的低优先级中断服务,能被高优先级中断请求所中断。
52单片机的中断级别:
在这里插入图片描述
3、SCON的中断标志
在这里插入图片描述
RI(SCON.0):串行口接收中断标志位。当允许串行口接收数据时,每接收完一个串行帧,由硬件置位RI。注意,RI必须由软件清除。
TI(SCON.1):串行口发送中断标志位。当CPU将一个发送数据写入串行口发送缓冲器时,就启动了发送过程。每发送完一个串行帧,由硬件置位TI。CPU响应中断时,不能自动清除TI,TI必须由软件清除。
三、单片机的定时器/计数器中断
定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0(定时器0)、T1(定时器1)的启动和停止(TR0,TR1)及设置溢出标志(TF0,TF1)。
在这里插入图片描述
加1计数器输入的计数脉冲有两个来源,一个是由系统的时钟振荡器输出脉冲经12分频后送来;一个是T0或T1引脚输入的外部脉冲源。每来一个脉冲计数器加1,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使TCON中TF0或TF1置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。
1、工作方式寄存器TMOD
工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。不能进行位寻址,如果设置定时器0为工作方式1的话就是0x01,即0000 0001高四位(定时器1可以理解为没有设置,其实0000是定时器1的方式0)是0,低四位0001是GATE=0,C/T=0选择为定时模式,M1M0=01是16位定时器,其格式如下:
在这里插入图片描述
GATE:门控制位。GATE=0时,只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚也为高电平时,才能启动定时/计数器工作,即此时定时器的启动多了一条件。
C/T:定时/计数模式选择位。C/T=0为定时模式;C/T=1为计数模式。
M1M0:工作方式选择位。定时/计数器有四种工作方式,由M1M0进行设置。
在这里插入图片描述
2、控制寄存器TCON
在这里插入图片描述
TF1(TCON.7):定时器1(T1)溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。
TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。
TF0(TCON.5):定时器0(T0)溢出中断请求标志位,其功能与TF1类同。
TR0(TCON.4):T0运行控制位,其功能与TR1类同。
IE1(TCON.3),外部中断1中断请求标志位。
IT1(TCON.2),外部中断1触发方式控制位。
IE0(TCON.1),外部中断0中断请求标志位。(在IT0下当INT0(外部中断0)为低电平或从高到低的负跳变时,IE0置1)
IT0(TCON.0),外部中断0触发方式控制位。当IT0=0时,为电平触发方式。当IT0=1时,为跳边沿触发方式(下降沿有效)。
3、定时器0方式1逻辑结构
在这里插入图片描述
注意:TR0是定时器的“自身原配开关”。EA,ET0,TR0三者容易搞不清。定时器可以工作在“查询标志位”和“中断”这两种状态,也就是说在没有中断的情况下定时器也可以单独使用的。TR0是定时器0自身的发动引擎,要不要把这个发动引擎所产生的能量传输到中断的渠道,则取决于中断开关EA和ET0。TR0是源头开关,EA是中断总渠道开关,ET0是中断分支渠道的定时器0开关。TR0取1表示启动定时器0,取0表示关闭定时器0。
看到定时器的结构图可知定时器0在GATE=0,TR0=0时,TL0就在机器周期的作用下开始计数,直到TL0和TH0计满溢出,由硬件将TF0置为1,接着向CPU申请中断。只要TR0=1,计数就不会停止。
四、中断函数
1、计算初值
假设时钟频率是12MHz,那么时钟周期是时钟频率的倒数(外接晶振的倒数)就是1/12微秒,则机器周期就是1微秒。在TL0和TH0计满时也就是2^16-1,再加上一个机器周期溢出,TF0置1,触发中断的话就需要2……16个个数,也就是65536微秒。
如果要定时50ms,就是要计50000个数,那么TL0和TH0要装的初值就是65536-50000=15536。则TH0=15536/256,TL0=15536%256。当晶振为11.0592MHz时,机器周期就是12*(1/11.0592)=1.09微秒,定时50ms时装初值就是50000/1.09=45872。在用定时器方式1时,计算TLX和THX要装的初值:THX=(65536-N)/256;TLX=(65536-N)%256。
2、中断服务程序

void main()
{
   配置中断;
   while(1)
   {  
       处理常事;
   }
}

void 中断函数() interrupt 中断号    //中断函数后缀带“interrupt 序号”特别修饰
{
   重装初值;
   中断服务程序内容;
}

可以看出“main函数”与“中断函数”在软件上看不到任何关联,既不存在“main函数”调用“中断函数”,也不存在“中断函数”调用“main函数”的情况,在观感上,“main函数”与“中断函数”仿佛是隔离的毫无“物理连接”的,为什么单片机还能在“main函数”与“中断函数”两者中切换自如?没错,“main函数”与“中断函数”在书写上是隔离的毫无关联的,但是它们之间之所以能相互切换,是因为背后有一只无形的手在自动操控这一切,这只手就是单片机硬件自身,这是一种特殊机制,也可以理解成一种特殊的游戏规则,我们只要遵守就好了,除了普通函数,其它凡是中断函数的,都不用跟main函数发生软件上的关联调用,它们之间的切换都是硬件自动完成的,这就是main函数与中断函数的特殊跳转机制(或者称为游戏规则也可以)
3、定时器初始化步骤
①初始化TMOD寄存器,确定定时器1(T1)和定时器0(T0)的工作方式,如TMOD=0x01,就是设置定时器0为工作方式1;
②计算初值,THX=(65536-50000)/256;TLX=(65536-50000)%256;就是将定时器定时为50ms(12MHz的晶振);
③开放中断,EA=1;ET0=1;开总中断和定时器0中断;
④启动定时器,TR0=1;启动定时器0。
五、实例
1、用定时器0实现第一个二极管间隔0.5S闪烁,在主程序里实现用延时函数让第八个二极管间隔300ms闪烁,两个互不干涉。

#include <reg52.h>
#define uint unsigned int
sbit led1=P1^0;
sbit led8=P1^7;
void delayms(uint xms)
{
	uint i,j;
	for(i=xms;i>0;i--)
		for(j=110;j>0;j--);
}
char num=0;
void main()
{
	TMOD=0x01;//定时器0方式1,16位计数器
	TH0=(65536-45872)/256;//高四位装初值,11.0592MHz
	TL0=(65536-45872)%256;//低四位装初值
	EA=1;
	ET0=1;
	TR0=1;
	while(1)
	{
		led8=~led8;//每次取反
		delayms(300);
	}
}
void Timer0() interrupt 1//注意:我刚开始时把函数名写为T0,会出现重定义错误,因为在头文件中定义了
{
	TH0=(65536-45872)/256;//一定要记住重装初值
	TL0=(65536-45872)%256;
	num++;//每次进入中断就累加一次,到10次置0
	if(num==10)//num到10时也就是500ms,二极管进行闪烁
	{
		num=0;
		led1=~led1;
	}

}

**注意:**一般情况下在中断服务程序中不要写太多语句,如果中断服务程序中写太多语句的话就可能会出现中断服务程序中的代码还没有执行完,而下一次中断又来临了,那么就丢失剩下的代码又重头开始执行,累计出现这种情况程序就有可能乱套。一般原则是能不在中断里面写就不在里面写。但是上面的程序就只能在中断里面写,因为我刚开始在主函数中写,放在delayms(300)语句后,会出现第一个二极管过了很长时间才亮时间(可能是127*50ms)很长时间才熄灭。原因就是主函数延时大概300ms,而num累积十次是500ms,在500ms时主函数刚好应该在第二次delayms函数600ms中,再进行一次中断50ms仍然在delayms函数中,但是num就累加到11了,当delayms函数执行完之后刚好就错过if语句的判断,而当num一直累加到127之后(char型变量)才回到0,在某一时刻刚好可以在主函数中判断到num=10,所以会出现这种情况。在有些程序中就有可能永远检测不到了。
2、在实验板上实现:用定时器0的方式1实现前两位数码管59s的循环计时,用定时器1的方式1实现前四个二极管和后四个二极管间隔亮300ms。

#include <reg52.h>
sbit dula=P2^6;
sbit wela=P2^7;
void delayms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=110;j>0;j--);
}

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
unsigned char num1=0,num=0,num2=0;
void main()
{
	TMOD=0x11;//设置定时器1和定时器0为方式一
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;//装初值,50ms
	TH1=(65536-45872)/256;
	TL1=(65536-45872)%256;
	EA=1;
	ET1=1;
	ET0=1;
	TR1=1;
	TR0=1;
	P1=0xf0;
	dula=0;
	wela=0;
	while(1)
	{
		dula=1;
		P0=table[num/10];//显示首位数码管数字,取整,可以理解为几个10
		dula=0;
		P0=0xff;
		wela=1;
		P0=0xfe;//打开第一个数码管
		wela=0;
		delayms(1);//延时最好要,如果不加会看到亮度比较暗,应该是点亮的速度比较快导致,时间长亮度会更亮一点
		wela=1;//最好一定要加上位选,不然会看到数字以外的部分有微弱亮度,
		P0=0xff;//原因在于如果不加,下面刚打开段选显示的数字就会先送到第一个数码管
		wela=0;//由于速度很快,又到第二个数码管了,时间短所以就出现数字以外的部分有微弱亮度

		dula=1;
		P0=table[num%10];//显示第二位数码管,取余
		dula=0;
		P0=0xff;
		wela=1;
		P0=0xfd;//打开第二个数码管
		wela=0;
		delayms(1);
		wela=1;
		P0=0xff;
		wela=0;
	}
}
void timer0() interrupt 1
{
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	num1++;
	if(num1==20)//1s
	{
		num1=0;
		num++;
		if(num==60)//计时1分钟,然后清零
			num=0;
	}
}
void timer1() interrupt 3//用序号3,单片机认识中断的唯一标识
{
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	num2++;
	if(num2==15)//300ms
	{
		num2=0;
		P1=~P1;
	}
}

在这里插入图片描述

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值