/**/ //
// 制作一个定时器,2位显示秒,2位显示分,用4个调节按钮调节
// 四个调节按钮为key0, key1, key2, key3分别为P3.2, P3.3, P3.4, P3.5
// 数码管用P0显示a,b,c,d,e,f,g,分别对应P0.0, P0.1, P0.2, P0.3, P0.4, P0.5, P0.6, P0.7
// 数码管用P2.0, P2.1, P2.2, P2.3控制,P2.0控制最左面的LED(即最高位)

/**/ //
#include < reg52.h >
#define char unsigned char

char code dis_7[ 11 ] = ... {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF} ; // 共阳LED

char data scan_con[ 4 ] = ... {0xF7, 0xFB, 0xFD, 0xFE } ; // 列扫描控制字

char data timedata[ 4 ] = ... {0x00, 0x00, 0x00, 0x00} ; // 记时单位初值

char data dis[ 6 ] = ... {0x00, 0x00, 0x00, 0x00, 0x0a, 0x00} ; // 显示数据单元
char data con1s = 0x00 , con04s = 0x00 , con = 0x00 ;
sbit key0 = P3 ^ 2 ;
sbit key1 = P3 ^ 3 ;
sbit key2 = P3 ^ 4 ;
sbit key3 = P3 ^ 5 ;

/**/ //
void clearmen( void );
void scan( void );
void keyscan( void );
void delay1ms( int );

/**/ //
int main( void )

... {
clearmen();
while(1)

...{
scan();
keyscan();
}
return 0;
}

/**/ //
void clearmen( void )

... {
int i;
for(i = 0; i < 4; i++)

...{
dis[i] = timedata[i];
}
TH0 = 0x3C;//50ms定时初值
TL0 = 0xB0;
TH1 = 0x3C;//50MS定时初值
TL1 = 0xB0;
TMOD = 0x11;//T0和T1由TRi控制开启/停止,对内部振荡器12分频计数,为16位计数
ET0 = 1;
ET1 = 1;
TR1 = 1;
TR0 = 1;
EA = 1;//打开中断总开关
}

/**/ //
void scan( void )

... {
char k;
for(k = 0; k < 4; k++)

...{
P0 = dis_7[dis[k]];//dis[0] = 0x00; dis_7[0] = 0xC0;
//dis[1] = 0x00; dis_7[0] = 0xC0;。。。。。。
P2 = scan_con[k]; //scan_con[0] = 0xFE; scan_con[1] = 0xFD; scan_con[2] = 0xFB;
delay1ms(1);
P2 = 0xFF;
}
}

/**/ //
void delay1ms( int t)

... {
int i, j;
for(i = 0; i < t; i++)
for(j = 0; j < 120; j++)
;
}

/**/ //
void keyscan( void )

... {
if(key0 == 0)

...{
TR0 = 0;//关定时器T0,用于1s计时
ET0 = 0;
delay1ms(10);
while(key0 == 0);
con++;
if(con >= 4)
con = 0;
}
if(key1 == 0)

...{
delay1ms(10);
while(key1 == 0);
timedata[con]++;
if(con == 0||con == 2)
if(timedata[con] >= 10)
timedata[con] = 0;
else ;
else if(con == 1||con == 3)
if(timedata[con] >= 6)
timedata[con] = 0;
else ;
else ;
dis[con] = timedata[con];
dis[4] = 0x0A;
}

if(key2 == 0)

...{
delay1ms(10);
while(key2 == 0);
timedata[con]--;
if(con == 0||con == 2)
if(timedata[con] == 0)
timedata[con] = 0x09;
else ;
else if(con == 1||con == 3)
if(timedata[con] == 0)
timedata[con] = 0x05;
else ;
else ;
dis[con] = timedata[con];
//dis[4] = 0x0A;
}
if(key3 == 0)

...{
TR0 = 1;//关定时器T0,用于1s计时
ET0 = 1;
delay1ms(10);
while(key3 == 0);
}
}

/**/ //
void time_intt0( void ) interrupt 1

... {
ET0 = 0;
TR0 = 0;
TH0 = 0x3C;//50MS
TL0 = 0xB0;
TR0 = 1;
con1s++;
if(con1s == 20)//1S

...{
con1s = 0x00;
timedata[0]++;
if(timedata[0] >= 10)

...{
timedata[0] = 0;
timedata[1]++;
if(timedata[1] >= 6)

...{
timedata[1] = 0;
timedata[2]++;
if(timedata[2] >= 10)

...{
timedata[2] = 0;
timedata[3]++;
if(timedata[3] == 6)
if(timedata[2] == 0)

...{
timedata[2] = 0;
timedata[3] = 0;
}
}
}
}
dis[0] = timedata[0];
dis[1] = timedata[1];
dis[2] = timedata[2];
dis[3] = timedata[3];
}
ET0 = 1;
}

/**/ //
void time_intt1( void ) interrupt 3

... {
ET1 = 0;
TR1 = 0;
TH1 = 0x3C;//50MS
TL1 = 0xB0;
TR1 = 1;
con04s++;
if(con04s == 9)//0.45S

...{
con04s = 0x00;
dis[5] = dis[con];
dis[con] = dis[4];
dis[4] = dis[5];
}
ET1 = 1;
}

/**/ //
这段代码不是我写的,出处是《51系列单片机——设计实例》(北航出版社)第八章,我略微做了一些改动。
这段代码通过T0控制秒的增加和分的增加,T1控制数字闪烁。
我们开始分析,程序开始的第一个函数是main
int main( void )

... {
clearmen();
while(1)

...{
scan();
keyscan();
}
return 0;
}
main函数调用的第一个函数是clearmen函数
void clearmen( void )

... {
int i;
for(i = 0; i < 4; i++)

...{
dis[i] = timedata[i];
}
TH0 = 0x3C;//50ms定时初值
TL0 = 0xB0;
TH1 = 0x3C;//50MS定时初值
TL1 = 0xB0;
TMOD = 0x11;//T0和T1由TRi控制开启/停止,对内部振荡器12分频计数,为16位计数
ET0 = 1;
ET1 = 1;
TR1 = 1;
TR0 = 1;
EA = 1;//打开中断总开关
}
首先是一个for循环是用timedata数组的前4位给dis数组的4个元素初始化,我们看前面对timedata数组的初始化,如下,我们发现这个初始化让dis[i] = 0 (i = 0, 1, 2, 3)
char code dis_7[ 11 ] = ... {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF} ; // 共阳LED

char data scan_con[ 4 ] = ... {0xF7, 0xFB, 0xFD, 0xFE } ; // 列扫描控制字

char data timedata[ 4 ] = ... {0x00, 0x00, 0x00, 0x00} ; // 记时单位初值

char data dis[ 6 ] = ... {0x00, 0x00, 0x00, 0x00, 0x0a, 0x00} ; // 显示数据单元
如下代码设置计数器工作方式和初值
TH0 = 0x3C ; // 50ms定时初值
TL0 = 0xB0 ;
TH1 = 0x3C ; // 50MS定时初值
TL1 = 0xB0 ;
TMOD = 0x11 ; // T0和T1由TRi控制开启/停止,对内部振荡器12分频计数,为16位计数
如下代码开启计数器和中断
ET0 = 1 ; // 开启T0中断
ET1 = 1 ; // 开启T1中断
TR1 = 1 ; // 开启T1计数器
TR0 = 1 ; // 开启T0计数器
EA = 1 ; // 打开中断总开关
clearmen函数执行结束,进入while死循环,接下来的函数是scan函数,scan函数中用一个for循环来给P0和P2赋值(注意:这里可不是初始化了,因为这个死循环一直不停执行,P0和P2的值是变化的。)我们看第一次P0和P2的值是多少?
k = 0时,dis[0] = 0; dis_7[dis[k]] = 0xC0; P0 = 0xC0;scan_con[0] = 0xF7; P2 = 0xF7;延时
k = 1时,dis[1] = 0; dis_7[dis[k]] = 0xC0; P0 = 0xC0;scan_con[1] = 0xFB; P2 = 0xFB;延时
k = 2时,dis[2] = 0; dis_7[dis[k]] = 0xC0; P0 = 0xC0;scan_con[2] = 0xFD; P2 = 0xFD;延时
k = 3时,dis[3] = 0; dis_7[dis[k]] = 0xC0; P0 = 0xC0;scan_con[3] = 0xFE; P2 = 0xFE;延时
while(1)是一个死循环,所以一开始没有超过1S时显示为四个0。
void scan( void )

... {
char k;
for(k = 0; k < 4; k++)

...{
P0 = dis_7[dis[k]];//dis[0] = 0x00; dis_7[0] = 0xC0;
//dis[1] = 0x00; dis_7[0] = 0xC0;。。。。。。
P2 = scan_con[k]; //scan_con[0] = 0xFE; scan_con[1] = 0xFD; scan_con[2] = 0xFB;
delay1ms(1);
P2 = 0xFF;
}
}
假设我们暂时不碰那几个调节键,那么keyscan函数暂时是无效的,我们留作后面分析。
死循环经过约50MS时,T0和T1出现了一个中断,我们先分析T1中断。如下图:关闭T1中断,关闭T1计时器,重新赋初值,开启T1计时器,con04s加1,中断9次以后(即0.45S)闪烁一次,并且让con04s =0x00(注:通过交换dis[con]和dis[4]的值,此时con = 0, 因为dis[4]的值为0x0A,而while(1)死循环中的scan函数P0 = dis_7[dis[k]],而dis_7[0x0A] = 0xFF为全灭。即)
void time_intt1( void ) interrupt 3

... {
ET1 = 0;
TR1 = 0;
TH1 = 0x3C;//50MS
TL1 = 0xB0;
TR1 = 1;
con04s++;
if(con04s == 9)//0.45S

...{
con04s = 0x00;
dis[5] = dis[con];
dis[con] = dis[4];
dis[4] = dis[5];
}
ET1 = 1;
}