51单片机学习笔记之中断(外部中断、定时器中断、中断嵌套)

文章目录[隐藏]

(一)寄存器

要想学习中断那么首先就要了解寄存器,在这里我们学习一下什么是寄存器,寄存器怎么用。

1.什么是寄存器

寄存器是特殊的RAM,特殊功能寄存器是控制单片机硬件的开关(例如IE)或者是指示单片机状态的信号(例如PSW),通过特殊寄存器你就可以方便的控制整个MCU,并且知道当前的MCU的工作状态。

2.寄存器怎么用

AT89S51单片机中的特殊功能寄存器(SFR)的单元地址映射在片内RAM区的80H~FFH区域中,它共有26个,离散地分布在该区域中。用到哪个寄存器就相应配置哪个寄存器即可。寄存器太多就不一一写出来了,用到再去找就好。

(二)中断

单片机的中断是由单片机片内的中断系统来实现的。当中断请求源(简称中断源)发出中断请求时,如果中断请求被允许的话,单片机暂时中止当前正在执行的主程序,转到中断服务程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。

1.中断允许寄存器IE

在这里插入图片描述

EX0

外部中断0允许位。EX0=1,允许外部中断0中断;EX0=0,禁止外部中断0中断。当EX0=1( SETB EX0 )时,同时单片机P3.2引脚上出现中断信号时,单片机中断主程序的执行而“飞”往中断服务子程序,执行完后通过中断返回指令RET 动返回主程序。当EX0=0( CLR EX0)时,即使单片机P3.2引脚上出现中断信程序也不会从主程序“飞” 出去执行,因为此时单片机的CPU相当于被“堵上了耳朵”,根本接收不到P3.2引脚上的中断信号,但是这并不表示这个信号不存在。如果单片机的CPU有空查一下TCON中的IE0位,若为1就说明有中断信号出现过。

ET0

T0溢出中断允许位。ET0=1,允许T0中断;ET0=0,禁止T0中断。

EX1

外部中断1允许位。EX1=1,允许外部中断1中断;EX1=0,禁止外部中断1中断。当EX1=1( SETB EX1)时,并且外部P3.3引脚上出现中断信号时,单片机CPU会中断主程序而去执行相应的中断服务子程序;当EX1=0( CLR EX1)时使外部P3.3引脚上即使出现中断信号,单片机的CPU也不能中断主程序转而去行中断服务子程序。
因此,可以这样认为,EX0和EX1是决定CPU能否感觉到外部引脚P3.2P3.3上的中断信号的控制位。

ET1

T1溢出中断允许位。ET1=1,允许T1中断;ET1=0,禁止T1中断。

ES

串行中断允许位。ES=1,允许串行口中断;ES=0,禁止串行口中断。

EA

中断总允许位。EA=1,CPU开放中断;EA=0,CPU禁止所有的中断请求。总允许EA好比一个总开关。EA就相当于每家水管的总闸,如果总闸不开,各个龙头即使开了也不会有水;反过来,如果总闸开了而各个分闸没开也不会有水,所当我们想让P3.2和P3.3引脚上的信号能够中断主程序则必须将EA位设置为0(CLR EA)。

使用方法

(1)整体赋值:IE=0x81;(开启全局中断,打开外部中断0 )。
(2)单独赋值:EA=1;EX0=1;(开启全局中断,打开外部中断0 )。

2.中断优先级寄存器IP

在这里插入图片描述

PS——串行口中断优先级控制位

PS=1,串行口中断定义为高优先级中断。
PS=0,串行口中断定义为低优先级中断。

PT1——定时器/计数器1中断优先级控制位

PT1=1,定时器/计数器1中断定义为高优先级中断。
PT1=0,定时器/计数器1中断定义为低优先级中断。

PX1——外部中断1中断优先级控制位

PX1=1,外部中断1定义为高优先级中断。
PX1=0,外部中断1定义为低优先级中断。

PT0——定时器/计数器0中断优先级控制位

PT0=1,定时器/计数器0中断定义为高优先级中断。
PT0=0,定时器/计数器0中断定义为低优先级中断。

PX0——外部中断0中断优先级控制位

PX0=1,外部中断0定义为高优先级中断。
PX0=0,外部中断0定义为低优先级中断。

中断优先级(高到低)

外部中断0
T0溢出中断
外部中断1
T1溢出中断
串行口中断
T2溢出中断(52)

3.TCON寄存器

在这里插入图片描述

TF1:片内定时器/计数器T1的溢出中断请求标志位。

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

TF0:片内定时器/计数器T0的溢出中断请求标志位。

功能与TF1相同。

IE1:外部中断请求1的中断请求标志位。

IE1=0,无中断请求。
IE1=1,外部中断1有中断请求。当CPU响应该中断,转向中断服务程序时,由硬件清“0”IE1。

IE0: 外部中断请求0的中断请求标志位。

IE0=0,无中断请求。
IE0=1,外部中断0有中断请求。当CPU响应该中断,转向中断服务程序时,由硬件清“0”IE0。

IT1:选择外部中断请求1为负跳变触发方式还是电平触发方式。

IT1=0,为电平触发方式,外部中断请求输入信号为低电平有效,并把IE置“1”。转向中断服务程序时,则由硬件自动把IE1清零。
IT1=1,为负跳变触发方式,外部中断请求输入信号电平为从高到低的负跳变有效,,并把IE置“1”。转向中断服务程序时,则由硬件自动把IE1清零。

IT0:选择外部中断请求0为负跳变触发还是电平触发方式。

与IT1相似。

4.SCON寄存器

在这里插入图片描述

TI:串行口发送中断请求标志位。

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

RI:串行口接收中断请求标志位。

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

(三)外部中断

51单片机的外部中断int0对应的引脚为p3.2,外部中断int1对应的引脚为p3.3。

1.外部中断0,按下开关K3,数码管0变1

寄存器配置:

    EA=1;//总中断允许
	EX0=1;//允许外部中断0
	IT0=0;//选择外部中断0为电平触发方式

完整代码:

#include<reg51.h>
#define uchar unsigned char
sbit key = P3^2;

void delay(unsigned int i)//延时函数
{
	unsigned int j;
	for(;i>0;i--)
		for(j=0;j<333;j++){}
}

void main()//主函数
{
	EA=1;//总中断允许
	EX0=1;//允许外部中断0
	IT0=0;//选择外部中断0为电平触发方式
	
	while(1)//循环
	{P0=0x3f;}//P0.0口的Led亮
}
void key_scan() interrupt 0 //外部中断0的中断服务函数
{
	if(key==0)//判断是否有按键按下
	{
		delay(10);//延时去抖
		if(key==0)
		{
			P2=0xfe;
			P0=0x06;
			while(!key);//等待按键松开
			P2=0xff;
			P0=0x3f;
		}

	}
}

2.外部中断1,按下开关K4,数码管0变1

寄存器配置:

    EA=1;//总中断允许
	EX1=1;//允许外部中断0
	IT1=0;//选择外部中断0为电平触发方式

完整代码:

#include<reg51.h>
#define uchar unsigned char
sbit key = P3^3;

void delay(unsigned int i)//延时函数
{
	unsigned int j;
	for(;i>0;i--)
		for(j=0;j<333;j++){}
}

void main()//主函数
{
	EA=1;//总中断允许
	EX1=1;//允许外部中断0
	IT1=0;//选择外部中断0为电平触发方式
	
	while(1)//循环
	{P0=0x3f;}//P0.0口的Led亮
}
void key_scan() interrupt 1 //外部中断1的中断服务函数
{
	if(key==0)//判断是否有按键按下
	{
		delay(10);//延时去抖
		if(key==0)
		{
			P2=0xfe;
			P0=0x06;
			while(!key);//等待按键松开
			P2=0xff;
			P0=0x3f;
		}

	}
}

3.外部中断扩展

寄存器配置:

    IT0 = 1;//跳沿触发
    IT1 = 1;//跳沿触发
    PX1 = 1;//中断1高于中断0
    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/

完整代码:

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
uint i;
void delay(uint xms);
void Int();
void Interrupt0(); 
void Interrupt1(); 

void main()
{
    Int();
    P2 = 0xfe;
while(1)
{
    for (i = 0;i < 7;i++)
    {
        P2 = _crol_(P2, 1);//先左移
        delay(600);
    }

    for (i = 0;i < 7;i++)
    {
        P2 = _cror_(P2, 1);//再右移
        delay(600);

    }

}


}

void Int()
{
    IT0 = 1;//跳沿触发
    IT1 = 1;//跳沿触发
    PX1 = 1;//中断1高于中断0
    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
}

void delay(uint xms)//AT89C5211.0592MHz
{
    uint x, y;
    for (x = xms;x > 0;x--)
        for (y = 110;y > 0;y--);
}

void Interrupt1() interrupt 0
{
    while (1)
    {
        P2 = 0x0f;
        delay(600);
        P2 = 0xf0;
        delay(600);
    }
}
void Interrupt2() interrupt 2/*外部中断1的标号是2!*/
{
    while (1)
    {
        P2 = 0xcc;//(11001100)
        delay(600);
        P2 = 0x33;
        delay(600);
    }


}

(四)定时器中断

1.定时器0

寄存器配置:

  TMOD = 0x01;
  TH0 = (65536 - 45872) / 256; // 设置定时器0为工作方式1(M1M0为01)
  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872
  EA = 1; // 开总中断
  ET0 = 1; // 开定时器0中断
  TR0 = 1; // 启动定时器0

完整代码:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit led1 = P2^0;
uchar num = 0;

void main()
{
  TMOD = 0x01;
  TH0 = (65536 - 45872) / 256; // 设置定时器0为工作方式1(M1M0为01)
  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872
  EA = 1; // 开总中断
  ET0 = 1; // 开定时器0中断
  TR0 = 1; // 启动定时器0
  while(1)
  {
    ;
  }
}

void T0_time() interrupt 1
{
  TH0 = (65536 - 45872) / 256;
  TL0 = (65536 - 45872) % 256;
  num++;
  if (num == 20)
  {
    num = 0;
    led1 = ~led1;
  }
}

2.定时器1

寄存器配置:

  TMOD = 0x01;
  TH0 = (65536 - 45872) / 256; // 设置定时器1为工作方式1(M1M0为01)
  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872
  EA = 1; // 开总中断
  ET1 = 1; // 开定时器1中断
  TR1 = 1; // 启动定时器1

完整代码:

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit led1 = P2^0;
uchar num = 0;

void main()
{
  TMOD = 0x01;
  TH0 = (65536 - 45872) / 256; // 设置定时器1为工作方式1(M1M0为01)
  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872
  EA = 1; // 开总中断
  ET1 = 1; // 开定时器1中断
  TR1 = 1; // 启动定时器1
  while(1)
  {
    ;
  }
}

void T1_time() interrupt 3
{
  TH0 = (65536 - 45872) / 256;
  TL0 = (65536 - 45872) % 256;
  num++;
  if (num == 20)
  {
    num = 0;
    led1 = ~led1;
  }
}

3.定时器计数控制数码管0到60

寄存器配置:

    TMOD=0x11;//写在一起
	//定时器0
	//TMOD=0x01;
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	EA=1;
	ET0=1;
	TR0=1;
	
	//定时器1
	//TMOD=0x10;
	TH1=(65536-45872)/256;
	TL1=(65536-45872)%256;
	EA=1;
	ET1=1;
	TR1=1;

完整代码:

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
                    0x3f,0x06,0x5b,0x4f,
                    0x66,0x6d,0x7d,0x07,
                    0x7f,0x6f,0x77,0x7c,
                    0x39,0x5e,0x79,0x71
                   };//共阴极数码管编码
uchar num0,num1;
uint ge ,shi;
sbit LSA=P2^2;//74HC138译码器端口
sbit LSB=P2^3;
sbit LSC=P2^4;
void  display_time(uint ,uint);
void delay_ms(uint);

void main()
{
	TMOD=0x11;//写在一起
	//定时器0
	//TMOD=0x01;
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	EA=1;
	ET0=1;
	TR0=1;
	
	//定时器1
	//TMOD=0x10;
	TH1=(65536-45872)/256;
	TL1=(65536-45872)%256;
	EA=1;
	ET1=1;
	TR1=1;
	while(1)
	{	
		display_time(ge ,shi);//时间一直显示中
	}
}

void T0_time()interrupt 1 //数码管处理 T0定时器
{
	TH0=(65536-45872)/256;//每50ms产生一次中断
	TL0=(65536-45872)%256;//所以每20次中断,个位+1
	num0++;
	if(num0==20)
	{
		num0=0;
		ge++;
		if(ge==10)
		{
			shi++; //时间进位
			ge=0;
		}
		if(shi==6)
		shi=0; //时间归零
	}
}

void  display_time(uint ge ,uint shi)
{
	LSA=0;LSB=1;LSC=1;
	P0=table[ge];//送入个位数字
	delay_ms(5);

	LSA=1;LSB=1;LSC=1;
	P0=table[shi];//送入十位数字
	delay_ms(5);
}
void delay_ms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=110;j>0;j--);
}

4.定时器做的时钟

寄存器配置:

    TMOD=0x01;
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	EA=1;
	ET0=1;
	TR0=1;

完整代码:

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar code table[]={
                    0x3f,0x06,0x5b,0x4f,
                    0x66,0x6d,0x7d,0x07,
                    0x7f,0x6f,0x77,0x7c,
                    0x39,0x5e,0x79,0x71
                   };//共阴极数码管编码
uchar num;
uint hour_ge,hour_shi,minute_ge, minute_shi,second_ge,second_shi;
sbit LSA=P2^2;//74HC138译码器端口
sbit LSB=P2^3;
sbit LSC=P2^4;
void  display_time(uint,uint,uint,uint,uint,uint);
void delay_ms(uint);
void main()
{
	TMOD=0x01;
	TH0=(65536-45872)/256;
	TL0=(65536-45872)%256;
	EA=1;
	ET0=1;
	TR0=1;
	while(1)
	{	
		display_time(hour_shi,hour_ge,minute_shi,minute_ge,second_shi,second_ge);
		//时间一直显示中
	}
}

void T0_time()interrupt 1 //数码管处理 T0定时器
{
	TH0=(65536-45872)/256;//每50ms产生一次中断
	TL0=(65536-45872)%256;//所以每20次中断,个位+1
	num++;
	if(num==20)
	{
		num=0;
		second_ge++;//秒+1
	}
	if(second_ge==10)
	{
		second_ge=0;
		second_shi++;
		if(second_shi==6)
		{
			second_shi=0;
			minute_ge++;
			if(minute_ge==10)
			{
				minute_ge=0;
				minute_shi++;
				if(minute_shi==6)
				{
					minute_shi=0;
					hour_ge++;
					if(hour_ge==10)
					{
						hour_ge=0;
						hour_shi++;
						if(hour_shi==2&&hour_ge==4)
						{
							hour_shi=0;
							hour_ge=0;
						}

					}	
				}	
			}
		}
	}
	
}



void display_time(uint hour_shi,uint hour_ge,uint minute_shi,uint minute_ge,uint second_shi,uint second_ge)
{
	LSA=0;LSB=0;LSC=0;//第六个数码管送入second_ge
	P0=table[second_ge];
	delay_ms(1);

	
	LSA=1;LSB=0;LSC=0;//第五个数码管送入second_shi
	P0=table[second_shi];
	delay_ms(1);

	LSA=1;LSB=1;LSC=0;//第四个数码管送入minute_ge 
	P0=table[minute_ge];		    
	delay_ms(1);

	LSA=0;LSB=0;LSC=1;//第三个数码管送入minute_shi 
	P0=table[minute_shi];
	delay_ms(1);

	LSA=0;LSB=1;LSC=1;//第二个数码管送入hour_ge
	P0=table[hour_ge];
	delay_ms(1);
	
  	LSA=1;LSB=1;LSC=1;//第一个数码管送入hour_shi
	P0=table[hour_shi];
	delay_ms(1);

}

void delay_ms(uint ms)
{
	uint i,j;
	for(i=ms;i>0;i--)
	for(j=110;j>0;j--);
}

(五)中断嵌套

1.外部中断嵌套K3,K4

寄存器配置:

    IT0 = 1;
    IT1 = 1;
    PX0 = 1;
    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/

完整代码:

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED1 = P2 ^ 0;
sbit LED2 = P2 ^ 1;

void Int();
void Interrupt1(); 
void Interrupt2(); 

void main()
{
    Int();
    while (1);

}

void Int()
{
    IT0 = 1;
    IT1 = 1;
    PX0 = 1;
    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/
}

void Interrupt1() interrupt 0
{
    LED1 = ~LED1;


}
void Interrupt2() interrupt 2/*外部中断1的标号是2!*/
{
    LED2 = ~LED2;

}

看到最后相信你也应该收获到很多,一起进步吧!

版权声明:本文为CSDN博主「是北豼不太皮吖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51029592/article/details/119351347

生成海报
点赞 0

是北豼不太皮吖

我还没有学会写个人说明!

暂无评论

相关推荐

实验一 stm32F407VETx点亮流水灯

二、设计指标 使电路板上的8个LED轮流点亮,并按键控制点亮速度。 三、操作 1、CubeMX操作 1.1依据开发板LED引脚设置CubeMX中8个LED的引脚为GPIO_Output模式, 2、按键设置

基于AT89C51的蓝牙循迹避障小车

基于AT89C51的蓝牙循迹避障小车 对标题的解读: AT89C51:在下使用的是STC89C52这款芯片,c51和c52在新手入门阶段是一样的,所以不必纠结于到底是哪个名字&#xff

基于单片机的智能家居控制系统

设计简介: 本设计是基于单片机的智能家居控制系统,主要实现以下功能: 可通过DS18B20实时测量环境温度温度具有上下限,自动模式下温度超出限值,GMS发送短信温度上下限