实验报告 电子时钟实验
- 一、实验要求:
- 二、实验结果
- 三、实验思路
- (一)模块整理
- (二)流程图绘制
- (三)C51编程
- 四、实验总结
- (一)未完成的部分
- (二)待优化的部分
一、实验要求:
利用定时计数器,设计一个电子时钟,使用前面使用过的显示子程序。从左到右依次显示时分秒。有两种方法实现,一种是在中断程序中计数,产生时分秒计数,送显示缓冲区。另一种是中断程序每一秒清除一个位变量,而主程序通过监视位变量的变化来知道每秒的时间。
进而要求:
①加入时间调整程序,使用两个或三个按钮,调节当前的时间。类似平常使用的电子表。可以让正在调整的位闪烁显示。
②可以加入一个闹钟钟设置,当所定的时间到时,产生断续的蜂鸣声。可以加入日历的功能。
二、实验结果
数码管显示24小时制电子时钟;
矩阵按键S11时钟界面、S15倒计时界面、S12时间设置界面;
S12按下循环调整时、分、秒,处于时间设置界面时L8闪烁;
L1亮调整时、L2亮调整分、L3亮调整秒;
S13按下数值加1,S17按下数值减1;
倒计时结束后蜂鸣器间隔鸣叫;
S16按下一键清零时分秒
三、实验思路
(一)模块整理
(二)流程图绘制
(三)C51编程
#include <reg51.h>
sbit L8 = P1^7;
sbit LED = P2^5;
sbit BUZZ = P2^3;
sbit DULA = P2^6;
sbit WELA = P2^7;
unsigned char num[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,
0x7D,0x07,0x7F,0x6F,};
unsigned char second,minute,hour = 0;
void delay(unsigned int t)
{
while(t--);
}
void Init_Timer()
{
TMOD = 0x21;
TH0 = 0x3C; //50ms=0.05s
TL0 = 0xB0;
TR0 = 1;
ET0 = 1;
TH1 = 0x00;
TL1 = 0x38;
TR1 = 0;
ET1 = 1;
EA = 1;
}
unsigned char flag = 0;
unsigned char count = 0;
void Service_Timer0() interrupt 1 //T0中断服务函数
{
TH0 = 0x3C;
TL0 = 0xB0;
count++;
if(count == 20) //20 * 50ms = 1s
{
count = 0;
if(flag == 0) //正计时状态
{
second++;
if(second == 60)
{
second = 0;
minute++;
if(minute == 60)
{
minute = 0;
hour++;
if(hour == 24)
{
hour = 0;
}
}
}
}
if(flag == 1) //倒计时状态
{
if(second == 0)
{
if(minute == 0)
{
if(hour == 0)
{
TR0 = 0; //终止倒计时
TR1 = 1;
flag = 3; //蜂鸣器标志位
}
else{
hour--;
minute = 59;
}
}
else{
minute--;
second = 59;
}
}
else
second--;
}
}
}
unsigned int count2 = 0;
void Service_Timer1() interrupt 3 //T1中断服务函数
{
count2++;
if(count2 == 1500) //0.2ms * 1500 = 0.2s
{
L8 = ~L8;
count2 = 0;
if(flag == 3)
{
BUZZ = ~BUZZ;
}
}
}
void s_Display(unsigned char sec)
{
DULA=1;
P0=num[sec%10];
DULA=0;
WELA=1;
P0=0XDF; //POS_6
WELA=0;
delay(150);
DULA=1;
P0=num[sec/10];
DULA=0;
WELA=1;
P0=0XEF; //POS_5
WELA=0;
delay(150);
}
void m_Display(unsigned char min)
{
DULA=1;
P0=num[min%10];
DULA=0;
WELA=1;
P0=0XF7; //POS_4
WELA=0;
delay(150);
DULA=1;
P0=num[min/10];
DULA=0;
WELA=1;
P0=0XFB; //POS_3
WELA=0;
delay(150);
}
void h_Display(unsigned char hor)
{
DULA=1;
P0=num[hor%10];
DULA=0;
WELA=1;
P0=0XFD; //POS_2
WELA=0;
delay(150);
DULA=1;
P0=num[hor/10];
DULA=0;
WELA=1;
P0=0XFE; //POS_1
WELA=0;
delay(150);
}
void SMG_Display()
{
s_Display(second);
m_Display(minute);
h_Display(hour);
}
sbit R1 = P3^0;
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;
sbit C1 = P3^4;
sbit C2 = P3^5;
sbit C3 = P3^6;
sbit C4 = P3^7;
unsigned char stat = 0;
void Key_Scan()
{
C2 = 0;
C1 = C3 = C4 = 1;
if(R2 == 0) //S11按下,暂停/启动正计时界面
{
flag = 0;
SMG_Display();
TR1 = 0; //不属于调整时间状态
LED = 1;
P1 = 0xff;
LED = 0;
if(R2 == 0)
{
TR0 = ~TR0;
}
while(R2 == 0)
{
SMG_Display();
}
}
if(R3 == 0) //S16按下,暂停/启动倒计时界面
{
flag = 1;
SMG_Display();
TR1 = 0; //不属于调整时间状态
LED = 1;
P1 = 0xff;
LED = 0;
if(R3 == 0)
{
TR0 = ~TR0;
}
while(R3 == 0)
{
SMG_Display();
}
}
C3 = 0;
C1 = C2 = C4 = 1;
if(R2 == 0) //S12按下,调整时间界面按键
{
LED = 1;
SMG_Display();
if(R2 == 0)
{
if(TR0 == 0) //必须在停止界面下调整时间
{
TR1 = 1;
switch(stat)
{
case 0: stat = 1; P1 = 0xFE; break; //s位调整
case 1: stat = 2; P1 = 0xFD; break; //m位调整
case 2: stat = 0; P1 = 0xFB; break; //h位调整
}
}
}
while(R2 == 0)
{
SMG_Display();
}
}
if(R3 == 0) //S15按下,复位按键
{
SMG_Display();
LED = 1;
P1 = 0xff;
LED = 0;
if(R3 == 0)
{
TR0 = 0;
TR1 = 0;
LED = 0;
second = minute = hour = 0;
}
while(R3 == 0)
{
SMG_Display();
}
}
C4 = 0;
C1 = C2 = C3 = 1;
if(R2 == 0) //S13按下,加1
{
SMG_Display();
if(TR1 == 1)
{
if(R2 == 0)
{
switch(stat)
{
case 1 :
second++;
if(second == 60)
second = 0;
break;
case 2 :
minute++;
if(minute == 60)
minute = 0;
break;
case 0 :
hour++;
if(hour == 24)
hour = 0;
break;
}
}
}
while(R2 == 0)
{
SMG_Display();
}
}
if(R3 == 0) //S17按下,减1
{
SMG_Display();
if(TR1 == 1)
{
if(R3 == 0)
{
switch(stat)
{
case 1 :
if(second == 0) //先判断,后减1
second = 59;
else
second--;
break;
case 2 :
if(minute == 0)
minute = 59;
else
minute--;
break;
case 0 :
if(hour == 0)
hour = 23;
else
hour--;
break;
}
}
}
while(R3 == 0)
{
SMG_Display();
}
}
}
void main(){
second = 54;
minute = 59;
hour = 23;
LED = 0;
Init_Timer();
while(1)
{
SMG_Display();
Key_Scan();
}
}
四、实验总结
(一)未完成的部分
1.让正在调整的位数码管闪烁显示。
从TX-1C的原理图中可以看到其位选和段选都需要通过P0口赋值,所以分别用了两个74HC573锁存器来分别锁存两个值,使两者互不干扰。所以想要实现位闪烁,一方面应该要选中相应的位选,在该位上实现闪烁功能;另一方面利用定时器写一个延时程序,赋当前要显示的值持续一段时间,再赋熄灭数码管显示的值持续一段时间,两个赋值之间循环,间隔点亮实现闪烁功能。
2.实现日历功能。实际上也是一个数码管显示界面,需要对年、月、日进行设定。方法一,通过定时器对日期进行累加,但是稍显麻烦,且中断需要快进快出,所以这个方法不太理想;方法二,通过时钟的24小时计时对日进行累加,再到月、年的累加,用此方法实现较为可行。
(二)待优化的部分
1.进一步实现从倒计时界面切换到时钟界面时,不影响时钟持续的运行。此实验中,时钟和倒计器用了同一个定时器,所以没能够实现两者之间互不影响的功能。后续可以用两个定时器将二者功能分开,利用switch-case状态机实现按键控制时钟和倒计时之间循环切换,且不干扰时钟的持续运行。
2.进一步实现温度显示界面。TX-1C实验板上有DS18B20温度模块,可以编写相关程序,实现时钟、闹钟、温度相互切换显示的功能