中断与定时计数的应用

一、中断系统

(一)中断系统结构

在下图所示的AT89C51的中断系统结构中,存在着5个中断请求源(包括:外部中断0请求定时器/计数器0中断请求外部中断1请求定时器/计数器1中断请求串行口中断请求)。此外,系统支持2个不同的中断优先级,并且可以实现嵌套的2级中断服务程序。每个中断源的中断状态可以由软件单独控制,可以选择允许或关闭中断。另外,每个中断源的优先级可以通过软件进行设置。

5个中断请求源的介绍:

(1)\overline{INTO}:外部中断请求0,外部中断请求信号(低电平或负跳变有效)由\overline{INTO}引脚输入,中断请求标志为IE0。

(2) T0:定时器/计数器T0计数溢出的中断请求,标志为TF0。

(3) \overline{INT1}:外部中断请求1,外部中断请求信号(低电平或负跳变有效)由\overline{INT1}引脚输入,中断请求标志为IE1。

(4) T1:定时器/计数器T1计数溢出的中断请求,标志为TF1。

(5) TX/RX:串行口中断请求,标志为发送中断TI或接收中断RI。

(二)中断寄存器

1、中断请求标志寄存器

(1)TCON寄存器

TCON位于地址88H,可通过位寻址进行访问。该寄存器用于控制定时器/计数器T0和T1的运行状态,并监测它们的溢出情况(TF0和TF1)。此外,该寄存器还管理两个外部中断请求的标志位(IE1和IE0),以及配置外部中断请求触发方式的控制位。TCON的格式如下图所示:

TCON寄存器中各标志位功能:

(1)TF1—定时器/计数器T1的溢出中断请求标志位。

当启动T1计数后,T1从初值开始加1计数,当最高位产生溢出时,硬件 置TF1为“1”,向CPU申请中断,响应TF1中断时,TF1标志硬件自动清“0”,TF1也可由软件清“0”。

(2)TF0—定时器/计数器T0溢出中断请求标志位,与TF1类似。

(3)IE1—外部中断请求1中断请求标志位。

(4)IE0—外部中断请求0中断请求标志位,与IE1类似。

(5)IT1—选择外中断请求1为跳沿触发还是电平触发方式。

0--电平触发方式,加到\overline{INTO}脚上的外中断请求输入信号为低电平有效,并把IE1置“1”。转向中断服务程序时,则由硬件自动把IE1清“0”。

1--跳沿触发方式,加到\overline{INT1}脚上的外中断请求输入信号从高到低的负跳变有效,并把IE1置“1”。转向中断服务程序时,则由硬件自动把IE1清“0”。

(6)IT0—选择外中断请求0为跳沿触发方式还是电平触发方式,与IT1类似。

(2)SCON寄存器

SCON寄存器是AT89C51单片机中的串行控制寄存器,具有8位的结构,用于配置和控制串行通信操作。SCON的格式如下图所示:

SCON寄存器标志位功能:

(1)RI:串行口接收中断请求标志位。在串口接收完一个串行数据帧,硬件自动使RI中断请求标志置“1”。CPU在响应串口接收中断时,RI标志并不清“0”,须在中断服务程序中用指令对RI清“0”。

(2)TI:串口发送中断请求标志位。CPU将1字节的数据写入串口的发送缓冲器SBUF时,就启动一帧串行数据的发送,每发送完一帧串行数据后,硬件使TI自动置“1”。CPU响应串口发送中断时,并不清除TI中断请求标志,TI标志必须在中断服务程序中用指令对其清“0”

2、中断允许寄存器IE

IE是一个位结构寄存器,用于控制和配置8051系列单片机中断的功能。这个寄存器允许开发人员启用或禁用不同类型的中断。IE寄存器的格式如下图所示:

IE对中断开放和关闭实现两级控制。两级控制就是有一个总的中断开关控制位EA(IE.7位),当EA=0,所有中断请求被屏蔽,CPU对任何中断请求都不接受;当EA=1时,CPU开中断,但5个中断源的中断请求是否允许,还要由IE中的低5位所对应的5个中断请求允许控制位的状态来决定。

IE中各位的功能:

(1)EA—中断允许总开关控制位。     

         EA=0,所有的中断请求被屏蔽。

         EA=1,所有的中断请求被开放。

(2)ES—串行口中断允许位。

         ES=0,禁止串行口中断。

         ES=1,允许串行口中断。

(3)ET1/ET0—定时器/计数器T1/T0溢出中断允许位。

         ET1/ET0=0,禁止T1/T0溢出中断。

         ET1/ET0=1,允许T1/T0溢出中断。

(4)EX1/EX0—外部中断1/0中断允许位。  

         EX1/EX0=0,禁止外部中断1/0中断。   

         EX1/EX0=1,允许外部中断1/0中断。

3、中断优先级寄存器IP

IP寄存器是一个8位寄存器,用于配置和控制中断的优先级。每个位对应于一个特定的中断,通过设置或清除这些位,可以指定每个中断的优先级。优先级高的中断将优先被处理。IP寄存器的格式如下图所示:

优先级寄存器IP各位含义:

(1)PS—串行口中断优先级控制位,1—高级;0—低级。

(2)PT1—T1中断优先级控制位,1—高级;0—低级。

(3)PX1—外部中断1中断优先级控制位,1—高级;0—低级。

(4)PT0—T0中断优先级控制位,1—高级;0—低级。    

(5)PX0—外部中断0中断优先级控制位,1—高级;0—低级。

同级中断的查询次序:

通过C语言代码可以知道,中断号介绍中断查询次序号。代码如下所示:

并且各个中断源的中断优先级关系都遵勖以下规则:

(1)低优先级可被高优先级中断,高优先级不能被低优先级中断。

(2)任何一种中断(不管是高级还是低级)一旦得到响应,不会再被它的同级中断源所中断。如果某一中断源被设置为高优先级中断,在执行该中断源的中断服务程序时,则不能被任何其他的中断源的中断请求所中断。

二级中断嵌套:

 中断请求源有两个中断优先级,每一个中断请求源可由软件设置为高优先级中断或低优先级中断,也可实现两级中断嵌套。

所谓两级中断嵌套,就是AT89S51正在执行低优先级中断的服务程序时,可被高优先级中断请求所中断,待高优先级中断处理完毕后,再返回低优先级中断服务程序。过程如下图所示:

(三)外部中断的运用

1、单一外中断

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

Keil代码实现:

#include <REGX51.H>

void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}


void main()
{
	EA = 1;
	EX0 = 1;
	IT0 = 1;
	while(1)
	{
		P1 = 0  ;
	}
}
void Int0_Routine() interrupt 0 using 0
{
	unsigned char n;
	EX0 = 0;
	for(n=0;n<5;n++)
	{
		P1 = 0x0F;
		Delay1ms(500);
		P1 = 0xF0;
		Delay1ms(500);
		EX0 = 1;
	}
}

Proteus电路图:

Proteus效果图:

开发板效果图:

将上述代码P1修改为P2来点亮开发板上的led,并按下独立按钮K3便开始闪烁如下图所示:

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

Keil代码实现:

#include <REGX52.H>

void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

void main()
{
	EA=1;		//总中断打开
	EX0=1;
	EX1=1;	//	允许中断0、1中断
	IT0=1;
	IT1=1;	//中断0、1设置下降沿中断
	IP=0;		//中断优先级控制寄存器低(可位寻址)
	
	while(1)
	{
		P2=0xFE;//1111 1110
		Delay1ms(500);
		P2=0xFD;//1111 1101
		Delay1ms(500);
		P2=0xFB;//1111 1011
		Delay1ms(500);
		P2=0xF7;//1111 0111
		Delay1ms(500);
		P2=0xEF;//1110 1111
		Delay1ms(500);
		P2=0xDF;//1101 1111
		Delay1ms(500);
		P2=0xBF;//1011 1111
		Delay1ms(500);
		P2=0x7F;//0111 1111
		Delay1ms(500);		
	}
}

	
void Int0_Routine() interrupt 0//外部中断0
{
	unsigned char i;
	for(i=0;i<10;i++)
	{
		P2=0xf0;
		Delay1ms(300);
		P2=0x0f;
		Delay1ms(300);
	}
}

void Int1_Routine() interrupt 2//外部中断1
{	
			unsigned char i;
			for(i=0;i<10;i++)
			{
				P2=0xff;
				Delay1ms(300);
				P2=0x00;
				Delay1ms(300);
			}
}

Proteus电路图:

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为高优先级。

Keil代码实现:

#include <REGX52.H>

void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}

void main()
{
	EA=1;		//总中断打开
	EX0=1;
	EX1=1;	//	允许中断0、1中断
	IT0=1;
	IT1=1;	//中断0、1设置下降沿中断
	//只设置IP优先级只有两级,设置IPH可将优先级设为四级
	PX0=0;	//IP可位寻址
	PX1=1;	//中断1优先于中断0
	while(1)
	{
		P2=0xFE;//1111 1110
		Delay1ms(500);
		P2=0xFD;//1111 1101
		Delay1ms(500);
		P2=0xFB;//1111 1011
		Delay1ms(500);
		P2=0xF7;//1111 0111
		Delay1ms(500);
		P2=0xEF;//1110 1111
		Delay1ms(500);
		P2=0xDF;//1101 1111
		Delay1ms(500);
		P2=0xBF;//1011 1111
		Delay1ms(500);
		P2=0x7F;//0111 1111
		Delay1ms(500);		
	}
}

	
void Int0_Routine() interrupt 0//外部中断0
{
	unsigned char i;
	for(i=0;i<10;i++)
	{
		P2=0xF0;
		Delay1ms(300);
		P2=0x0F;
		Delay1ms(300);
	}
}

void Int1_Routine() interrupt 2//外部中断1
{	
			unsigned char i;
			for(i=0;i<10;i++)
			{
				P2=0xFF;
				Delay1ms(300);
				P2=0;
				Delay1ms(300);
			}
}

Proteus效果图:

二、定时器和计数器的工作原理

(一)定时器和计数器的介绍

AT89S51定时器/计数器结构如下图所示,定时器/计数器T0由特殊功能寄存器TH0、TL0构成,T1由特殊功能寄存器TH1、TL1构成。

  • T0、T1都有定时器和计数器两种工作模式,两种模式实质都是对脉冲信号进行计数,只不过计数信号来源不同。
  • 计数器模式是对加在T0(P3.4)和T1(P3.5)两个引脚上的外部脉冲进行计数
  • 定时器模式是对系统时钟信号经12分频后的内部脉冲信号(机器周期)计数。由于系统时钟频率是定值,可根据计数值计算出定时时间。两个定时器/计数器属于增1计数器,即每计一个脉冲,计数器增1。

(二)定时器和计数器寄存器

1、工作方式控制寄存器TMOD

TMOD寄存器是一个8位寄存器,用于配置定时/计数器的工作模式。它允许开发人员选择定时器0和定时器1的工作模式,包括定时器模式、定时器/计数器模式、以及自动重装载模式。TMOD格式如下图所示:

定时器1/2的前两位符号及其功能介绍:

符号功能
TMOD.7/GATETMOD. 7控制定时器1,置1时只有在INT1*脚为高及TR1控制位置1时才可打开定时器/计数器1。
TMOD.3/GATETMOD.3控制定时器0,置1时只有在INTO*脚为高及TRO控制位置1时才可打开定时器/计数器0。
TMOD.6/C/TTMOD.6控制定时器1用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),置1用作计数器(从T1/P3. 5脚输入)
TMOD.2/C/TTMOD.2控制定时器0用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),置1用作计数器(从T0/P3.4脚输入)

定时器1/2后两位符号及其功能介绍:

(1)TMOD.5/TMOD.4 M1、M0:定时器/计数器1模式选择

符号功能
M1M2/
0013位定时器/计数器,兼容8048定时模式,TL1只 用低5位参与分频,THI 整个8位全用。
0116位定时器/计数器,TL1、 TH1全用。
108位自动重装载定时器,当溢出时将TH1存放的值自动重装入TL1。
11定时器/计数器1此时无效(停止计数)。

(2)TMOD.1/TMOD.0 M1、M0:定时器/计数器0模式选择

符号功能
M1M0/
0013位定时器/计数器,兼容8048定时 模式,TL0只用低5位参与分频,THO整个8位全用。
0116位定时器/计数器,TL0、TH0全用
108位自动重装载定时器,当溢出时将TH0存放的值自动重装入TL0
11定时器0此时作为双8位定时器/计数器。TL0作为一个8位定时器/计数器,通过标准定时器0的控制位控制。TH0仅作为一个8位定时器,由定时器1的控制位控制。

2、定时器/计数器控制寄存器TCON

TCON寄存器是一个8位寄存器,用于控制定时器0和定时器1的运行和状态。它包含了定时器/计数器的控制位,以及用于中断请求的外部中断标志位。TCON格式如下图所示:

  • TF1:T1溢出标志。T1被允许计数以后,从初值开始加1计数。当最高位产生溢时由硬件置“1”TF1,向CPU请求中断,一直保持到CPU响应中断时,才由硬件清 “0”TF1 (TF1 也可由程序查询清“0”)。
  • TR1:定时器T1的运行控制位。该位由软件置位和清零。当GATE (TMOD.7) =0,TR1=1时就 允许T1开始计数,TR1=0时禁止T1计数。当GATE (TMOD.7) =1, TR1=1且INTI*输入高电平时,才允许T1计数。
  • TF0:T0溢出中断标志。T0被允许计数以后,从初值开始加1计数,当最高位产生溢出时,由硬件置“1”TF0,向CPU请求中断,一直保持CPU响应 该中断时,才由硬 件清“0”TF0 ( TF0也可 由程序查询清“0”)。
  • TR0:同上方的TR1类似是定时器T0的运行控制位。该位由软件置位和清零。当GATE (TMOD.3) =0,TR0= 1时就 允许T0开始计数,TR0=0时禁止T0计数。当GATE (TMOD.3) =1, TR1=0且INTO*输入高电平时,才允许T0计数。
  • IE1: 外部中断1请求源(INT1*/P3.3)标志。IE1=1,外部中断向CPU请求中断,当CPU响应该中断时由硬件清“0” IE1。
  • IE0:外部中断0请求源(INT0/P3.2)标志。IE0=1外 部中断0向CPU请求中断,当CPU响应外中断时由硬件清“0”IE0 。
  • IT1:外部中断1中断源类型选择位。IT1=0,INT1*/P3.3引脚上的低电平信号可触发外部中断1。IT1=1, 外部中断1为下降沿触发方式。
  • IT0:外部中断0中断源类型选择位。IT0=0,INT0*/P3.2引脚上的低电平信号可触发外部中断0。IT0=1, 外部中断0为下降沿触发方式。、

(三)定时器和计数器的应用

(1)定时器T0中断

题目要求:在Prodeus和普中单片机板上分别完成采用定时计数器控制LED灯每隔1S周期性亮灭的实验。要求KEIL仿真中的虚拟逻辑仪对LED管脚进行波形观察,测量真实的周期数,并与软件循环进行周期定时的精度进行对比,看哪一种方式更加精准

定时器初值计算:

设定时时间5ms(即5 000µs),设T0计数初值为X,假设晶振的频率为11.059 2MHz,则定时时间为:

定时时间=(216−X)×12/晶振频率     则  5 000=(216 −X) ×12/11.059 2    

得X = 60 928    

转换成十六进制:0xee00,其中0xee装入TH0,0x00装入TL0。

同理得到的计算公式为: 定时时间=(216−X)×12/晶振频率

因此带入延时1ms的数值,假设晶振频率为11.0592MHz得到定时X = 64614,十六进制为0xFC66,将0xFC放入TH0,0x66放入TL0即可

Keil代码:

#include <REGX52.H>

void Timer0_Init()
{
	//设置定时器工作模式TMOD为方式1
	TMOD&=0xF0;//高四位不变,低四位清零
	TMOD|=0x01;//最低位置1,其余位不变 //TOMD=0x01
	           //定时时间=(2^16-X)*12/晶振频率
	TL0=0x66;
	TH0=0xFC;//定时1ms
	//设置定时器控制寄存器TCON
	TF0=0; //中断溢出标志位先清0,避免刚配置好就中断
	TR0=1; //定时器开始工作
	//中断
	EA=1;//允许总中断
	ET0=1;//T0的中断溢出允许位,T0=1,允许中断
}

void main()
{
	Timer0_Init();
	while(1)
	{}
}

void Timer0_Runtine() interrupt 1
{
	unsigned int a;//计数
	TL0=0x66;
	TH0=0xFC;
	Count++;
	if(a>=1000)//计数累加到1000,定时器定时1000ms=1s
	{
		P2_0=~P2_0;//LED状态取反
		a=0;
	}
}

Proteus电路图:

Proteus效果图:

(2)计数器T0中断

题目要求:采用计数器中断,实现按4次按键开关后,P2口的8只LED闪烁不停。

计数器初值计算:

由于每按1次按钮开关,计数1次,按4次后,P1口的8只LED闪烁不停。因此计数器初值为65 536−4=65 532,将其转换成十六进制后为0xfffc,所以,TH0=0xff,TL0=0xfc。

Keil代码:

#include <REGX51.H>

void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}


void Count0_Init()	//计数器
{
	//设置计数器0工作模式1
	TMOD&=0xf0;
	TMOD|=0x05;// C/T置1为计数器模式
	TL0=0xfc;
	TH0=0xff;//计数4次,65536-4=65532
	//设置计数器控制寄存器TCON
	TF0=0;
	TR0=1;
	//中断
	EA=1;
	ET0=1;
}

void main()
{
	Count0_Init();
	while(1)
	{
		
	}
}

void Count0_Routine() interrupt 1
{
	while(1)
	{
		P2=~P2;
		Delay1ms(500);
		P2=~P2;
		Delay1ms(500);
	}

}

Proteus电路图:

Proteus效果图:

三、中断优化  

题目要求: 一般来说,中断函数中要尽量避免使用执行时间较长(耗时)的代码,以避免中断服务影响到主程序代码的执行效率。但是在上面外部中断的实验中,中断函数采用了软件延时函数去控制LED亮灭的间隔周期。这是一种不好的编程。请你思考,换一种更合理的方式,不在中断函数使用延时循环,实现同样的功能。

Keil代码:

#include <REGX52.H>

void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		xms--;
	}
}


void Init0()
{
	EA=1;
	EX0=1;
	IT0=1;//下降沿触发
}

unsigned char Key_Interrupt_Flag=0;//中断模式标志位.不进行中断则中断标志为0,下方的循环不进行

void Init0_Routine() interrupt 0//每次进行中断中断标志都置1
{
	Key_Interrupt_Flag=1;
}
	
void main()
{
	unsigned char Mode=0;
	Init0();
	while(1)
	{
		if(Key_Interrupt_Flag)//非零则进行循环
		{
			Key_Interrupt_Flag=0;//标志位置0
			Mode++;//切换亮灯模式 
			if(Mode>=3)
			{
				Mode=0;//循环切换
			}
		}
		
		switch (Mode)//亮灯模式选择
		{
			case 0:
				{
				P2=0xfe;
				}
				break;
			case 1:
				{
				P2=0xf0;
				Delay1ms(300);
				P2=0X0F;
				Delay1ms(300);
				}
				break;
			case 2:
				{P2=0XAA;
				Delay1ms(300);
				P2=0x55;
				Delay1ms(300);
				}
				break;
			default:
				break;
		}	
	}
}

Proteus电路图:

Proteus效果图:

开发板效果:

四、总结

学习AT89C51单片机定时器、计数器和中断系统后,能够熟练配置和控制各种定时器模式、中断优先级,并理解定时器/计数器的原理及中断处理流程,为实现精准的定时、计数和中断响应提供了重要基础。

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值