中断与定时计数
1.参考课件中例7-1,在Proteus和普中单片机板上分别完成采用定时计数器控制LED灯每隔1s周期性亮灭的实验(即上次实验任务相同的任务)。要求Keil仿真中的虚拟逻辑仪对LED管脚进行波形观察,测量真实的周期数,并与上次采用软件循环进行周期定时的精度进行对比,看哪一种方式更加精准。
keil:时间为1.008212s
sdcc:时间为1s15ms157us
在设计时间合理的情况下,keil的时间精度明显是高于sdcc的。
2.参考课件中例7-2,采用计数器中断,实现 按4次按钮开关后,P1口的8只LED闪烁不停。
代码如下:
#include<reg51.h>
#define uchar unsigned char
void Delay(unsigned int i){
uchar j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main(){
TMOD=0x50;
TH1=0xff;
TL1=0xfc;
EA=1;
ET1=1;
TR1=1;
while(1);
}
void int1_isr(void) interrupt 3{
uchar m;
for(;;){
P1=0xff;
Delay(500);
P1=0;
Delay(500);
}
}
在proteus上绘制如下电路图,点击P3.5所连接的按钮四次便能得到如下效果图:
3.一般来说,中断函数中要尽量避免使用执行时间较长(耗时)的代码,以避免中断服务影响到主程序代码的执行效率。但是在上面外部中断的实验中,中断函数采用了软件延时函数去控制LED亮灭的间隔周期。这是一种不好的编程。请你思考,换一种更合理的方式,不在中断函数使用延时循环,实现同样的功能。(提示:可以在main函数中写好几种亮灯模式代码和对应的模式标志位,按键中断发生后,中断服务程序只改变模式标志位,不做其他处理;由主程序根据模式标志,选择不同的亮灯模式)
代码如下:
#include<reg51.h>
#define uchar unsigned char
int a=0;
void Delay(unsigned int i){
uchar j;
for(;i>0;i--)
for(j=0;j<125;j++)
{;}
}
void main(){
for(;;){
EA=1;
EX0=1;
EX1=1;
IT0=1;
IT1=1;
PX0=0;
PX1=1;
if(a==0){
for(;;){
P1=0x0f;
Delay(500);
P1=0xf0;
Delay(500);
if(a==1)break;
}}
if(a==1){
for(;;){
P1=0xff;
Delay(500);
P1=0;
Delay(500);
if(a==0)break;
}}
}
}
void int2_isr(void) interrupt 0 {
if(a==1)a=0;
else a=1;
}
效果图如下:
点击P3.2连接的按钮触发中断函数后,效果图如下:
再次触发按钮,亮灯又会回到一半亮一半灭的状态。
4.总结:
学习使人快乐。