07-中断系统与外部中断应用
外部中断的基本操作与应用
关于51单片机的中断系统
一般来说,51单片机有5个中断源(忽略定时/计数器2),分2个优先级,这个5个中断源按照自然优先级从高到低依次为:
外部中断0: INT0
定时/计数器0: TF0
外部中断1: INT1
定时/计数器1: TF1
串口中断: RI/TI
下面一图将充分说明51单片机的中断系统结构:
每个中断源都对应着一个固定的入口地址,也就是中断向量,它们依次是:
0 0x0003: INT0
1 0x000B: TF0
2 0x0013: INT1
3 0x001B: TF1
4 0x0023: RI/TI
也就是说,不管主程序执行到什么地方,只要外部中断1产生请求,内核要响应该中断,就会到0x0013这个地址去执行代码。如果你是在使用汇编语言进行程序开发的时候,你需要记住每个中断源对应的地址;如果你使用的是C语言,你只需要记住中断源的顺序就可以了,也就是最左边的中断号。
3、中断相关的寄存器
中断相关的寄存器有4个,每个寄存器都是可以位寻址的,这该编程带来了方便。 其中2个为控制寄存器:IE寄存器与IP寄存器:
另外2个为中断请求标志:TCON寄存器与SCON寄存器:
4、关于中断服务函数程序的编写
一般情况下,中断的处理函数有两个,其一为中断初始化函数,其二为中断服务函数。初始化函数就是一个普通的函数,而中断服务函数却有特殊的格式要求:
<1> 中断函数没有返回值,也不能带参数。
<2> 函数名后面要跟一个关键字interrupt,说明这是一个中断服务函数。
<3> 在关键字interrupt后面要跟上中断号,说明这个中断服务函数是为那个中断服务的。
中断服务函数的格式为:
void 函数名() interrupt 中断号
{ ----函数体---- }
我们要利用定时器0来进行间隔定时,中断程序架构我们C语言可以这样写:
由上可知将J5跳帽接到2~3脚,S5按键可以操作外部中断INT0
原理图如下:
方法一:
#include <REGX52.H>
sbit L1 = P0^0;
sbit L8 = P0^7;
// 延时函数
void Delay_ms(unsigned int xms) {
unsigned int i,j;
for(i = 0; i<xms; i++) {
for(j=0;j<299;j++);
}
}
// 10us
void Delay(unsigned int t) {
while(t--);
while(t--);
while(t--);
}
void _74HC138(unsigned char n) {
switch(n) {
case 4:P2=(P2 & 0x1f) | 0x80;
break;
case 5:P2=(P2 & 0x1f) | 0xa0;
break;
case 6:P2=(P2 & 0x1f) | 0xc0;
break;
case 7:P2=(P2 & 0x1f) | 0xe0;
break;
}
}
void SystemInit(void) {
_74HC138(5);
P0=0X00;
_74HC138(4);
P0 = 0XFF;
}
void Working(void) {
_74HC138(4);
L1 = 0;
Delay_ms(1000); // 1us = 1000ms
L1 = 1;
Delay_ms(1000);
}
void Init_INT0() {
// 源类型选择器
// IT0 = 0; 低电平触发, IT0=1;下降沿触发
IT0 = 1;
// 中断使能
EX0 = 1;
// 打开总中断
EA = 1;
}
void main(void) {
SystemInit();
Init_INT0();
while(1) {
Working();
}
}
// 由于P3_2口和INT0引脚一致
void Int0_Routine(void) interrupt 0 {
L8 = 0;
Delay_ms(1000);
L8 = 1;
Delay_ms(1000);
}
方法二:
#include <REGX52.H>
sbit L1 = P0^0;
sbit L8 = P0^7;
// 延时函数
void Delay_ms(unsigned int xms) {
unsigned int i,j;
for(i = 0; i<xms; i++) {
for(j=0;j<299;j++);
}
}
// 10us
void Delay(unsigned int t) {
while(t--);
while(t--);
while(t--);
}
void _74HC138(unsigned char n) {
switch(n) {
case 4:P2=(P2 & 0x1f) | 0x80;
break;
case 5:P2=(P2 & 0x1f) | 0xa0;
break;
case 6:P2=(P2 & 0x1f) | 0xc0;
break;
case 7:P2=(P2 & 0x1f) | 0xe0;
break;
}
}
void SystemInit(void) {
_74HC138(5);
P0=0X00;
_74HC138(4);
P0 = 0XFF;
}
void Working(void) {
_74HC138(4);
L1 = 0;
Delay_ms(1000); // 1us = 1000ms
L1 = 1;
Delay_ms(1000);
}
void Init_INT0() {
// 源类型选择器
// IT0 = 0; 低电平触发, IT0=1;下降沿触发
IT0 = 1;
// 中断使能
EX0 = 1;
// 打开总中断
EA = 1;
}
unsigned char stat_int = 0;
void LED_INT() {
if(stat_int == 1) {
L8 = 0;
Delay_ms(1000);
L8 = 1;
Delay_ms(1000);
}
stat_int = 0;
}
void main(void) {
SystemInit();
Init_INT0();
while(1) {
Working();
LED_INT();
}
}
// 由于P3_2口和INT0引脚一致
void Int0_Routine(void) interrupt 0 {
stat_int = 1;
}