- 主要实现:能够在数码管上显示时,分,秒;
设置闹钟(蜂鸣器);
利用51单片机的定时器功能进行计时。
说明:在程序的编写过程中无法实现减一的操作,没按一次减一的键总是不止一次地减一。这个问题尚未解决,详情见附录的程序部分。希望各路大神看到了能指点一二,在此不胜感激。 - 系统仿真图:
- 程序如下:
#include<reg51.h> //头文件
#define uchar unsigned char //宏定义 之后用uchar代替unsigned char 这里指无符号字符
#define uint unsigned int //宏定义 同上 无符号整数
sbit beep=P0^0;
uchar dat[]={0,0,10,0,0,10,2,1}; //定义初始化显示时间数组
uchar dat1[]={0,0,10,0,0,10,0,0}; //定义初始化闹钟设定值数组,本程序中闹钟只设定到分
uchar dis_bit[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //数码管位选
uchar code SEG7[11]={0xC0,/*0*/0xF9,/*1*/0xA4,/*2*/0xB0,/*3*/0x99,/*4*/0x92,/*5*/0x82,/*6*/0xF8,/*7*/
0x80,/*8*/0x90,/*9*/0xBF,/*-*/}; //共阴极数码管字段码
uchar key_code[]= { /*列检测时按键按下时key的可能值,通过对这些值的判断也就可以知道具体按键的位置*/
0x7e,0x7d,0x7b,0x77, /*当列中的最高位P2.7为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为0,1,2,3*/
0xbe,0xbd,0xbb,0xb7, /*当列中的P2.6为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为4,5,6,7*/
0xde,0xdd,0xdb,0xd7, /*当列中的P2.5为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为8,9,A,B*/
0xee,0xed,0xeb,0xe7 /*当列中的P2.4为0时,这一列四个按键按下时(即对应行值变为0)的key的值,对应的键值为C,D,E,F*/
};
uchar code ksp[4]={0x7f,0xbf,0xdf,0xef}; //确定列的前提下(分别给每列置零)进行行检测
uint tcount,t_beep;
uchar flag=0; //闹钟切换标志位,
uchar flag_beep=0; //蜂鸣器响标志位,=1表示蜂鸣器响
/*flag=0,设定闹钟;flag=1,显示正常时间*/
struct time{uint second;uint minute;uint hour;}time1; //定义名为time的结构体,变量名time1
uchar n,i,k;
void delay(n) //延时函数
{while(n--)
{
for(i=110;i>0;i--);
}
}
void display(void) //数字显示
{
if(flag==0) //显示正常时间
{
for(k=0;k<8;k++)
{
P3=dis_bit[k];
P2=SEG7[dat[k]]; //p2接数码管a-g,p3接数码管1-8,控制动态扫描输出
delay(5);
P3=0X00;
}
}
if(flag==1) //显示闹钟设定时间
{
for(k=0;k<8;k++)
{
P3=dis_bit[k];
P2=SEG7[dat1[k]]; //p2接数码管a-g,p3接数码管1-8,控制动态扫描输出
delay(5);
P3=0X00; //消影
}
}
}
uchar keypad_scan()
{
uchar key,temp=0;
P1=0xf0;
if(P1!=0xf0)
{
delay(10);
if(P1!=0xf0)
{
do{
for(i=0;i<4;i++) //检测四列,按键必定在这四列之中
{
P1=ksp[i]; //重新给P2口赋值,此时列已经确定了
if(P1!=ksp[i]) //某一行值变为0,P2口的值发生改变
{
delay(10); //消抖,按键抖动
key=P1;
if(key!=ksp[i]) //再次确认四行中有某行变为0
{
while(temp!=ksp[i])
{P1=ksp[i];temp=P1;display();}
return(key); //此时的key值既包含了行值信息又包含了列值信息。
}
}
}
}while(1);
}
}
}
uchar gotkey()
{
uchar temp;
temp=keypad_scan();
for(i=0;i<16;i++)
{
if(temp==key_code[i]) //查表确定键盘号
return(i);
}
}
void keyscan(void) //时间调整函数
{ uchar keynum;
keynum=gotkey();
EA=0; //中断开关。=0关中断
if(keynum==0) //开始设定闹钟时间
{
flag=1;
TR0=0;
}
if(keynum==1) //暂停功能触发,停止计时,便于调整时间
{
flag=0;
TR0=0;ET0=0; //ET0为定时器T0的中断控制位。=0禁止中断;TR0运行控制位,位于TCON内部,=1定时器可能工作
}
if(keynum==2)
{
if(flag==0) //时钟调整每次加1
{
dat[6]++;
if((dat[7]==2)&&(dat[6]>3))
{
dat[7]=0;
dat[6]=0;
}
if(dat[6]>9)
{
dat[6]=0;
dat[7]++;
if(dat[7]>2)
{
dat[7]=0;
}
}
}
if(flag==1) //闹钟时钟定时
{
dat1[6]++;
if((dat1[7]==2)&&(dat1[6]>3))
{
dat1[7]=0;
dat1[6]=0;
}
if(dat1[6]>9)
{
dat1[6]=0;
dat1[7]++;
if(dat1[7]>2)
{
dat1[7]=0;
}
}
}
}
if(keynum==3)
{
if(flag==0) //分钟调整每次加一
{
dat[3]++;
if(dat[3]>=9)
{
dat[4]++;
dat[3]=0;
if(dat[4]>5)
{
dat[4]=0;
}
}
}
if(flag==1) //闹钟分钟定时
{
dat1[3]++;
if(dat1[3]>9)
{
dat1[4]++;
dat1[3]=0;
if(dat1[4]>5)
{
dat1[4]=0;
}
}
}
}
if(keynum==4) //暂停结束,显示正常时间;正常情况按下时无影响
{
flag=0;
TR0=1;ET0=1;
}
if(keynum==5)
{
dat1[0]=0;
dat1[1]=0;
dat1[3]=0;
dat1[4]=0;
dat1[6]=0;
dat1[7]=0;
}
/* if(keynum==6)
{
if(flag==0) //时钟减一
{
if(dat[6]!=0)
{ dat[6]=dat[6]-1; }
else
{
if((dat[6]==0)&&(dat[7]!=0))
{
dat[7]=dat[7]-1;
dat[6]=9;
}
else
{
dat[6]=3;
dat[7]=2;
}
}
}
if(flag==1) //闹钟时钟减一
{
if(dat1[6]!=0)
dat1[6]=dat1[6]-1;
else
{
if((dat1[6]==0)&&(dat1[7]!=0))
{
dat1[7]=dat[7]-1;
dat1[6]=9;
}
else
{
dat1[6]=3;
dat1[7]=2;
}
}
}
}
if(keynum==7)
{
if(flag==0) //分钟减一
{
if(dat[3]!=0)
dat[3]=dat[3]-1;
else
{
if((dat[3]==0)&&(dat[4]!=0))
{
dat[4]=dat[4]-1;
dat[3]=9;
}
else
{
dat[3]=9;
dat[4]=5;
}
}
}
if(flag==1) //闹钟分钟减一
{
if(dat1[3]!=0)
dat1[3]=dat1[3]-1;
else
{
if((dat1[3]==0)&&(dat1[4]!=0))
{
dat1[4]=dat1[4]-1;
dat1[3]=9;
}
else
{
dat1[3]=9;
dat1[4]=5;
}
}
}
} */
EA=1; //中断开关,开中断
}
void init(void) //初始化函数
{
TMOD = 0x11; //TMOD特殊功能寄存器。控制两个定时器T1,T0,这里=00010001,T1T0处于工作方式1,定时开关仅由TR0控制
TH0 = 0xDB; //预置数计时,转为十进制56319,到65536结束。计时约10ms
TL0 =0xFF;
ET0=1;
TR0=1;
tcount=0;
EA = 1;
beep=1;
t_beep=0;
flag=0;
flag_beep=0;
}
void main()
{
init();
delay(10);
while(1) //只要条件为真就一直循环。
{
display();
keyscan();
if((dat[7]==dat1[7])&&(dat[6]==dat1[6])&&(dat[4]==dat1[4])&&(dat[3]==dat1[3])&&(dat[1]==dat1[1])&&(dat[0]==dat1[0]))
/*以上条件同时成立*/
{
flag_beep=1; //当正常时间到达设定时间时,将蜂鸣器响标志置为1
}
if(flag_beep)
{
if(t_beep%2==0)
{ beep=0;delay(5);}
beep=1;
}
}
}
void timer_0() interrupt 1
{
ET0=0; //T0禁止中断
TR0=0;
TH0 = 0xDB;
TL0 = 0xFF;
TR0=1;
tcount++;
if(tcount==100) //定时器是否满1秒
{
time1.second++;
t_beep++;
if(t_beep==60) //蜂鸣器持续响60s
{
flag_beep=0;
t_beep=0;
}
tcount=0;
dat[0]=(time1.second)%10;
dat[1]=(time1.second)/10; //显示秒
if(time1.second>59)
{
dat[0]=0;
dat[1]=0;
time1.second=0;
time1.minute++;
dat[3]=(time1.minute)%10;
dat[4]=(time1.minute)/10; //显示分
if(time1.minute>59)
{
dat[3]=0;
dat[4]=0;
time1.minute=0;
time1.hour++;
dat[6]=time1.hour%10; //显示小时
dat[7]=time1.hour/10;
if(time1.hour>23)
{
dat[6]=0;
dat[7]=0;
time1.hour=0;
}
}
}
}
ET0=1;
}
本设计相关工程文件和仿真文件见:基于数码管的简单时钟系统