中断系统知识点

发布于:2022-12-25 ⋅ 阅读:(571) ⋅ 点赞:(0)

目录

一、中断基础知识介绍

1、中断基础

2、寄存器

3、中断口的设置

二、外部中断的使用 

1、中断使用流程

2、中断代码 

三、内部中断的使用 

1、相关知识介绍

2、中断使用流程

3、相关代码 


中断其实并不是那么吓人哦,一定要搞清楚各寄存器、中断口、中断源等示意图,后来你会发现其实就是根据你一开始的选择不断设置而已!

一、中断基础知识介绍

你知道中断是什么吗?它有哪些类型呢?

1、中断基础

中断系统:计算机执行某程序时,发生了紧急事件或有特殊请求,处理完毕后再重新执行程序的过程

中断类型: 中断分为外部中断及内部中断,外部中断可以由低电平或下降沿两种方式实现,而       内部中断则分为计数器模式和定时器模式。

中断流程:    中断请求->中断响应->中断处理->中断返回

**中断源示意图**:

小tip:后面中断相关代码都要根据该图设置,不是随意设置的,该图的掌握对中断而言至关重要哦!

2、寄存器

寄存器的使用与设置,是中断不可缺少的重要环节,它可用于控制中断开关、设置中断方式等等。

(1)IE寄存器

(2)TCON寄存器

 

小知识穿插(有关数据的输入/输出传送方式):

  • 无条件传送方式 : 一方对另一方总是准备好的
  • 查询传送方式 :   传送前一方先查询另一方状态,若已准备好就传送,否则就继续查询/等待
  • 中断传送方式: 一方通过申请中断的方式与另一方进行数据传送

3、中断口的设置

一定要根据自己选择的中断方式与触发方式(或工作模式)结合图示选择中断入口,不可以自己随意设置! 

二、外部中断的使用 

不管是内部中断还是外部中断,上述内容中的寄存器与中断源示意图都需要熟练掌握哦,后面的程序均要结合其进行代码编写!

1、中断使用流程

  1. 允许中断(IE寄存器)    打开IE中断总开关   打开相应的中断开关(外部中断0或1)
  2. 配置中断方式(TCON寄存器) 选择中断方式为低电平还是下降沿
  3. 编写中断服务函数(写对应的中断入口)和主函数 

2、中断代码 

     下降沿触发相关代码

#include <reg52.h>

#define  uchar unsigned char
#define  uint  unsigned int

sbit flag = P3^3;  //对应P3^3的第二功能(外部中断1输入)
sbit key = P3^1;  //中断1必须要使用P3^3,中断2必须使用P3^2

void delay(uint z)
{
    uint x,y;
    for(x=z;x>0;x--)
        for(y=114;y>0;y--);
}

void int1init()
{
    EA=1;  //打开EA总开关
    EX1=1; //允许外部中断1中断
    ET1=1;  //外部中断1下降沿触发
}

void int1() interrupt 2
{
    //该单片机中断口有问题,进了中断不会出来,只能加上该循环,正常情况可以不用
    while(!key)
    {
        P2=~P2;  //P2的状态按位取反
    }
}

void main() 
{
    int1init();  //调用初始化函数进行初始化
    while(1)
    {
        if(key==0)
        {
             delay(20);
             if(key==0)
             {
                  flag=1;
                  flag=0;
                  while(!key);  //松手检测
             }

        }


    }


}

三、内部中断的使用 

1、相关知识介绍

       51单片机有两个16位定时器/计数器:  定时器0(T0 引脚为P3^4)   定时器1(T1引脚为P3^5)

       因此,定时器/计数器可以工作在如下不同模式:

  **当定时器工作在定时器模式时**   每经过一个机器周期内部的16位计数寄存值加1,当这个寄存器装满时溢出

  **当定时器工作在计数器模式**   T0(P3^4)  T1(P3^5) 每来一个脉冲寄存器加1

工作模式寄存器(用于调配上述寄存器工作模式)

2、中断使用流程

       1、允许中断(IE寄存器) 打开IE中断总开关                                                                                     2、启动定时/计数器(TCON控制器) TR0=1/TR1=1(T0/T1开始计数)                                               3、设置定时/计时器工作模式    调配定时/计时工作模式  调配8位/16位模                                         4、查询定时/计数器是否溢出(读TCON中TF位)

3、相关代码 

定时器模式

#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); 
			}
		}
   }
}

小tips:定时器模式初值如何设置?

          例如 5ms,5ms=5000us,5000/1.085(机器周期)=4608(次),65535-4608=60926; 将其换算为二进制为11101101 11111110,则高八位为0xED(TH0),低八位为0xFE(TL0)

计时模式 

#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

#define uchar unsigned char
#define uint unsigned int

uint data;

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

//延时函数
void delay(uchar z)
{
    uchar x,y;
    for(x=z;x>0;x--)
        for(y=114;y>0;y--);
}

void timeint1()  //定时器1中断初始化
{
    EA = 1; //打开中断总开关
    TR1 = 1;
    TMOD = 0x10;  //0001 0000(十六位定时器,TL1、TH1全用)		
    TH0=0xED;
    TL0=0XFE;    //设置初值为5ms
}


void display(data)
{
    uint m,n;
    m=data/10;  //该数的十位数
    n=data%10;  //该数的个位数
    static uchar wei = 0;  //静态变量,函数执行完了之后数据不会抹去,下一次执行该函数还可以接着用
    switch(wei)
    {
         case 0: LA=1;LB=1;LC=1; P0=smgduan[m]; break;
         case 1: LA=0;LB=1;LC=1; P0=smgduan[n]; break;
    }
    wei++;  //也就是说,每过10ms才会实现一次个位与十位的显示,但是速度极快,可以看成是动态显示
    if(wei==2)
    {
        wei=0; 
    }

}


void timer1() interrupt 0
{
    TH0=0xED;
    TL0=0XFE;    //重新设置初值为5ms
    display(data);  //显示数字,不断5ms即实现动态显示
}

void main()
{
    timeint1();
    while(1)
    {
     	if(key1==0)  //按键1被按下时为零
    	{
         		delay(20);
        		 if(key1==0)  //防误触
         		{
         			data++;  //按键按下,秒数加1
                		while(!key1)  //松手检测
         		}
    	}
    	if(key2==0)  //按键2被按下时为0
   	 {
         		delay(20);
         		if(key2==0)  //防误触
        	 	{
         			data--;  //按键按下,秒数减1
                		while(!key2)  //松手检测
        	 	}
   	 }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到