承接上文,今天我们来学习一下中断服务函数,对中断不了解的朋友可以回顾一下笔者之前的文章
中断服务函数是嵌入式系统中用于处理中断事件的函数,在原版的C语言中并不存在。当发生中断事件时,系统将会跳转到相应的中断服务函数来处理该事件。
定义语法如下:函数类型 函数名 (形式参数)[interrupt n] [using m]
中断编号 | 中断源 |
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点亮模式改变
感谢大家,之后会为大家演示多种中断方式的嵌套应用。