基于51单片机时钟设计
(仿真+程序)
功能介绍
具体功能:
1.采用数码管显示时间时-分-秒;
2.可按键设置时分秒、清零;
3.可按键切换至显示年月日;
4.年月日和初始时间可在程序中修改;
演示视频:
基于51单片机时钟设计—数码管显示
添加图片注释,不超过 140 字(可选)
程序
#include<reg52.h> //52单片机头文件
/***微信公众号:木子单片机********/
uchar wei=0X01,duan=0;
void smg()//数码管扫描送显示函数
{
P1=wei; // 选择要点亮的数码管是哪一个
P2=table[val[duan]]; // 给改数码管送显示数据
wei=_crol_(wei,1); // 移位,为点亮下一个数码管做准备
duan++;
if(duan>7) duan=0;
}
void delay(uint z) //1毫秒
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void time0init() // 定时器0初始化函数
{
TMOD=0x01; //设置定时器0为工作方式1(M1M0为01)
TH0=(65536-2000)/256; //装初值12M晶振定时2ms数为2000
TL0=(65536-2000)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
}
uint num=0,keytime=0,time; //时间更新 1s,20ms扫描一次按键, 控制修改项闪烁
void time0() interrupt 1
{
TH0=(65536-2000)/256; //装初值12M晶振定时2ms数为2000
TL0=(65536-2000)%256;
keytime++; //20ms扫描一次按键
time++; //控制修改项闪烁
num++; //时间更新 1s
smg();
}
uchar key()
{
static uchar kzt=0; //推动循环,每次执行一次case
uchar sb=NOT_Break; //任意赋值避开条件
switch(kzt) //按顺序依次执行
{
//------------case 0:------------//
case 0: //第一步
P3=0xff; //P3做读入状态时,应该要先写1的,才能正确读入数据
//按照课本原文 作输入时:必须先将1写入口锁存器,使场效应管截止,该口线同时被内部上拉电阻拉成高电平,同时也能被外部输入源拉成低电平,即外部输入1时,该口线为高电平,输入0时,该口线为低电平
if(P3!=0xff) //如果有按键按下
{
kzt=1; //向下执行第二步
return NOT_Break; //返回一个无关的值,用来跳出此次循环
}
break; //如果没有按键按下,直接跳出
//------------case 1:------------//
case 1: //第二步
P3=0xff; //P3做读入状态时,应该要先写1的,才能正确读入数据
//按照课本原文 作输入时:必须先将1写入口锁存器,使场效应管截止,该口线同时被内部上拉电阻拉成高电平,同时也能被外部输入源拉成低电平,即外部输入1时,该口线为高电平,输入0时,该口线为低电平
if(P3!=0xff) //有按键按下
{
switch(P3)
{
case 0xfe: //第一个按键按下
sb=0;
break; //直接跳出
case 0xfd: //第二个按键按下
sb=1;
break; //直接跳出
case 0xfb: //第三个按键按下
sb=2;
break; //直接跳出
case 0xf7: //第四个按键按下
sb=3;
break; //直接跳出
}
kzt=2; //如果无按键按下 向下执行第三步
return sb; //返回sb的值
}
else //如果无按键按下 回到第一步
{
kzt=0;
return NOT_Break; //返回一个无关的值,用来跳出此次循环
}
break;
//------------case 2:------------//
case 2: //第三步
P3=0xff; //P3做读入状态时,应该要先写1的,才能正确读入数据
//按照课本原文 作输入时:必须先将1写入口锁存器,使场效应管截止,该口线同时被内部上拉电阻拉成高电平,同时也能被外部输入源拉成低电平,即外部输入1时,该口线为高电平,输入0时,该口线为低电平
if(P3==0xff) //如果没有按键按下
{
kzt=0; //如果无按键按下 回到第一步
return NOT_Break;
}
break; //如果有按键按下 直接跳出
}
return NOT_Break;
}
void main()
{
char shi=23,fen=59,miao=55,qh=0; //初始化时分秒 状态标志位(0:正常,1:改变秒钟,2:改变分钟,3:改变时钟)
char flag=0; //标志位---年月日&&时分秒
char keycode=NOT_Break; //键值
P0=0xff;
P1=0xff;
P2=0xff;
P3=0xff;
delay(10); //保证上面三条指令顺利完成
time0init(); //定时器0初始化函数
while(1)
{
if(key0==0) //清零按键按下
{
shi=0;fen=0;miao=0; //时分秒清零
qh=0; //开始显示
}
if(key1==0) //年月日&&时分秒按键按下
{
while(!key1); //等待放开按键
if(flag==0) flag=1; //年月日&&时分秒
else flag=0;
qh=0; //开始显示
}
if(keytime>9) //2ms*10=20ms
{
keytime=0; //计数清零
keycode=key(); //检测是否有按键按下
}
//---时间更新---//
if((num>=500)&&(qh==0)) //时间更新 2ms*500=1s
{
num=0; //计数清零
miao++; //秒数加1
if(miao>59) //如果miao等于60
{
miao=0; //miao赋值为0
fen++; //分钟加1
if(fen>59) //如果fen等于60
{
fen=0; //fen赋值为0
shi++; //小时加1
if(shi>23) shi=0;//如果shi等于24 shi赋值为0
}
}
}
///
//---按键检测---///
///---第一个按键按下---///
if(keycode==0) //第一个按键按下 选择
{
qh++; //状态标志位(0:正常,1:改变秒钟,2:改变分钟,3:改变时钟)
if(qh>3) qh=1; //如果qh等于4,qh赋值为1
keycode=NOT_Break; //任意赋值避开条件
}
///---第二个按键按下---///
if(keycode==1) //第二个按键按下 加
{
if(qh==1)
{
miao++;
if(miao>59) miao=0;//如果miao等于60 miao赋值为0
}
if(qh==2)
{
fen++;
if(fen>59) fen=0; //如果fen等于60 fen赋值为0
}
if(qh==3)
{
shi++;
if(shi>23)shi=0; //如果shi等于24 shi赋值为0
}
keycode=NOT_Break; //任意赋值避开条件
}
///---第三个按键按下---///
if(keycode==2) //第三个按键按下 减
{
if(qh==1)
{
miao--;
if(miao<0) miao=59;//如果miao等于-1 miao赋值为59
}
if(qh==2)
{
fen--;
if(fen<0) fen=59; //如果fen等于-1 fen赋值为59
}
if(qh==3)
{
shi--;
if(shi<0) shi=23; //如果shi等于-1 shi赋值为23
}
keycode=NOT_Break; //任意赋值避开条件
}
///---第四个按键按下---///
if(keycode==3) //第四个按键按下 确定
{
qh=0;
keycode=NOT_Break; //任意赋值避开条件
}
///
///---显示函数---///
switch(qh) //按键按下后立即显示
{
//正常显示
case 0:
if(flag==1) //显示日期 年月日
{
val[0]=2;
val[1]=0;
val[2]=2;
val[3]=4;
val[4]=0;
val[5]=1;
val[6]=0;
val[7]=1;
}
else
{
val[0]=shi/10; //显示时间 时分秒
val[1]=shi%10;
val[2]=10;
val[3]=fen/10;
val[4]=fen%10;
if(fen==30) { BEEP=0;delay(200);BEEP=1; }
else if(fen==0) { BEEP=0;delay(100);BEEP=1;}
val[5]=10;
val[6]=miao/10;
val[7]=miao%10;
}
break;
//秒钟修改后显示 其中秒钟部分在闪烁
case 1:
if(time<250) //2ms*250=0.5s
{
val[0]=shi/10;
val[1]=shi%10;
val[3]=fen/10;
val[4]=fen%10;
val[6]=miao/10;
val[7]=miao%10;
}
else if(time<500) //2ms*500=1s
{
val[0]=shi/10;
val[1]=shi%10;
val[3]=fen/10;
val[4]=fen%10;
val[6]=11;
val[7]=11;
}
else if(time>500) //2ms*500=1s
{
time=0;
}
break;
//分钟修改后显示 其中分钟部分在闪烁
case 2:
if(time<250)
{
val[0]=shi/10;
val[1]=shi%10;
val[3]=fen/10;
val[4]=fen%10;
val[6]=miao/10;
val[7]=miao%10;
}
else if(time<500)
{
val[0]=shi/10;
val[1]=shi%10;
val[3]=11;
val[4]=11;
val[6]=miao/10;
val[7]=miao%10;
}
else if(time>500)
{
time=0;
}
break;
//时钟修改后显示 其中时钟部分在闪烁
case 3:
if(time<250)
{
val[0]=shi/10;
val[1]=shi%10;
val[3]=fen/10;
val[4]=fen%10;
val[6]=miao/10;
val[7]=miao%10;
}
else if(time<500)
{
val[0]=11;
val[1]=11;
val[3]=fen/10;
val[4]=fen%10;
val[6]=miao/10;
val[7]=miao%10;
}
else if(time>500)
{
time=0;
}
break;
}
///
}
}
硬件设计
使用元器件:
单片机:AT89C52;
(注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)
添加图片注释,不超过 140 字(可选)
设计资料
01仿真图
本设计使用proteus7.8和proteus8.9两个版本设计!具体如图!
添加图片注释,不超过 140 字(可选)
02程序
本设计使用软件keil5版本编程设计!具体如图!
添加图片注释,不超过 140 字(可选)
03设计资料
资料获取请关注同名公众号,全部资料包括程序(含注释)、仿真源文件等。具体内容如下,全网最全!!
添加图片注释,不超过 140 字(可选)
资料获取请观看前面演示视频!
点赞分享一起学习成长。