51单片机案例(1) 您所在的位置:网站首页 实时钟表时间 51单片机案例(1)

51单片机案例(1)

2023-11-15 18:04| 来源: 网络整理| 查看: 265

目录 一、案例描述二、实时时钟程序实现2.1 LCD1602和DS1302功能实现2.2 宏定义相关地址2.3 写入时间2.4 读出时间 三、拓展——可调时钟程序实现3.1 按键功能3.2 显示时钟3.3 设置时钟3.4 调节时对应位闪烁 四、效果演示

一、案例描述

利用51单片机(STC89C52)和DS1302时钟芯片实现实时时钟功能,并在LCD1602液晶屏上显示年月日时分秒。 拓展:在此基础上实现,实现可调时钟的功能,可以通过按键实现时钟的年月日时分秒可以调节。

二、实时时钟程序实现 2.1 LCD1602和DS1302功能实现

LCD1602液晶屏的显示功能和DS1302时钟芯片的相应功能已经在上文中分别实现,详细内容可以查看本文最下方的参考。 本程序在DS1302中做了一下小改动,在DS1302_ReadByte写字节函数中,添加如下代码:

Command|=0x01;//写地址+1=读地址

众所周知,DS1302中读的地址(Read)是写的地址+1(这么表述可能不太准确,但意思是这样的),如下图所示,因此利用Command|=0x01;语句来使函数DS1302_WriteByte和DS1302_ReadByte输入的变量Command为同一地址,只是在函数内容进行重新修改,以此来提升代码的易用性。

在这里插入图片描述

2.2 宏定义相关地址

为表示方便,可以宏定义相关地址(秒、分、时、日、月、周、年、写保护):

//地址 #define DS1302_SECOND 0x80 #define DS1302_MINUTE 0x82 #define DS1302_HOUR 0x84 #define DS1302_DATE 0x86 #define DS1302_MONTH 0x88 #define DS1302_DAY 0x8A #define DS1302_YEAR 0x8C #define DS1302_WP 0x8E //写保护 2.3 写入时间

定义数组存储设置的年、月、日、时、分、秒:

unsigned char DS1302_Time[]={22,4,20,12,59,55,3};

将时间写入时钟芯片函数如下:

void DS1302_SetTime(){ DS1302_WriteByte(DS1302_WP,0x00);//解除芯片写保护 DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10); DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10); DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10); DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10); DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10); DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10); DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10); DS1302_WriteByte(DS1302_WP,0x80);//打开写保护 }

【注】:这里/10*16+%10表示将十进制转BCD码,关于BCD码的内容可以参考文章(文章)第六部分。

2.4 读出时间

将时间从时钟芯片读出函数代码如下:

void DS1302_ReadTime(){ unsigned char temp; temp=DS1302_ReadByte(DS1302_YEAR); DS1302_Time[0]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_MONTH); DS1302_Time[1]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_DATE); DS1302_Time[2]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_HOUR); DS1302_Time[3]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_MINUTE); DS1302_Time[4]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_SECOND); DS1302_Time[5]=temp/16*10+temp%16; temp=DS1302_ReadByte(DS1302_DAY); DS1302_Time[6]=temp/16*10+temp%16; } 三、拓展——可调时钟程序实现 3.1 按键功能

实现可调时钟需要四个按键,分别是:

调节/确定;移动;加一;减一;

由于郭天祥的51单片机的四个独立按键S2,S3,S4,S5和LCD1602存在引脚冲突(共用引脚P3),因此这里选择矩阵键盘第四列的四个按键S9,S13,S17,S21作为上述的四个按键。 代码如下:

//延时函数 void Delay(int xms) //@12.000MHz { unsigned char i, j; while(xms){ i = 2; j = 239; do{ while (--j); } while (--i); xms--; } } //矩阵键盘读取按键键码 unsigned char MatrixKey(){ unsigned char KeyNumber=0; P3=0xff; P3_7=0; //检测S9被按下 if(P3_0==0){Delay(5);while(P3_0==0);Delay(5);KeyNumber=1;} //检测S13被按下 if(P3_1==0){Delay(5);while(P3_1==0);Delay(5);KeyNumber=2;} //检测S17被按下 if(P3_2==0){Delay(5);while(P3_2==0);Delay(5);KeyNumber=3;} //检测S21被按下 if(P3_3==0){Delay(5);while(P3_3==0);Delay(5);KeyNumber=4;} return KeyNumber; }

【注】:如果你的独立按键与LCD1602不冲突,也可以根据你的单片机板子进行选择,单片机按键引脚进行自行调整,以你的板子为准,独立按键代码如下:

/** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */ unsigned char Key() { unsigned char KeyNumber=0; P3=0xff; if(P3_4==0){Delay(5);while(P3_4==0);Delay(5);KeyNumber=1;} if(P3_5==0){Delay(5);while(P3_5==0);Delay(5);KeyNumber=2;} if(P3_6==0){Delay(5);while(P3_6==0);Delay(5);KeyNumber=3;} if(P3_7==0){Delay(5);while(P3_7==0);Delay(5);KeyNumber=4;} return KeyNumber; } 3.2 显示时钟

显示时钟函数代码如下:

//显示时钟 void TimeShow(){ DS1302_ReadTime(); LCD_ShowNum(1,1,DS1302_Time[0],2); LCD_ShowNum(1,4,DS1302_Time[1],2); LCD_ShowNum(1,7,DS1302_Time[2],2); LCD_ShowNum(2,1,DS1302_Time[3],2); LCD_ShowNum(2,4,DS1302_Time[4],2); LCD_ShowNum(2,7,DS1302_Time[5],2); } 3.3 设置时钟

设置时钟函数代码如下:

//设置时钟 void TimeSet(){ if(KeyNum==2){ TimeSetSelect++; TimeSetSelect%=6;//相当于if(TimeSetSelect>5)TimeSetSelect=0; } //+ if(KeyNum==3) { DS1302_Time[TimeSetSelect]++; ...//年月日时分秒越界判断 } if(KeyNum==4) { DS1302_Time[TimeSetSelect]--; ...//年月日时分秒越界判断 }

如果第二个按键按下,时钟设置选择位TimeSetSelect,当TimeSetSelect超过5(年、月、日、时、分、秒)时,清零重新开始选择。 年月日时分秒越界判断由于代码量较大,这里不再展示,代码可到本文最后获取。

3.4 调节时对应位闪烁

对应位闪烁需要用到定时器,基本思路是:定义一个变量FlashFlag,实现定时1010翻转。 初始化定时器:

//定时器初始化 void Timer0Init() //1毫秒@12.000MHz { TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 //中断 ET0=1; EA=1; PT0=0; }

定时器中断:

unsigned int T0Count; //中断 void Timer0_Rountine() interrupt 1 { TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 T0Count++; if(T0Count>=500){ //每隔500ms取反 FlashFlag=!FlashFlag; } }

最后在设置时钟函数TimeSet()中加入闪烁判断相关语句,如果时钟设置选择位TimeSetSelect在某位上而且闪烁标志位FlashFlag为1则显示,显示500ms后FlashFlag为0,此时熄灭,这样就实现了闪烁功能,相关代码如下:

//闪烁判断 if(TimeSetSelect==0 && FlashFlag==1){ LCD_ShowString(1,1," "); } else{LCD_ShowNum(1,1,DS1302_Time[0],2);} if(TimeSetSelect==1 && FlashFlag==1){ LCD_ShowString(1,4," "); } else{LCD_ShowNum(1,4,DS1302_Time[1],2);} if(TimeSetSelect==2 && FlashFlag==1){ LCD_ShowString(1,7," "); } else{LCD_ShowNum(1,7,DS1302_Time[2],2);} if(TimeSetSelect==3 && FlashFlag==1){ LCD_ShowString(2,1," "); } else{LCD_ShowNum(2,1,DS1302_Time[3],2);} if(TimeSetSelect==4 && FlashFlag==1){ LCD_ShowString(2,4," "); } else{LCD_ShowNum(2,4,DS1302_Time[4],2);} if(TimeSetSelect==5 && FlashFlag==1){ LCD_ShowString(2,7," "); } else{LCD_ShowNum(2,7,DS1302_Time[5],2);} 四、效果演示

完整效果如下:

51单片机案例之利用DS1302实现实时时钟和可调时钟的功能

这里介绍一下我的接线,由于郭天祥51单片机板子没有DS1302时钟芯片而我又需要用到,因此这里花两块钱买了一个DS1302,将DS1302的CLK连接P2.6,DAT连接P2.4,RST连接P2.5,如下图所示。 在这里插入图片描述

如果没有看懂,完整代码可以参考:https://download.csdn.net/download/didi_ya/85187911

ok,以上便是本文的全部内容了,如果对你有所帮助,记得点个赞哟~

参考:

单片机常用芯片总结(一)——LCD1602液晶屏单片机常用芯片总结(二)——DS1302时钟芯片


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有