当前位置:网站首页>基于51单片机的电子时钟设计
基于51单片机的电子时钟设计
2022-07-05 16:40:00 【少年、潜行】
基于51单片机的电子时钟设计
0 功能介绍
1、从DS1302中读取时间显示
2、一共4个按键,按键1按下进入修改时间模式,再按下切换修改的时间变量,这个时候第2和3个按键就是修改时间变量的按键,修改完毕后,点击按键4确认修改
3、不是修改模式下,按下按键2,可以切换时间和日期的显示
4、修改模式下,对应修改的时间变量会闪烁
1 软件平台及代码开源
仿真软件:Proteus 8.9
代码编写:Keil5
百度网盘链接:
链接:https://pan.baidu.com/s/1RP_8MkZIqHt7WFPc6na3sQ
提取码:y2fn
–来自百度网盘超级会员V4的分享
Gitee链接:
51单片机项目学习: 这个仓库拿来保存一些51单片机项目学习 (gitee.com)
2 仿真硬件选型
DS1302获取当前时间,8位共阴极数码管,74HC138作位选,74HC573作段选,4个按键。
3 代码编写
3.1 整体设计思路
从DS1302中读取出当前时间显示,在修改时间的时候,先把当前时间存入一篇缓存中,然后修改缓存中的数据,等到修改完毕后,再把缓存中的数据写入DS1302中。
3.2 软件代码设计
3.2.1 数码管显示
数码管的显示将放置在一个5ms的定时器中实现,每隔5ms,换一个显示的位次,通过74HC138的编码来达到显示位的改变。segCode就是存放的数码管段码,缓存,segBuff的实际值为多少,就是谁的段码,如果值为10,我设置的segCode为0x00,即为不显示。
void SegShow()
{
static u8 segSelectCount = 0;//位选变量
segSelectCount ++;
if(segSelectCount > 7)
segSelectCount = 0;
SEG = 0x00;//消隐
switch (segSelectCount)
{
case 0: HCC = 0;HCB = 0;HCA = 0;SEG = segCode[segBuff[0]];break;
case 1: HCC = 0;HCB = 0;HCA = 1;SEG = segCode[segBuff[1]];break;
case 2: HCC = 0;HCB = 1;HCA = 0;SEG = 0x40 ;break;
case 3: HCC = 0;HCB = 1;HCA = 1;SEG = segCode[segBuff[2]];break;
case 4: HCC = 1;HCB = 0;HCA = 0;SEG = segCode[segBuff[3]];break;
case 5: HCC = 1;HCB = 0;HCA = 1;SEG = 0x40 ;break;
case 6: HCC = 1;HCB = 1;HCA = 0;SEG = segCode[segBuff[4]];break;
case 7: HCC = 1;HCB = 1;HCA = 1;SEG = segCode[segBuff[5]];break;
default:HCC = 0;HCB = 0;HCA = 0;SEG = segCode[segBuff[0]];break;
}
}
3.2.2 DS1302中数据的处理
往DS1302寄存器中写值
void ds1302write(u8 addre,u8 dat)
{
u8 i;
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
for (i=0;i<8;i++)
{
IO=addre&0x01;
addre>>=1;
SCK=1;
_nop_();
SCK=0;
_nop_();
}
for (i=0;i<8;i++)
{
IO=dat&0x01;
dat>>=1;
SCK=1;
_nop_();
SCK=0;
_nop_();
}
RST=0;
}
从DS1302中读值
u8 ds1302read(u8 addre)
{
u8 i,dat1,dat;
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
for (i=0;i<8;i++)
{
IO=addre&0x01;
addre>>=1;
SCK=1;
_nop_();
SCK=0;
_nop_();
}
_nop_();
for (i=0;i<8;i++)
{
dat1=IO;
dat=(dat>>1)|(dat1<<7);
SCK=1;
_nop_();
SCK=0;
_nop_();
}
RST=0;
_nop_();
SCK=1;
_nop_();
IO=1;
_nop_();
IO=0;
_nop_();
return dat;
}
DS1302的初始化,如果在文件开头定义的FIRST_WRITE的值为1,那么在初始化的时候就会往DS1302中写入time[]中设置的时间,在第一次写入可以将这块代码打开,后面就可以关闭。
void ds1302init()
{
#if FIRST_WRITE == 1
u8 i;
ds1302write(0x8e,0x00);
for (i=0;i<7;i++)
{
ds1302write(writeaddre[i],time[i]);
}
ds1302write(0x8e,0x80);
#endif
}
DS1302读取时间,将数据从DS1302寄存器中读取出来,然后再做一个BCD码转10进制的转换。
void ds1302readtime()
{
u8 i;
for (i=0;i<7;i++)
{
time[i]=ds1302read(readaddre[i]);
}
second = (time[0]/16)*10+(time[0]&0x0f);
minute = (time[1]/16)*10+(time[1]&0x0f);
hour = (time[2]/16)*10+(time[2]&0x0f);
day = (time[3]/16)*10+(time[3]&0x0f);
month = (time[4]/16)*10+(time[4]&0x0f);
week = (time[5]/16)*10+(time[5]&0x0f);
year = (time[6]/16)*10+(time[6]&0x0f);
}
DS1302写入时间,将要写入的变量先做10进制转BCD码,然后写入相应的寄存器。
void ds1302writetime()
{
u8 i;
ds1302write(0x8e,0x00);
time[0] = (((secondTemp/10)<<4) + (secondTemp%10));
time[1] = (((minuteTemp/10)<<4) + (minuteTemp%10));
time[2] = (((hourTemp/10)<<4) + (hourTemp%10));
time[3] = (((dayTemp/10)<<4) + (dayTemp%10));
time[4] = (((monthTemp/10)<<4) + (monthTemp%10));
time[5] = (((weekTemp/10)<<4) + (weekTemp%10));
time[6] = (((yearTemp/10)<<4) + (yearTemp%10));
for (i=0;i<7;i++)
{
ds1302write(writeaddre[i],time[i]);
}
ds1302write(0x8e,0x80);
}
3.2.3 按键扫描
按键扫描参考正点原子的写法,但是我的延时不是按照他的用delay延时,而是使用的定时器延时,这样的好处是延时时不占用CPU资源。
void KeyScan(u8 mode)
{
static int keyCount = 0;
static int keyState = 0;
if(mode == 1) keyState=0;
if (keyState == 0 && (KEY0 == 0||KEY1 == 0||KEY2 == 0||KEY3 == 0))
{
keyCount++;
if(keyCount>2)
{
keyState = 1;
keyCount=0;
if(KEY0 == 0) isKey0 = 1;
else if(KEY1 == 0) isKey1 = 1;
else if(KEY2 == 0) isKey2 = 1;
else if(KEY3 == 0) isKey3 = 1;
}
} else if (KEY0 == 1 && KEY1 == 1 && KEY2 == 1 && KEY3 == 1)
{
keyState = 0;
}
}
3.2.4 根据显示模式修改显示变量
根据显示状态变量,修改现在的显示变量
void SegBuffChange()
{
if(showMode == 0)
{
segBuff[5] = second%10;
segBuff[4] = second/10;
segBuff[3] = minute%10;
segBuff[2] = minute/10;
segBuff[1] = hour%10;
segBuff[0] = hour/10;
}else if(showMode == 1)
{
segBuff[5] = day%10;
segBuff[4] = day/10;
segBuff[3] = month%10;
segBuff[2] = month/10;
segBuff[1] = year%10;
segBuff[0] = year/10;
}else if(showMode == 2)
{
segBuff[5] = secondTemp%10;
segBuff[4] = secondTemp/10;
segBuff[3] = minuteTemp%10;
segBuff[2] = minuteTemp/10;
segBuff[1] = hourTemp%10;
segBuff[0] = hourTemp/10;
}else if(showMode == 3)
{
segBuff[5] = dayTemp%10;
segBuff[4] = dayTemp/10;
segBuff[3] = monthTemp%10;
segBuff[2] = monthTemp/10;
segBuff[1] = yearTemp%10;
segBuff[0] = yearTemp/10;
}
}
3.2.5 闪烁函数
在按键修改模式下,将闪烁状态值置1,由于该函数放置在segBuff修改的后面,所以在实际显示前,会以这里改变的为实际显示,就可以达到一个闪烁的效果。
void dataBlink()
{
static u8 blinkCount = 0;
static bit blinkState = 0;
if(changeOrNormalState == 1)//在按键修改模式下
{
blinkCount++;
if(blinkCount == 80)//每隔80*5 闪烁状态值转换
{
blinkState = !blinkState;
blinkCount = 0;
}
}else
{
blinkState = 0;
}
if(blinkState == 1)//假如闪烁状态值为1,该位次变量数码管不显示,我在seg.c中有定义,10就是不显示
{
segBuff[(2-changeCount%3)*2+1] = 10;
segBuff[(2-changeCount%3)*2] = 10;
}
}
3.2.6 按键执行函数
按键按下后的执行函数,可以看代码注释
void ClockChangeFunction()
{
if(isKey0 == 1)
{
isKey0 = 0;
if(changeCount == 0 && changeOrNormalState == 0)//修改的位选为0,即为秒,同时显示状态为正常显示状态下
{
changeOrNormalState = 1;//显示状态改为修改时间模式
DataTempGet();//获取修改前的时间变量值
showMode = 2;//显示模式为显示修改时间下的时分秒
}else if(changeOrNormalState == 1)//假如为显示模式
{
changeCount++;//按键按下位次++
if(changeCount > 5)
changeCount = 0;
if(changeCount > 2)//时分秒是0、1、2,大于2就要换成年月日显示
showMode = 3;//显示模式为显示修改时间下的年月日
else
showMode = 2;
}
}else if(isKey1 == 1)
{
isKey1 = 0;
if(changeOrNormalState == 1)//显示状态为修改时间模式
{
dataAdd();//对应位次时间变量增加
}else //正常显示模式
{
if(showMode == 0)//切换时间和日期的显示
showMode = 1;
else if(showMode == 1)
showMode = 0;
}
}else if(isKey2 == 1)
{
isKey2 = 0;
if(changeOrNormalState == 1)//和增加一样
{
dataSub();
}
}else if(isKey3 == 1)
{
isKey3 = 0;
if(changeOrNormalState == 1)//在修改模式下按下
{
changeOrNormalState = 0;//变为正常显示模式
ds1302writetime();//写入修改后的时间
showMode = 0;//显示模式为时分秒
changeCount = 0;//修改位次归零
}
}
}
3.2.7 时间变量增加函数
这部分代码,在按键执行函数中执行,但是由于 这一部分太多,所以将其封装函数,主要是拿来改变时间变量。主要是有个平闰年的处理,其他都比较正常。
void dataAdd()
{
if(changeCount == 0)
{
secondTemp ++;
if(secondTemp > 59)
secondTemp = 0;
}else if(changeCount == 1)
{
minuteTemp ++;
if(minuteTemp > 59)
minuteTemp = 0;
}else if(changeCount == 2)
{
hourTemp ++;
if(hourTemp > 23)
hourTemp = 0;
}else if(changeCount == 3)
{
dayTemp ++;
if(monthTemp == 1 || monthTemp == 3 || monthTemp == 5 || monthTemp == 7 || monthTemp == 8 || monthTemp == 10 || monthTemp == 12)
{
if(dayTemp > 31)
dayTemp = 1;
}else if(monthTemp == 3 || monthTemp == 6 || monthTemp == 9 || monthTemp == 11)
{
if(dayTemp > 30)
dayTemp = 1;
}else if(monthTemp == 2)
{
if((2000+year)%400==0)
{
if(dayTemp > 29)
dayTemp = 1;
}
else
{
if((2000+year)%4==0&&(2000+year)%100!=0)
{
if(dayTemp > 29)
dayTemp = 1;
}else
{
if(dayTemp > 28)
dayTemp = 1;
}
}
}
}else if(changeCount == 4)
{
monthTemp ++;
if(monthTemp > 12)
monthTemp = 1;
}else if(changeCount == 5)
{
yearTemp ++;
if(yearTemp > 99)
yearTemp = 0;
}
}
4 总结
这个设计功能比较简单,也许有些地方也有一些小BUG,但是我目前没有发现,如果有人发现,欢迎交流。
边栏推荐
猜你喜欢
URP下Alpha从Gamma空间到Linner空间转换(二)——多Alpha贴图叠加
干货!半监督预训练对话模型 SPACE
Learnopongl notes (I)
Application of threshold homomorphic encryption in privacy Computing: Interpretation
Get ready for the pre-season card game MotoGP ignition champions!
Embedded -arm (bare board development) -2
PHP talent recruitment system development source code recruitment website source code secondary development
Games101 notes (II)
China Radio and television officially launched 5g services, and China Mobile quickly launched free services to retain users
Embedded -arm (bare board development) -1
随机推荐
深耕5G,芯讯通持续推动5G应用百花齐放
深潜Kotlin协程(二十一):Flow 生命周期函数
编译libssh2报错找不到openssl
C# TCP如何限制单个客户端的访问流量
thinkphp模板的使用
The survey shows that the failure rate of traditional data security tools in the face of blackmail software attacks is as high as 60%
winedt常用快捷键 修改快捷键latex编译按钮
It is forbidden to copy content JS code on the website page
Embedded-c Language-1
Embedded-c Language-2
Data verification before and after JSON to map -- custom UDF
Jarvis OJ shell traffic analysis
国内首家 EMQ 加入亚马逊云科技「初创加速-全球合作伙伴网络计划」
【7.7直播预告】《SaaS云原生应用典型架构》大咖讲师教你轻松构建云原生SaaS化应用,难题一一击破,更有华为周边好礼等你领!
The first EMQ in China joined Amazon cloud technology's "startup acceleration - global partner network program"
American chips are no longer proud, and Chinese chips have successfully won the first place in emerging fields
[729. My schedule I]
高数 | 旋转体体积计算方法汇总、二重积分计算旋转体体积
Browser rendering principle and rearrangement and redrawing
【Web攻防】WAF检测技术图谱