一、关于单片机定时器做的电子钟
通常用单片机内部定时器做的电子钟也很难做到十分准确(24小时误差几秒算是把程序计算的不错了),这是因为外接晶振频率的细小波动和参杂中断处理杂陈指令会难以计算周全造成的。所以大多采用了DS1302+备用电池,或是更好的DS12887等,这样电路就麻烦一些,主要是开发时间增长,成本就会提高。
选择硬件要看在什么场合用,比如您不需要做专业的万年历,或是应用到某个时间段,比如数分钟、数个小时的计时或倒计时,那么用单片机的定时器做是能满足要求的。
二、用矩阵按键做时钟调整
1.大家看到大部分学习板有4*4矩阵键盘,部分还有几个独立的键盘。其实矩阵键盘同样可以当作独立键盘来用的,如下图,在程序中把P1.7设为0,那么P1.~P1.3不就成了4个独立的按键吗?
(把XY850或XY900板的矩阵键盘设成独立按键)
2.显示部分,这里就不列出了(本站XY850或XY900板为例),大家可在这个栏目找可看到其它例子有XY900的数码管显示电路。
(用8位数码管显示时钟的可视性比6位数码管好看多了)
三、电子钟8位数码管参考程序(C51)
/***************************************************************
* 程序名称:51单片机数码管电子钟+定时闹钟 晶振:11.0592
* 实验对象:XY850/XY900型单片机学习开发板
* 单 片 机:AT89S52或STC89C52 闹钟时间:7:10分(程序自定义)
* 本板另外有<<不怕掉电的时钟程序+1602>>做实验
* 更多的资料和程序共享登陆:http://www.mcusy.cn
****************************************************************/
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit duan =P3^3;//段码控制位
sbit weis =P3^4;//位码控制位
//--------------------------------------------------------------
//这里我们把矩阵键盘改为普通按键开关用
sbit key3=P1^3;//时调整
sbit key2=P1^2;//分调整
sbit key1=P1^1;//秒调整
sbit key0=P1^0;//全部清零键
sbit bit0=P1^7;//把bit0一直设为0
sbit LED0=P2^7;//秒闪烁灯(可不要)
sbit bell=P3^7;//小喇叭
//--------------------------------------------------------------
uchar code tab1[]=
{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0xBF,0x7F};//共阳0~9/-段码/点
uchar code tab2[]={0x02,0x01,0x08,0x04,0x20,0x10,0x80,0x40};//0~7依次位码表
uchar sec, min, hour, count; //定义秒,分,时,中断计数
//--------------------------------------------------------------
void delay(uint z) //延时子函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//--------------------------------------------------------------
void init() //初始化T0函数
{
TMOD=0x01; //T0-方式1-16位计时器
TH0=0x4C; //49.9MS
TL0=0x5C; //晶振:11.0592计算
EA=1; //开总中断
ET0=1;//允许T0中断
TR0=1;//启动T0中断
}
//--------------------------------------------------------------
void timer0() interrupt 1 //定时器函数
{
TH0=0x4C; //49.9MS
TL0=0x5C; //以晶振11.0592调整计算
count++;LED0=1; //50毫秒中断一次count便加1
if(count>=20) //中断了20次?(20*49.9=998毫秒/就是1秒)
{count=0;sec++;LED0=0;} //计数清零/秒加1
if(sec==60) //满了60秒?
{sec=0;min++;} //秒清零/分加1
if(min==60) //满了60分钟?
{min=0;hour++;} //分清零/时加1
if(hour==24) //满了24小时?
{hour=0;} //时清零
}
//--------------------------------------------------------------
void display() //数码管显示子函数
{
uchar s ;
for(s=0;s<=10;s++)//扫描//控制显示刷新和按键速度
{
duan=1; P0=tab1[hour/10]; duan=0;
weis=1; P0=tab2[0]; weis=0; delay(2);//时十位
duan=1; P0=tab1[hour%10]; duan=0;
weis=1; P0=tab2[1]; weis=0; delay(2);//时个位
duan=1; P0=tab1[11]; duan=0;
weis=1; P0=tab2[2]; weis=0; delay(2);//横
duan=1; P0=tab1[min/10]; duan=0;
weis=1; P0=tab2[3]; weis=0; delay(2);//分十位
duan=1; P0=tab1[min%10]; duan=0;
weis=1; P0=tab2[4]; weis=0; delay(2);//分个位
duan=1; P0=tab1[11]; duan=0;
weis=1; P0=tab2[5]; weis=0; delay(2);//横
duan=1; P0=tab1[sec/10]; duan=0;
weis=1; P0=tab2[6]; weis=0; delay(2);//秒十位
duan=1; P0=tab1[sec%10]; duan=0;
weis=1; P0=tab2[7]; weis=0; delay(2);//秒个位
}
}
//--------------------------------------------------------------
void alarm_clock() //闹钟子函数-变频发声
{
uint i,j,y,m;
if(hour==7)//时到了7点?
{
if(min>=11){m=0;} //分大于或等于11就把m清零,若不成立向下执行
if(min==10)//到了10分?
{
if(m<15)
{
do{ //循环-变频
m++; display();
for(i=0;i<1000;i++)
{bell=~bell;for(j=0;j<50;j++);} //取反/低
for(y=0;y<2000;y++)
{bell=~bell;for(j=0;j<25;j++);} //取反/高
}
while(m<15); //闹15次结束
}
}
}
}
//--------------------------------------------------------------
void key() //按键调整子函数
{
bit0=0; //使用矩阵的列4个按钮
//-----------------------------
if(key1==0) //秒调整(矩阵1号键)
{ delay(10);
if(key1==0){sec++;if(sec==60) sec=0;}//调到了60?
}
if(key2==0) //分调整(矩阵4号键)
{ delay(10);
if(key2==0){min++; if(min==60) min=0;} //调到了60?
}
if(key3==0) //时调整(矩阵7号键)
{ delay(10);
if(key3==0){hour++;if(hour==24) hour=0;} //调到了24?
}
if(key0==0) //全部归清零按(矩阵*号键)
{ delay(10);
if(key0==0){sec = min = hour = 0;} //秒/分/时清零
}
}
//--------------------------------------------------------------
void main() //主函数
{
init(); //T0初始化
while(1) //死循环
{
key(); //调整函数
alarm_clock();//闹钟函数
display(); //显示函数
}
}