目录
(1)TCON寄存器(Timing Control Register)
(2)SCON寄存器(Serial Control Register)
(三)采用计数器中断,实现 按4次按钮开关后,P1口的8只LED闪烁不停
一.作者小课堂
在上一篇博客里,我们已经充分了解学习了普中51单片机实验开发板的开发使用方法,那么现在让我们共同进入中断与定时记数的学习中吧!同时本篇博客将会迎来新的朋友:gitee代码版本仓库网站!
(一)什么是AT89S51中断技术?
1.概述
中断技术主要用于实时监测与控制,要求单片机能及时地响应中断请求源提出的服务请求,并快速响应与及时处理。 当中断请求源发出中断请求时,如中断请求被允许,单片机暂时中止当前正在执行的主程序,转到中断服务处理程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。
如没有中断系统,单片机大量时间可能会浪费在查询是否有服务请求的定时查询操作上,即不论是否有服务请求,都必须去查询。采用中断技术完全消除查询方式的等待,大大提高单片机工作效率和实时性。
图1.中断响应和处理过程
2.中断系统结构
中断系统有5个中断请求源(简称中断源),2个中断优先级,可实现2级中断服务程序嵌套。每一中断源可用软件独立控制为允许中断或关闭中断状态;每一个中断源的优先级均可用软件设置。
图2.中断系统结构
INT0* | 外部中断请求0,外部中断请求信号(低电平或负跳变有效)由INT0*引脚输入,中断请求标志为IE0。 |
INT1* | 外部中断请求1,外部中断请求信号(低电平或负跳变有效)由INT1*引脚输入,中断请求标志为IE1。 |
TF0 | 定时器/计数器T0计数溢出的中断请求 |
TF1 | 定时器/计数器T1计数溢出的中断请求 |
发送中断TI/接 收中断RI | 串行口中断请求 |
3.中断请求标志寄存器
5个中断请求源的中断请求标志分别由特殊功能寄存器TCON和SCON相应位锁存
(1)TCON寄存器(Timing Control Register)
图3.特殊功能寄存器TCON的格式
(2)SCON寄存器(Serial Control Register)
图4. SCON中的中断请求标志位
(二)定时器/计数器的工作原理及应用
1. 定时器/计数器的结构
AT89S51定时器/计数器结构见图 7-1,定时器/计数器T0由特殊功能寄存器TH0、TL0构成,T1由特殊功能寄存器TH1、TL1构成。
图5. 定时器/计数器结构框图
二.实践出真知
(一)按键中断控制流水灯的实验
1.单一外中断的应用
(1)实验内容
在单片机P1口上接有8只LED。在外部中断0输入引脚(P3.2)接一只按钮开关K1。要求将外部中断0设置为电平触发。程序启动时,P1口上的8只LED全亮。每按一次按钮开关K1,使引脚接地,产生一个低电平触发的外中断请求,在中断服务程序中,让低4位的LED与高4位的LED交替闪烁5次。然后从中断返回,控制8只LED再次全亮。
(2)代码示例
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( ),i形式参数,不能赋初值
{
unsigned int j;
for(;i > 0;i--)
for(j=0;j<333;j++) //晶振为12MHz,j选择与晶振频率有关
{;} //空函数
}
void main( ) //主函数
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
IT0=1; //选择外部中断0为跳沿触发方式
while(1) //循环
Delay(400) ; //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
EX0=1; //中断返回前,打开外部中断0中断
}
(3)proteus电路图示例
图6.
(4)仿真结果及实验结果演示
①proteus仿真结果
本例程包含两部分,一部分是主程序段,完成中断系统初始化,并把8个LED全部点亮。另一部分是中断函数部分,控制4个LED交替闪烁1次,然后从中断返回。
图7
②普中开发板实验结果
图8
2.两个外中断的应用
(1)实验内容
当需要多个中断源时,只需增加相应的中断服务函数即可。
(2)代码示例
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( ),i为形式参 //数,不能赋初值
{
uchar j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;} //空函数
}
void main( ) //主函数
{
uchar display[9]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf, 0x7f};
//流水灯显示数据数组
unsigned int a;
for(;;)
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
IP=0; //两个外部中断均为低优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P1=display[a]; //将已经定义的流水灯显示数据送到P1口
}
}
}
void int0_isr(void) interrupt 0 using 1//外中断0的中断服务函数
{
uchar n;
for(n=0;n<10;n++) //高、低4位显示10次
{
P1=0x0f; //低4位LED灭,高4位LED亮
Delay(500); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(500); //延时
}
}
void int1_isr (void) interrupt 2 using 2//外中断1中断服务函数
{
uchar m;
for(m=0;m<10;m++) //闪烁显示10次
{
P1=0xff; //全灭
Delay(500); //延时
P1=0; //全亮
Delay(500); //延时
}
}
(3)proteus电路图示例
图9
(4)仿真结果及实验结果演示
①proteus仿真结果
图10
②普中开发板实验结果
图11
3.中断嵌套的应用
(1)实验内容
中断嵌套只发生正执行一个低优先级中断,此时又有一高优先级中断产生,就会去执行高优先级中断服务程序。高优先级中断服务程序完成后,再继续执行低优先级中断程序。
(2)代码示例
#include <reg51.h>
#define uchar unsigned char
void Delay(unsigned int i) //延时函数Delay( )
{
unsigned int j;
for(;i > 0;i--)
for(j=0;j<125;j++)
{;} //空函数
}
void main( ) //主函数
{
uchar display[9]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//流水灯显示数据组
uchar a;
for(;;)
{
EA=1; //总中断允许
EX0=1; //允许外部中断0中断
EX1=1; //允许外部中断1中断
IT0=1; //选择外部中断0为跳沿触发方式
IT1=1; //选择外部中断1为跳沿触发方式
PX0=0; //外部中断0为低优先级
PX1=1; //外部中断1为高优先级
for(a=0;a<9;a++)
{
Delay(500); //延时
P1=display[a]; //流水灯显示数据送到P1口驱动LED显示
}
}
}
void int0_isr(void) interrupt 0 using 0 //外中断0中断函数
{
for(;;)
{
P1=0x0f; //低4位LED灭,高4位LED亮
Delay(400); //延时
P1=0xf0; //高4位LED灭,低4位LED亮
Delay(400); //延时
}
}
void int1_isr (void) interrupt 2 using 1 //外中断1中断函数
{
uchar m;
for(m=0;m<5;m++) //8位LED全亮全灭5次
{
P1=0; //8位LED全亮
Delay(500); //延时
P1=0xff; //8位LED全灭
Delay(500); //延时
}
}
①proteus仿真结果
图12
②普中开发板实验结果
图13
(二)采用定时计数器控制LED灯每隔1s周期性亮灭的实验
(1)实验内容
在AT89S51的P1口上接有8只LED,原理电路见图7-13。采用T0方式1的定时中断方式,使P1口外接的8只LED每0.5s闪亮一次。
(2)代码示例
#include <REGX52.H>
void Timer0_Init()
{
//设置定时器工作模式TMOD为方式1
TMOD&=0xF0;//高四位不变,低四位清零
TMOD|=0x01;//最低位置1,其余位不变 //TOMD=0x01
//定时时间=(2^16-X)*12/晶振频率
TL0=0x66;
TH0=0xFC;//定时1ms
//设置定时器控制寄存器TCON
TF0=0; //中断溢出标志位先清0,避免刚配置好就中断
TR0=1; //定时器开始工作
//中断
EA=1;//允许总中断
ET0=1;//T0的中断溢出允许位,T0=1,允许中断
}
void main()
{
Timer0_Init();
while(1)
{}
}
void Timer0_Runtine() interrupt 1
{
unsigned int a;//计数
TL0=0x66;
TH0=0xFC;
Count++;
if(a>=1000)//计数累加到1000,定时器定时1000ms=1s
{
P2_0=~P2_0;//LED状态取反
a=0;
}
}
(3)proteus电路图示例
图14
(4)仿真结果及实验结果演示
①proteus仿真结果
图15
②普中开发板实验结果
图16
(三)采用计数器中断,实现 按4次按钮开关后,P1口的8只LED闪烁不停
(1)实验内容
采用计数器中断,实现 按4次按钮开关后,P1口的8只LED闪烁不停
(2)代码示例
#include <REGX51.H>
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void Count0_Init() //计数器
{
//设置计数器0工作模式1
TMOD&=0xf0;
TMOD|=0x05;// C/T置1为计数器模式
TL0=0xfc;
TH0=0xff;//计数4次,65536-4=65532
//设置计数器控制寄存器TCON
TF0=0;
TR0=1;
//中断
EA=1;
ET0=1;
}
void main()
{
Count0_Init();
while(1)
{
}
}
void Count0_Routine() interrupt 1
{
while(1)
{
P2=~P2;
Delay1ms(500);
P2=~P2;
Delay1ms(500);
}
}
(3)proteus电路图示例
图 17
(4)仿真结果及实验结果演示
①proteus仿真结果
图18
三.你好,gitee!
在本期的博客,我们将认识一个新的学习平台——gitee。
图19
注册之后,我们就可以在这个平台进行一些列的学习活动了!
四.总结
通过此次的学习,我掌握了一下知识:深入了解51单片机中断原理,掌握外部中断、定时器/计数器中断的编程方式;了解中断响应、中断优先级、中断标志位复位等原理,掌握二级中断、中断嵌套的具体应用编程;了解定时器/计数器的工作原理,掌握计数器初值计算方法,定时/计数中断服务的编程开发。