单片机原理及应用:中断服务函数

发布时间:2024年01月09日

承接上文,今天我们来学习一下中断服务函数,对中断不了解的朋友可以回顾一下笔者之前的文章

中断系统结构与控制寄存器

中断服务函数是嵌入式系统中用于处理中断事件的函数,在原版的C语言中并不存在。当发生中断事件时,系统将会跳转到相应的中断服务函数来处理该事件。

中断服务函数的调用过程可以参照一般的函数调用,但两者之间也是有区别的:
  • 一般函数的调用在程序中是事先安排好的,何时调用中断服务函数事先却无法确定,因为中断的发生是由外部因素决定的,程序中无法事先安排调用语句,因此调用中断服务函数的过程是由硬件自动完成的。换而言之,我们并不需要像之前点亮LED或数码管那样在主程序里补充一条LED_?function()来调用封装函数,中断服务函数在控制寄存器允许的情况下会自动执行。
  • 中断函数具有特殊关键字interrupt,这也导致中断函数的定义方法也与普通函数不同。

定义语法如下:函数类型 函数名 (形式参数)[interrupt n] [using m]

函数类型多为void,就笔者目前所学而言,中断函数不需要返回值;函数名自拟,其后的形式参数为空;关键字interrupt表示中断,其后的n对应中断源的编号,5个中断源编号根据优先级从小到大排序,如下表所示
中断编号中断源
0外部中断0
1定时/计数器0溢出中断
2外部中断1
3定时/计数器1溢出中断
4串行口中断

m对应寄存器组号,取值范围是0~3,我们也可以不指定执行中断服务的寄存器组号,由编译器自动分配。

下面我用中断函数来尝试改变LED的点亮状态。

#include <reg51.h>
#include<intrins.h>
#define uchar  unsigned char

void Delay(unsigned int i)	
{	unsigned int j;
 	for(;i > 0;i--)		
		for(j=0;j<333;j++);        
}

void  main( )		
{					//开始设置中断允许控制寄存器,使用外部中断0
	EA=1;			//开启总中断允许
 	EX0=1;			//允许外部中断0中断
	//IE=0x81;      //可以用字节赋值IE代替上述位赋值

					//开始设置定时/计数器控制寄存器中的触发方式
	IT0=1;			//选择外部中断0为跳沿触发方式
	while(1)			 
	{ uchar temp,i;
		temp=0xfe;
		for(i=0;i<8;i++)  //主函数为库函数流水灯
		{
		P1=temp;
		Delay(400);
		temp=_crol_(temp,1);
		}
}		
}
//在允许外部中断0中断的情况下,P3.2引脚上检测到低电平,执行外部中断0服务函数 	
void int0( )  interrupt 0  	//外部中断0的中断服务函数,定义时省略了using
{	uchar  m;
	EX0=0;			//禁止下一次外部中断0中断信号的输入,防止打断本次中断,可以省略
 	for(m=0;m<2;m++)	//LED闪烁
	{
	  P1=0x0f;	
		Delay(400) ;		
 		P1=0xf0;		
 		Delay(400); 		
	}
		EX0=1;			//执行完毕后,打开外部中断0中断,等待下一次中断请求
}

大家可以看到在仿真软件中有一枚按键与P3.2引脚相连,当按下按键时,引脚便会检测到低电平,执行中断服务函数。

由于引脚只要检测到低电平便会触发中断,因此中断按键无法消抖。?

此外,我们在设计单片机时,通常希望触发中断函数时程序执行得越快越好,如报警装置应尽量及时让人们注意到异常状态,因此我们可以简化中断服务函数,将执行主体置于主函数中,中断函数只起到一个修改状态值,以便主函数在检测到该值时及时切换执行程序。

#include <reg51.h>
#include<intrins.h>
#define uchar  unsigned char
uchar flag1=0;				 //加入中断标志
void Delay(unsigned int i)	
{	unsigned int j;
 	for(;i > 0;i--)		
		for(j=0;j<333;j++);        
}

void  main( )		
{							
    IE=0x81;     					
	IT0=1;			
	while(1)			 
{    uchar temp,i,m;
	 temp=0xfe;
	 if(flag1==0)	      //常态下标志位为0,执行主函数
	 {
		for(i=0;i<8;i++)  //主函数为库函数流水灯
		{
		P1=temp;
		Delay(400);
		temp=_crol_(temp,1);
			               } 
			                }
	  if(flag1==1)			//触发中断后更改标志位
	  {
		 for(m=0;m<2;m++)	//中断函数LED闪烁
	     {
	     P1=0x0f;	
		 Delay(400) ;		
 		 P1=0xf0;		
 		 Delay(400); 		
		            } 
		 flag1=0;			//还原标志位,继续执行主函数
		             }
}		
}
 	
void int0( )  interrupt 0  	//中断服务函数化简
{
  flag1=1;					//只有一个标志位赋值语句
}

不过这样做也存在缺点,中断函数虽然更改了标志位数值,但是两个if函数是平行关系,也就是说只有主函数执行完一次代码块后才能切换为中断服务函数,我在视频中也演示了这两种方法的区别。

外部中断控制LED点亮模式改变

感谢大家,之后会为大家演示多种中断方式的嵌套应用。

文章来源:https://blog.csdn.net/qq_62530454/article/details/135471180
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。