一. 基本原理
软时钟是利用单片机的定时器/计数器来实现的,它的处理过程如下:首先设定单片机
内部的一个定时器/计数器工作于定时方式,对机器周期技术形成基准时间爱你如(10ms),
然后用另一个定时器/计数器或软件技术的方法对基准时间计数形成秒(对 10ms 计数 100
次),秒计 60 次形成分,分计 60 次形成小时,小时计 24 次则满一天。最后通过数码管把它
们的内容在相应位置显示出来即可。
数码管显示可以采用静态显示方法或动态显示方法。静态显示方法需要数据锁存器等硬
件,接口复杂,时钟显示一般用 6 个或 8 个数码管。由于没有其他的复杂的任务处理,而且
现实的时钟信息随时都可能改变,因而,一般采用动态显示方法。动态显示方法,线路相对
简单,但须动态扫描,扫描频率要大于人眼视觉暂留率(每秒 24 次),信息看起来才稳定。
译码方式可分为软件译码和硬件译码。软件译码通过译码程序差得显示信息的字段码;硬件
译码通过硬件译码器得到显示信息的字段码,实际中通常采用软件译码。
在具体处理时,定时器/计数器采用中断方式工作,对时钟的形成在中断服务程序中实
现。在主程序中只需对定时器/计数器初始化、调用显示子程序和控制子程序。另外,为了
使用方便,设计了简单的按键,可以通过按键实现时,分的调整,这样在主程序中就加入了
键盘设置子程序。
二. 硬件电路设计
本系统的硬件电路主要包括单片机芯片、数码管显示、按键开关等电路,它的硬件电路
如下图所示,单片机采用应用广泛的 STC 89c52,系统时钟采用 12mhz 的晶振,8 个数码管
显示,小时与分钟、分钟与秒钟之间用短横线间隔,采用供阳极七段式数码管,P0 口为段
选码输出端,通过排阻与数码管相连,P2 口为位选码输出端,分别通过三极管驱动与数码
管阳极相连,三极管能对 P2 口输出信号取反。按键开关设定了 3 个,通过 P1 口相连。
电子时钟电路原理图如下:
三.软件程序设计
1. 流程图
1.1 主程序流程图:
主程序执行如下流程图,主程序先对显示单元和定时器/计数器初始化,然后重复调用
数码管显示模块和案件处理模块,当有键按下时,则转入相应的功能程序。
开始
显示单元清 0
T0,T1 设为 16 位技术模式
允许 T0 中断
调用显示子程序
否
按下键否?
是
进入功能程序
1.2 定时器/计数器 T0 中断服务程序流程图:
定时器/计数器 T0 用于时间计时。选择方式 1,重复定时,定时时间为 50ms,定时时
间到则中断,在中断服务程序中用一个计数器对 50ms 技术,计 20 次则对秒单元加 1,秒单
元加到 60 则对分单元加 1,同时秒单元清 0;分单元加到 60 则对时单元加 1,同时分单元
清 0;时单元加到 24 则对时单元清 0,标志一天时间计满。在对各单元计数的同时,把他们
的至放到存储单元的指定位置。定时器/计数器 T0 中断服务程序的流程图如下图所示:
开始
现场保护,重置初值启动下一个 50ms
50ms 计数器加 1
否
50ms 计数器=20?
是
秒单元加 1,50ms 计数器清 0
否
否
否
秒单元=60?
是
分单元加 1,秒单元清 0
分单元=60?
是
时单元加 1,分单元清 0
时单元=24?
是
时单元清 0
中断返回
2. 源程序
C 语言程序:
//采用 8 位 LED 软件译码动态显示程序
//使用 STC 89C52 单片机,12MHZ 晶振,P0 输出字段,P2 输出位选码
//用共阳 LED 数码管,key0 为调试定位选择器,key1 为加 1 键,key2 为减 1 键
#include “reg52.h”
#define char unsigned char
char code
dis_7[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0xb2,0xf8,0x80,0x90,0xff,0xbf};
//共阳极 LED 数码管“0~9”,“灭”的字段码
char code scan_con[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf };
//位选择码
char date dis[8]={0x00,0x00,0x0b,0x00, 0x00,0x00};
//显示缓冲区,时,分,秒初始为 0,的编码
int date timedate[3]={0x00,0x00,0x00};
//分别为秒,分和小时的值
char date ms50=0x00; int con=0x00,con1=0x00,con2=0x00;
sbit key0=p1^0;
sbit key1=p1^1;
sbit key2=p1^2;
//1ms 延时函数
delay1ms(int t)
{
int i,j;
for (i=0;i
keyscan()
{
EA=0;
if(key0==0)
{
delay1ms(10);
while (key0==0);
1==0con++;TR0=0;ET0=0;
if(con>=3)
{con=0;TR0=1;ET0=1;}
}
if (con!=0)
{
if (key1==0)
{
delay1ms(10);
while (key1==0);
timedate[con]++;
if (con==2) con1=24;else con1=60;
if (timedate [con]>=con1)
{timedate[con]=0;}
}
}
if (con!=0)
{
if (key2==0)
{
delay1ms(10);
while (key2==0);
timedate[con]--;
if (con==2) con2=23;else con2=59;
if (timedate [con]<=0)
{timedate[con]=con2;}
}
}
EA=1;
}
//数码管显示函数
void
scan()
{
char k;
dis [0]=timedate[0]%10;dis [1]=timedate[0]/10;
dis [2]=timedate[1]%10;dis [3]=timedate[1]/10;
dis [4]=timedate[2]%10;dis [5]=timedate[2]/10;
for (k=0;k<8;k++)
{
P0=dis_7[dis[k]];P2=scan_con[k];delay1ms(1);P2=0xff;
}
}
//主函数
main()
{
TH0=0x3c; TL0==xb0;
TMOD=0x01; ET0=1; EA=1;
while (1)
{
scan();
keyscan();
}
}