当前位置:网站首页>基于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,但是我目前没有发现,如果有人发现,欢迎交流。
边栏推荐
- PHP talent recruitment system development source code recruitment website source code secondary development
- npm安装
- Get ready for the pre-season card game MotoGP ignition champions!
- ECU简介
- 项目引入jar从私服Nexus 拉去遇到的一个问题
- Embedded-c Language-2
- If you can't afford a real cat, you can use code to suck cats -unity particles to draw cats
- 7.Scala类
- [729. My Schedule i]
- Allusions of King Xuan of Qi Dynasty
猜你喜欢
Jarvis OJ simple network management protocol
WR | 西湖大学鞠峰组揭示微塑料污染对人工湿地菌群与脱氮功能的影响
IDC报告:腾讯云数据库稳居关系型数据库市场TOP 2!
American chips are no longer proud, and Chinese chips have successfully won the first place in emerging fields
Summary of PHP pseudo protocol of cisp-pte
First day of learning C language
Practical example of propeller easydl: automatic scratch recognition of industrial parts
PHP人才招聘系统开发 源代码 招聘网站源码二次开发
Games101 notes (I)
PHP talent recruitment system development source code recruitment website source code secondary development
随机推荐
C how TCP restricts the access traffic of a single client
High number | summary of calculation methods of volume of rotating body, double integral calculation of volume of rotating body
Scratch colorful candied haws Electronic Society graphical programming scratch grade examination level 3 true questions and answers analysis June 2022
项目引入jar从私服Nexus 拉去遇到的一个问题
張平安:加快雲上數字創新,共建產業智慧生態
干货!半监督预训练对话模型 SPACE
CMake教程Step1(基本起点)
WSL2.0安装
The survey shows that the failure rate of traditional data security tools in the face of blackmail software attacks is as high as 60%
深潜Kotlin协程(二十一):Flow 生命周期函数
浏览器渲染原理以及重排与重绘
Is it safe to open an account for digging wealth stocks? How is it safe to open a stock account?
时间戳strtotime前一天或后一天的日期
tf. sequence_ Mask function explanation case
Thoughtworks 全球CTO:按需求构建架构,过度工程只会“劳民伤财”
Learnopongl notes (I)
[Jianzhi offer] 63 Maximum profit of stock
Timestamp strtotime the day before or after the date
npm安装
精准防疫有“利器”| 芯讯通助力数字哨兵护航复市