单片机(二):外部中断、定时计数器

通过上一篇的了解,应该对单片机:
内部的结构、组成、寄存器、内存空间、外部引脚I/O功能、数字电路基础知识等有所了解了。
接下来说说单片机P3口的第二功能:外部中断、定时器中断、计数器中断

中断相关的寄存器

如图所示:
按中断优先级排列
/INT0(外部中断0的引脚)
T0(定时计数器0的引脚)
/INT1(外部中断0的引脚)
T1(定时计数器0的引脚)

1、TCON(定时/计数器控制寄存器)
在这里插入图片描述

  • TF1:定时器T1溢出标志,可由程序查询和清零,TF1也是中断请求源,当CPU响应T1中断时由硬件清零。
  • TF0:定时器T0溢出标志,可由程序查询和清零,TF0也是中断请求源,当CPU响应T0中断时由硬件清零。
  • TR1:T1充许计数控制位,为1时充许T1计数。
  • TR0:T0充许计数控制位,为1时充许T0计数。
  • IE1:外部中断1请示源(INT1,P3.3)标志。IE1=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE1(边沿触发方式)。
  • IT1:外部中断源1触发方式控制位。IT1=0,外部中断1程控为电平触发方式,当INT1(P3.3)输入低电平时,置位IE1。
  • IE0:外部中断0请示源(INT0,P3.2)标志。IE0=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE0(边沿触发方式)。
  • IT0:外部中断源0触发方式控制位。IT0=0,外部中断1程控为电平触发方式,当INT0(P3.2)输入低电平时,置位IE0。

2、IE(中断允许寄存器)

在这里插入图片描述

  • EA:中断总控制位,EA=1,CPU开放中断。EA=0,CPU禁止所有中断。
  • ES:串行口中断控制位,ES=1允许串行口中断,ES=0,屏蔽串行口中断。
  • ET1:定时/计数器T1中断控制位。ET1=1,允许T1中断,ET1=0,禁止T1中断。
  • EX1:外中断1中断控制位,EX1=1,允许外中断1中断,EX1=0,禁止外中断1中断。
  • ET0:定时/计数器T0中断控制位。ET1=1,允许T0中断,ET1=0,禁止T0中断。
  • EX0:外中断0中断控制位,EX1=1,允许外中断0中断,EX1=0,禁止外中断0中断。

3、IP(中断优先级控制寄存器)
在这里插入图片描述

  • PS:串行口中断口优先级控制位,PS=1,串行口中断声明为高优先级中断,PS=0,串行口定义为低优先级中断。
  • PT1:定时器1优先级控制位。PT1=1,声明定时器1为高优先级中断,PT1=0定义定时器1为低优先级中断。
  • PX1:外中断1优先级控制位。PT1=1,声明外中断1为高优先级中断,PX1=0定义外中断1为低优先级中断。
  • PT0:定时器0优先级控制位。PT1=1,声明定时器0为高优先级中断,PT1=0定义定时器0为低优先级中断。
  • PX0:外中断0优先级控制位。PT1=1,声明外中断0为高优先级中断,PX1=0定义外中断0为低优先级中断。

4、SCON(串行通信控制寄存器)
在这里插入图片描述

  • SM0、SM1:串行口工作方式控制位。
    SM0,SM1 工作方式
    00 方式0-波特率由振荡器频率所定:振荡器频率/12
    01 方式1-波特率由定时器T1或T2的溢出率和SMOD所定:2SMOD ×(T1溢出率)/32
    10 方式2-波特率由振荡器频率和SMOD所定:2SMOD ×振荡器频率/64
    11 方式3-波特率由定时器T1或T2的溢出率和SMOD所定:2SMOD ×(T1溢出率)/32
  • SM2:多机通信控制位。
    《 br》 多机通信是工作于方式2和方式3,SM2位主要用于方式2和方式3。接收状态,当串行口工作于方式2或3,以及SM2=1时,只有当接收到第9位数据(RB8)为1时,才把接收到的前8位数据送入SBUF,且置位RI发出中断申请,否则会将接受到的数据放弃。当SM2=0时,就不管第位数据是0还是1,都难得数据送入SBUF,并发出中断申请。
    工作于方式0时,SM2必须为0。
  • REN:允许接收位。
    《 br》 REN用于控制数据接收的允许和禁止,REN=1时,允许接收,REN=0时,禁止接收。
  • TB8:发送接收数据位8。
    《 br》 在方式2和方式3中,TB8是要发送的——即第9位数据位。在多机通信中同样亦要传输这一位,并且它代表传输的地址还是数据,TB8=0为数据,TB8=1时为地址。
  • RB8:接收数据位8。
    在方式2和方式3中,RB8存放接收到的第9位数据,用以识别接收到的数据特征。
  • TI:发送中断标志位。
    可寻址标志位。方式0时,发送完第8位数据后,由硬件置位,其它方式下,在发送或停止位之前由硬件置位,因此,TI=1表示帧发送结束,TI可由软件清“0”。
  • RI:接收中断标志位。
    可寻址标志位。接收完第8位数据后,该位由硬件置位,在其他工作方式下,该位由硬件置位,RI=1表示帧接收完成。

在这里插入图片描述
在这里插入图片描述

和中断有关的寄存器一共有
TMOD

在这里插入图片描述

  • M1M0:定时/计数器一共有四种工作方式,就是用M1M0来控制的,2位正好是四种组合。
  • C/T:选择定时器、计数器
  • GATE:门控位

工作方式:

  • 1、定时器/计数器的工作方式0称之为13位定时/计数方式。它由TL(1/0)的低5位和TH(0/1)的8位组成13位的计数器,此时TL(1/0)的高3位未用。
  • 2、工作方式1是16位的定时/计数方式,将M1M0设为01即可,其它特性与工作方式0相同。
  • 3、8位的定时/计数方式,自动再装入预置数的工作方式。在工作方式2,只有低8位参与计数,而高8位不参与计数,用作预置数的存放,每当计数溢出,就会打开T(0/1)的高、低8位之间的开关,计预置数进入低8位。这是由硬件自动完成的,不需要由人工干预。
  • 4、定时/计数器0被拆成2个独立的定时/计数器来用。其中,TL0能组成8位的定时器或计数器的工作方式,而TH0则只能作为定时器来用。

一般情况处,只有在T1以工作方式2运行(当波特率发生器用)时,才让T0工作于方式3的。

TCON

在这里插入图片描述
TCON被分成两部份,高4位用于定时/计数器,低4位则用于中断。
TF0:当计数溢出后,TF0就由0变为1
TR0:运行控制位,可用指令SETB来置位以启动计数器/定时器运行,用指令CLR来关闭定时/计数器的工作

  • 1、中断源:8031中一共有5个,两个外部中断,两个计数/定时器中断,一个串行口中断。
  • 2、中断的嵌套与优先级处理
  • 3、中断响应过程:
    1、保护断点,即保存下一将要执行的指令的地址,就是把这个地址送入堆栈。
    2、寻找中断入口,根据5个不一样的中断源所产生的中断,查找5个不一样的入口地址。以上工作是由计算机自动完成的,与编程者无关。在这5个入口地址处存放有中断处理程序(这是程序编写时放在那儿的,如果没把中断程序放在那儿,就错了,中断程序就不能被执行到)。
    3、执行中断处理程序。
    4、中断返回:执行完中断指令后,就从中断处返回到主程序,继续执行。

中断处理

当外部引脚被触发后,CPU接收到中断发生,暂停并保存当前的工作转去执行中断。
当发生中断,CPU接收到中断请求和中断处理程序的入口地址,转去执行中断处理程序,
执行完后,接着执行上次暂停的任务代码

在这里插入图片描述

1、中断响应的主要内容就是由硬件自动生成一条长调用LCALL addr16指令,这里的addr16就是程序存储器中相应的中断区入口地址,生成LCALL指令后,CPU紧跟着便进入入口地址。
2、首先将PC的内容压入堆栈保护断点,然后把中断入口地址赋予PC,CPU便按照新的PC地址执行程序
3、各个中断区只有8个单元,一般情况下都不可能安装下一个完整的中断服务程序,因此通常是在这些入口地址区放置一条无条件跳转指令(LCALL addr16),使程序按转移的实际地址去执行真正的中断服务程序。

中断处理程序
在这里插入图片描述
1、配置相应的中断寄存器
2、编写中断处理程序
3、安装中断到中断地址
4、编写程序使用中断

代码


//NE555脉冲发生器代码,(T0定时,T1计数,配置两个中断,计算并显示脉冲的频率)

#include <reg51.h>

typedef unsigned char u8;
typedef unsigned int  u16;

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0~F

u8 Digduan[8];			//频率的各个位的值
#define GPIO_DIG P0
sbit A38 = P2^0;
sbit B38 = P2^1;
sbit C38 = P2^2;

unsigned long TimeNum;
unsigned long Number;
					
void delay(u16 i)		//延时功能
{
	while(i--);
}

void DigDisplay()		//数码管显示功能
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)
		{
			case 0:A38=0;B38=0;C38=0;break;
			case 1:A38=1;B38=0;C38=0;break;
			case 2:A38=0;B38=1;C38=0;break;
			case 3:A38=1;B38=1;C38=0;break;
			case 4:A38=0;B38=0;C38=1;break;
			case 5:A38=1;B38=0;C38=1;break;
			case 6:A38=0;B38=1;C38=1;break;
			case 7:A38=1;B38=1;C38=1;break;
		}
		GPIO_DIG=Digduan[i];
		delay(10);
		GPIO_DIG=0x00;
	}
}

void Init()		//初始化定时器计数器
{
	//设置T0为定时器,T1为计数器TMOD = 0101 0001
	TMOD = 0x51;
	
	//设置定时器的初值(晶振12mhz,定时50ms)
	TH0=0x3C;
	TL0=0xB0;
	
	
	//打开中断允许
	EA = 1;
	ET0= 1;
	ET1= 1;
	
	//开启定时器和计数器
	TR0 = 1;
	TR1 = 1;
}

//定时器定时1s
//计数器累加1s内的计数值
//把计数值通过数码管进行显示
void main()
{
	Init();
	while(1)
	{
		if(TR1==0)	//定时器时间到,计数器停止,统计1ms内的脉冲频率
		{
			Number = Number + TL1;
			Number = Number + TH1*256;
			
			Digduan[0] = smgduan[Number%1000000/100000];	
			Digduan[1] = smgduan[Number%100000/10000];	
			Digduan[2] = smgduan[Number%10000/1000];	
			Digduan[3] = smgduan[Number%1000/100];	
			Digduan[4] = smgduan[Number%100/10];	
			Digduan[5] = smgduan[Number%10];
			
			//显示完,重新进行下一次
			Number = 0;
			
			TH1 = 0;
			TL1 = 0;
			
			TR0 = 1;
			TR1 = 1;
			
		}
		DigDisplay();
	}
}



void Timer0() interrupt 1  //定时器中断处理
{
	TH0=0x3C;
	TL0=0xB0;
	
	TimeNum++;
	if(TimeNum==20)
	{
		TR0 = 0;
		TR1 = 0;
		TimeNum = 0;
	}
	
}

void Timer1() interrupt 3  //计数器中断处理
{
	Number = Number + 65536;
}











猜你喜欢

转载自blog.csdn.net/qq_42856154/article/details/90667566