记录对51单片机中断、定时/计数器的重要知识点以及难点理解,并且举例中断在实际编程中的应用,从而加深对单片机中断、定时/计数器的理解,熟练的使用中断。
中断就是计算机在执行某一程序的过程中,由计算机系统内部或外部的某种原因而必须终止当前程序的运行,先去执行相应的处理程序,然后再返回继续执行原程序。
实现中断功能的软、硬件系统统称为中断系统。
通常情况下,一个程序中可能会有多个中断,优先级越高的中断优先执行。如果在一个中断的服务过程中,有一个优先级更高的中断插入,则当前中断暂停,前往执行优先级更高的中断。当优先级高的中断执行完毕后再返回继续执行低优先级的中断。
MCS-51共有五个中断源
INT0
、INT1
T0
和T1
的溢出中断中断源 | 功能 |
---|---|
INT0 |
外部中断0请求,由INT0 引脚(P3.2)输入。低电平/负跳变有效,中断请求标志为IE0 |
INT1 |
外部中断1请求,由INT1 引脚(P3.3)输入。低电平/负跳变有效,中断请求标志为IE1 |
T0 |
定时/计数器0溢出中断请求,中断标志位为TF0 |
T1 |
定时/计数器1溢出中断请求,中断标志位为TF1 |
RXD/TXD |
串行口中断请求,中断请求标志位TI 或RI |
从单片机外部引脚INT0
和INT1
输入中断请求信号的中断。
外部中断的触发方式有两种电平触发IT0 =0
和跳变触发(边沿)IT0 = 1
,可以通过定时/计数器控制寄存器TCON
编程选择。
与中断有关的特殊功能寄存器一共有4个。
TCON
)、SCON
)、IE
)、IP
)TCON
作用:
T0
和T1
的溢出中断IT0
和IT1
控制位地址 | 位定义 | 功能 |
---|---|---|
88H | IT0 | 选择外部中断0的中断触发方式。由软件控制。IT0=0为电平触发方式 。IT0=1为下降沿触发方式 |
89H | IE0 | 选择外部中断1的中断触发方式。功能与IT0 相似 |
8AH |
SCON
串行口的接收发送数据中断请求标志位(RI
和TI
)
位定义 | 功能 |
---|---|
TI |
串行口发送中断请求标志位。CPU每发送一帧数据,硬件置位1(TI=1 ),但是中断被响应时,需要在中断服务程序中通过软件对TI 清零 |
RI |
串行口接受中断请求标志位。每接收一帧数据,硬件置位1(TI=1 ),但是中断被响应时,一样需要在中断服务程序中通过软件对TI 清零 |
串行口中断不能由硬件自动清除中断请求标志位,需要用户通过软件进行控制清零。
IE
IE
是控制中断的开关,通过对IE
的清0和置1操作来控制中断的屏蔽和开放。
中断允许控制寄存器IE
对中断的开放与屏蔽实现两级控制,存在一个总的中断控制位EA
位定义 | 功能 |
---|---|
EA |
总中断允许控制位。当EA=0 时,不允许任何中断请求。 |
ES |
串行口中断控制位。当ES=0 时,不允许串行口中断;当EA=1 且ES=1 时,允许串行口中断。 |
ET1 |
定时/计数器1中断允许控制位。当ET1=0 时,屏蔽T1 的溢出中断;当EA=1且ET1=1 时,允许T1溢出中断 |
ET0 |
定时/计数器0中断允许控制位。功能与ET1 相同。 |
EX1 |
外部中断1的中断允许控制位。当EX1=0 时,屏蔽外部中断1的中断请求;当EA=1 且EX1=1 时,允许外部中断1的中断请求 |
EX0 |
外部中断0的中断允许控制位。功能与EX1 相同 |
若某个中断源被允许,出来IE
对应位置1外,还需要总中断控制位EA
置1。
实例:若允许片内两个定时/计数器中断,禁止其他中断源的中断请求,尝试编写出设置IE的响应指令
#include
EX0 = 0; // 禁止外部中断0
EX1 = 0; // 禁止外部中断1
ES = 0; // 禁止串行口中断
ET0 = 1; // 允许定时/计数器0中断
ET1 = 1; // 允许定时/计数器1中断
EA = 1; // 总中断控制器打开
IP
位定义 | 功能 |
---|---|
PS |
串行口中断优先级控制位。PS=1,串行口中断为高优先级;PS=0,为低优先级。 |
PT1 |
定时/计数器1中断优先级控制位。当PT1=0 时,T1溢出中断为低优先级;当PT1=1 时,T1溢出中断为高优先级。 |
PT0 |
定时/计数器0中断优先级控制位。当PT0=0 时,T0溢出中断为低优先级;当PT0=1 时,T0溢出中断为高优先级。 |
PX1 |
外部中断1的中断优先级控制位。当PX1=0 时,外部中断1为低优先级;当PX1=1 时,外部中断1为高优先级。 |
PX0 |
外部中断0的中断优先级控制位。当PX0=0 时,外部中断0为低优先级;当PX0=1 时,外部中断0为高优先级。 |
同级内第二优先级的次序:
外部中断0 > T0溢出中断 > 外部中断1 > T1溢出中断 > 串行口中断
#include
void init() // 中断的初始化函数
{
EA = 1; // 总中断控制位
ES = 1; // 串行口中断允许
EX0 = 1; // 外部中断0允许
EX1 = 1; // 外部中断1允许
ET0 = 1; // 定时/计数器0中断允许
ET1 = 1; // 定时/计数器1中断允许
IT0 = 1; // 选择外部中断0的触发方式
IT1 = 1; // 选择外部中断1的触发方式
}
例1:假设允许外部中断0和1中断,并设定外部中断0为高级中断,外部中断1为低级中断,外部中断0为下降沿触发方式,外部中断1为电平触发方式。试写出该程序的中断初始化程序。
#include
void init() //
{
EA = 1; 打开中断控制
EX0 = 1; 允许外部中断0
EX1 = 1; 允许外部中断1
IT0 = 1; 外部中断1采取边沿触发方式
IT1 = 0; 外部中断0采取电平触发方式
PX0 = 1; 外部中断0为高优先级
PX1 = 0; 外部中断1为低优先级
}
要求:
用80C51单片机控制8个LED灯,在外部中断0输入引脚(P3.2)接一个开关K1。要求将外部中断0设置为下降沿触发,程序启动是8个LED以跑马灯的形式交替闪烁。每按一次开关K1,使引脚接地,产生一个下降沿触发的外部中断请求。在中断服务程序中,8个LED高四位和低四位交替闪烁5次,然后中断返回,8个LED继续以跑马灯形式闪烁。
采用Protues
+Keil
仿真
元器件
- 单片机:
80C51
*1- 开关按钮:
Button
*1- 电阻:
MINRES470K
*1- LED:
LED-BLUE
*8
仿真图
#include
unsigned char code table[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0x00,0xff}; // 控制P2端口的状态
unsigned char i,j,k,num;
void delay() // 延时函数
{
for(i = 0;i<100;i++)
{
for(j=0;j<200;j++)
;
}
}
void init() // 中断的初始化
{
EA = 1; // 打开总中断控制
EX0 = 1; // 允许外部中断0
IT0 = 1; // 外部中断为下降沿触发方式
}
void main()
{
init();
while(1)
{
for(num =0;num<10;num++)
{
P2 = table[num];
delay();
}
}
}
void int0() interrupt 0 // 中断服务程序
{
for(k = 0;k<5;k++){
P2 = 0xf0;
delay();
P2=0x0f;
delay();
}
}
要求:在例2的基础上,在外部中断1输入引脚(P3.3)接一只按钮开关K2。当按下K1时,外部中断0下降沿触发方式触发,进入外部中断0服务程序,上下4个灯交替闪烁;此时按下K2,外部中断1下降沿触发方式触发,进入外部中断1服务程序,8个灯交替闪烁。当外部中断1响应完毕后,返回继续响应外部中断0,直到外部中断0响应完毕,返回执行主程序。
首先我们分析一波中断初始化函数
两个外部中断0和1。外部中断0的服务程序为上下4灯交替闪烁,外部中断1的服务程序为8灯闪烁。即EA = 1; EX0 = 1; EX1 = 1;
优先级:外部中断1 > 外部中断0 即PX1 = 1; PX0 = 0;
触发方式:都为下降沿触发。即IT0 = 1; IT1 = 1;
这样我们的中断初始化程序基本完成
void init()
{
EA = 1;
EX0 = 1; EX1 = 1;
PX0 = 0; PX1 = 1;
IT0 = 1; IT1 = 1;
}
其次我们再捯饬一下主程序
void main()
{
init();
while(1)
{
for(num =0;num<10;num++)
{
P2 = table[num];
delay();
}
}
}
另外我们再搞一下外部中断0的服务程序
void int0() interrupt 0
{
for(k = 0;k<5;k++)
{
P2 = 0xf0;
delay();
P2=0x0f;
delay();
}
}
最后我们再他喵的弄一下外部中断1的服务程序
void int1() interrupt 2 // 外部中断1服务程序
{
for(l = 0;l < 5; l++)
{
P2 = 0x00;
delay();
P2 = 0xff;
delay();
}
}
完整代码
#include
unsigned char code table[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, 0x00, 0xff}; // 控制P2端口的状态
unsigned char i, j, k, l, num;
void delay() // 延时函数
{
for(i = 0; i < 200; i++)
{
for(j = 0; j < 200; j++)
;
}
}
void init() // 中断的初始化
{
EA = 1;
EX0 = 1; EX1 = 1;
PX0 = 0; PX1 = 1;
IT0 = 1; IT1 = 1;
}
void main()
{
init();
while(1)
{
for(num = 0; num < 10; num++)
{
P2 = table[num];
delay();
}
}
}
void int0() interrupt 0 // 外部中断0中断服务程序
{
EX0 = 0;
for(k = 0; k < 5; k++)
{
P2 = 0xf0;
delay();
P2 = 0x0f;
delay();
EX0 = 1;
}
}
void int1() interrupt 2 // 外部中断1服务程序
{
for(l = 0;l < 5; l++)
{
P2 = 0x00;
delay();
P2 = 0xff;
delay();
}
}
仿真图