纯软件打造的时钟
1、程序特点:针对“计时”和“动态扫描”分别用到了两个定时器。本来键盘扫描也想用定时器做防抖来着,结果干扰动态扫描,只好作罢。
2、实现功能:计时,闹钟。调节时间和闹钟时,对应的显示位会闪烁。有闹钟开关界面。按调节键可以止闹。
计时精度没有仔细调校,存在一定的误差。
/***********************************************************************************
名称:纯软件时钟
版本:V1.0
作者:zjzj007
时间:2008/10/28
联系方式:zjzj1973@sina.com
1、程序特点:针对“计时”和“动态扫描”分别用到了两个定时器。本来键盘扫描也想用定时器做防抖来着,结果干扰动态扫描,只好作罢。
2、实现功能:计时,闹钟。调节时间和闹钟时,对应的位会闪烁。有闹钟开关界面。按调节键可以止闹。
3、时间设置说明:
按K1键1次进入设置分钟界面,按k4键时间加,按K2键时间减
按K1键2次进入设置小时界面,按k4键时间加,按K2键时间减
闹钟设置说明:
按K1键3次进入闹钟分钟设置,按k4键时间加,按K2键时间减
按K1键4次进入闹钟小时设置,按k4键时间加,按K2键时间减
按K1键5次进入闹钟开关设置,按k4键闹钟开,按K2键闹钟关
************************************************************************************/
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
uchar reg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x88,0xbf,0xc0,0xc8,0x8e};//段码
// 0 ,1, 2, 3, 4, 5, 6, 7, 8, 9, 隐码, A,-, O, N, F //
uchar dis[8]={0,0,0,0}; //显示位缓冲
//uchar set[4];
uchar t=0,shi=0,fen=0,miao=0,key=0,num,n,j,z,zz,i;
uchar fen_a=30,shi_a=06,a_stop=0;
sbit beep=P1^7; //蜂鸣器引脚
uchar a_flag; //闹钟标志位
void delay(uint t) //延时函数
{
while(t--)
{
for(j=0;j<125;j++)
{}
}
}
void ring() //震铃函数
{
{if(t>10)
{
beep=!beep;
for(z=0;z<50;z++)
{}
}
}
}
void set_alarm(uchar n) //闹钟时间设置
{
switch(n)
{
case 3: //K1键按下3次
{
if(key==0x24) //k4键按下
{
fen_a++; //分钟加1
if(fen_a==60)fen_a=0;
}
else if(key==0x28)//k2键按下
{
if(fen_a==0)fen_a=60;
fen_a--; //分钟减1
}
}
break;
case 4:
{
if(key==0x24)
{
shi_a++; //小时加1
if(shi_a==24)shi_a=0;
}
else if(key==0x28)
{
shi_a--; //小时减1
if(shi_a==0)shi_a=24;
}
}
break;
}//switch
}
void timer2(void) interrupt 5 //时钟计时中断(TIMER2)
{
TF2=0; //清中断标志位
t++; //到50MS就加1
if(t==20) //1S
{
t=0;
miao++; //时间进位
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
}
}
}
}
}
void display(uchar i) //动态扫描函数
{
switch (i) // 四位数码管轮流显示
{
case 0:
P1=0xfe;
break;
case 1:
P1=0xfd;
break;
case 2:
P1=0xfb;
break;
case 3:
P1=0xf7;
break;
}
dis[2]=fen/10; // 分钟的十位送显
dis[3]=fen%10; //分钟的个位送显
dis[0]=shi/10; //小时的十位送显
dis[1]=shi%10; //小时的个位送显
if(n==0) //无键按下
{
if((i==1)&&(t<10))//小时的个位数码管的小数点半秒闪动1次,作为秒显示
{
P0=(reg[dis[i]])&0x7f; //加小数点
}
else
{
P0=reg[dis[i]];
}
}
else if(n==1)//K1按一次
{
if((i==2)|(i==3)) //分钟位闪动
{
if(t<10)P0=(reg[dis[i]]);
else {P0=reg[10];}
}
else P0=(reg[dis[i]]);
}
else if(n==2)//K1按二次
{
if((i==1)|(i==0)) //小时位闪动
{
if(t<10)P0=(reg[dis[i]]);
else {P0=reg[10];}
}
else P0=(reg[dis[i]]);
}
else if(n==3)//K1按三次
{
dis[2]=fen_a/10; //闹钟小时,分钟送显
dis[3]=fen_a%10;
dis[0]=shi_a/10;
dis[1]=shi_a%10;
if((i==2)|(i==3))
{
if(t<10)//分钟位隔0.5秒闪烁一次
{
if(i==3)P0=(reg[dis[i]]&0x7f);//在分钟的个位显示小数点(小数点定义为闹钟标识)
else P0=reg[dis[i]];
}
else
{
if(i==3)P0=(reg[10]&0x7f);
else P0=reg[10];
}
}
else P0=(reg[dis[i]]);
}
else if(n==4)//K1按四次
{
dis[2]=fen_a/10; //闹钟小时,分钟送显
dis[3]=fen_a%10;
dis[0]=shi_a/10;
dis[1]=shi_a%10;
if((i==1)|(i==0)) //闹钟小时位闪动
{
if(t<10)P0=(reg[dis[i]]);
else {P0=reg[10];}
}
else
{
if(i==3)P0=(reg[dis[i]]&0x7f);//在分钟的个位显示小数点
else P0=reg[dis[i]];
}
}
else if(n==5) //闹钟开闭状态显示, 默认值关A-OFF
{
if(!num) // 按下3键,即NUM=0,显示A-OFF 按下2键,NUM=1,显示A-ON
{
a_flag=0; //闹钟标志位,a_flag=0为off
if(i<2)P0=reg[i+11];
else
{
if(t<10)
{
if(i==2)P0=reg[i+11];
else P0=reg[i+12]; //在各位显示F
}
else P0=reg[10];
}
}
else
{
a_flag=1;//闹钟标志位,a_flag=1为on
if(i<2)P0=reg[i+11]; // //闹钟开状态显示,A-ON
else
{
if(t<10)
P0=reg[i+11];
else P0=reg[10];
}
}
}
}
void timer1() interrupt 3 //动态扫描中断 每位40ms
{
uchar i;
TH1=(65536-40000)/256;
TL1=(65536-40000)%256;
display(i); //调用显示函数
i++;
if(i>3)i=0; // 位
}
uchar keyscan() //键扫
{ uchar scancode,tempcode;
P2=0xf0;
if((P2&0xf0)!=0xf0)
{
delay(20);
if((P2&0xf0)!=0xf0)
{
scancode=0xfe;
while((scancode&0x10)!=0)
{ P2=scancode;
if((P2&0xf0)!=0xf0)
{
tempcode=((P2&0xf0)|0x0f);
while((P2&0xf0)!=0xf0);
return ((~scancode)+(~tempcode));
}
else scancode=((scancode<<1)|0x01);
}//while
} //if
}//if
else return 0 ;
}
void setjia() //进入时间调整子程序,进行加1操作
{
if(n==1)
{
fen++;
if(fen==60)fen=0;
}
else if(n==2)
{ shi++;
if(shi==24)shi=0;
}
}
void setjian() //进入时间调整子程序,进行减1操作
{
if(n==1)
{
if(fen==0)fen=60;
fen--;
}
else if(n==2)
{
if(shi==0)shi=24;
shi--;
}
}
void main()
{
TMOD=0x01; //定时器1工作在计时方式1
T2CON=0; //定时器2工作在自加载模式
// TH0=(65536-60000)/256;
// TL0=(65536-60000)%256;
RCAP2H=(65536-45900)/256; //定时器2初值
RCAP2L=(65536-45900)%256;
TH1=(65536-40000)/256; //定时器1初值
TL1=(65536-40000)%256;
IP=0x20; //设定TIMER2优先级最高
ET1=1; //开计时器1中断
ET2=1; //开计时器2中断
EA=1; //开总中断
TR1=1; //开始计时
TR2=1; //开始计时
while(1) //大循环
{
key=keyscan(); //把键值读出来
switch(key) //键值识别语句
{
case 0x18: //k1键,为功能设置键
n++; //有键按下就加1
if(n>5)n=0; //按键超过5次,就清零
break;
case 0x24: //k4--加号键
num=1; //供开关闹钟显示的标志位 A-ON
setjia(); //进入时间调整子程序,进行加1操作
break;
case 0x28: //k2--减号键
num=0; //供开关闹钟显示的标志位 A-OFF
setjian(); //进入时间调整子程序,进行减1操作
break;
/* case 0x14://k3
num=4;
break;
case 0x21://k5
num=5;
break;
case 0x22://k6
num=6;
break;
case 0x11://k7
num=7;
break;
case 0x12://k8
num=8;
break;*/
}
if((n==3)|(n==4)) //当K1键值累计到3或4次后,系统进入闹钟设置状态,分别设置闹钟的分或时
{
set_alarm(n); //调用闹钟设置
}
if(shi_a==shi) //比较小时位
{
if(fen_a==fen) //比较分钟位
{
if(a_flag&&!a_stop)ring(); //检测闹钟标志位和止闹按键
if(key){a_stop++;} // 有按键按下,A_STOP就加1
}
}
else a_stop=0; //退出时按键值清零
}//while
}





