当前位置: 首页 > news >正文

DS1302实时时钟模块

目录

0.单片机定时器时钟的几个缺点:

1.DS1302介绍

2.引脚定义和应用电路

3.原理图

4.内部结果框图,RAM(寄存器)

5.寄存器定义

6.时序定义

7.DS1302时钟代码

第一步:

第二步:

第三步:

第四步:

第五步:

第六步:

第七步:

第八步:

第九步:

第十步:

第十一步:

第十二步:

第十三步:

第十四步:

最终代码:

模块化:

DS1302.c

DS1302.h

main.c

8.可调时钟代码

第一步:

第二步:

第三步:

第四步:

第五步:

独立按键1:

独立按键2:

独立按键3:

独立按键4:

第六步:

第七步:

给定时器0初始化

复制定时器中断函数模板到主函数最下面,进行修改,让他1010(二进制)的变化

在TimeShow函数末尾修改为

最终代码:

模块化:

main.c


0.单片机定时器时钟的几个缺点:

1.精度不高,不如时钟芯片精度高

2.占用单片机CPU时间

3.不能断电,断电了就重新计时了。时钟芯片有备用电池,断电后还可以运行

1.DS1302介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能

RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片

2.引脚定义和应用电路

DIP直插封装、so贴片封装、接时钟的晶振(脉冲)固定的。CE、I/O、SCLK通讯引脚,设置写入时间及读取时钟

3.原理图

4.内部结果框图,RAM(寄存器)

5.寄存器定义

寄存器、WP:读写写保护;地址:0s80

要操作RTC最高位给1,第6位操作时钟给0,操作秒地址位给0,第0位读写操作:WR:0写;即10000000->80h:写秒,读81h

6.时序定义

CE(操作使能)在整个操作过程中要给高电频,就是开始写之前给1,写完之后给0,这样整个写入操作才是有效的;对我们单片机来说,在时钟的上升沿(READ)向时钟芯片写入数据,在时钟的下降沿(WRITE)时钟芯片读出发出的数据;在SCLK时钟上升沿,IO口被写入,下降沿输出:R/W(控制读写,给1单片机输出数据,给0写完一个字节后继续写);在整个时序中只要D0~D7是1302操控,其他的部分都是单片机操控。

写入数据(在WRITE中):第一步,CE置1;第二步把命令制的最低位0/1,设置在I/O空上;第三步,时钟给个上升沿。然后命令制的最后一位就会被写入单片机。然后A0~1重复第二第三步,最后给低电频。到了发送信号给单片机时,发第一位D0给个上升沿,重复到D7,最后给CE置0。写入数据就完成了

读出数据(在READ中):D0之前的步骤和写入数据的D0之前的步骤一样;然后,要接受写入的数据,接受第一位数据给个下降沿数据到D0,重复到D7;然后,再给CE置0。读出数据就完成了

通过写入数据和读出数据的步骤,就能对时钟进行设置和读取了

7.DS1302时钟代码

第一步:

DS1302要用液晶屏显示,所以要把LCD1602液晶屏显示配置代码复制过来,导入项目中

第二步:

看原理图重新定义P35、P34、P36这三个引脚

第三步:

在DS1302.c里面定义这两个函数,有了这两个函数就很方便在的在某个地址下数据进行读写操作

第四步:

在DS1302.c里面初始化写操作,默认给0

第五步:

在DS1302.c时钟写字节

第六步:

看时序定义图,时钟读操作,先给下降沿,再上升沿,控制下面红色部分,上下区分开来:(&清零,|置1)

第七步:

头文件声明

第八步:

主函数调用

之后把读和显示的部分拉入循环

调用测试后发现的问题并解决

为什么,测试是,时钟会在9的时候直接到16,是因为BCD码的存在,BCD码存在方式:解读一下用4位二进制数来表示十进制数,0001 0011-->13为例,前面的0001(二进制)转换为1(十进制),后面的0011(二进制)转换位3(十进制),组合为13。0001(二进制)-->1(十进制),1010(二进制)-->10(十进制)组合超过两位不合法。十六进制就是先转换为二进制,在按照BCD码规则变成十进制数

第九步:

将BCD码转换为十进制显示,方法按照上述图片中的公式,注意:只能两位。这里是为了测试所以在主函数里面进行了BCD转换为十进制,后面为了方便,就模块化,然后在主函数里面调用,这样会方便很多

第十步:

定义数组优化模块 DS1302时钟&可调时钟

第十一步:

设置时间和读取时间(WP:写保护关闭,置0):写的地址或上0x01就是读地址

第十二步:

这里就是第九步中BCD转换为十进制的模块化

第十三步:

函数头文件里面声明

第十四步:

主函数调用自定义函数和设置时钟的形式

最终代码:

模块化:

DS1302.c

#include <REGX52.H>//引脚定义
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;//寄存器写入地址/指令定义
#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//时间数组,索引0~6分别为年、月、日、时、分、秒
unsigned char DS1302_Time[]={25,5,9,18,00,00};/*** @brief  DS1302初始化* @param  无* @retval 无*/
void DS1302_Init(void)
{DS1302_CE=0;DS1302_SCLK=0;
}/*** @brief  DS1302写一个字节* @param  Command 命令字/地址* @param  Data 要写入的数据* @retval 无*/
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0;
}/*** @brief  DS1302读一个字节* @param  Command 命令字/地址* @retval 读出的数据*/
unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data=0x00;Command|=0x01;	//将指令转换为读指令DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i);DS1302_SCLK=0;DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1;DS1302_SCLK=0;if(DS1302_IO){Data|=(0x01<<i);}}DS1302_CE=0;DS1302_IO=0;	//读取后将IO设置为0,否则读出的数据会出错return Data;
}/*** @brief  DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中* @param  无* @retval 无*/
void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入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);
}/*** @brief  DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中* @param  无* @retval 无*/
void DS1302_ReadTime(void)
{unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取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;
}

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期
extern unsigned char DS1302_Time[];void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);#endif

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"void main()
{LCD_Init();DS1302_Init();LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示LCD_ShowString(2,1,"  :  :  ");DS1302_SetTime();//设置时间while(1){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);//显示秒}
}

8.可调时钟代码

第一步:

将DS1302时钟复制整个工程

第二步:

把按键代码和定时器代码复制粘贴到工程里面

第三步:

在主函数包含头文件,其他的模块代码,不用动,写好直接用

第四步:

显示时间(最后2是显示宽度)

第五步:

设置时间设置函数(年,月(代码次复杂),日(最复杂),小时,分钟,秒)(越界判断,超出回归初始值)(调用函数Key)

独立按键1:

进入/退出设置时间模式

独立按键2:

按照年、月、日、小时、分钟、秒依此移动设置

独立按键3:

加时间

独立按键4:

减时间

第六步:

让设置的时间,可以写入时钟,在主函数加入DS1302_setTime

第七步:

进入时间设置模式让对应位闪烁(调用函数Timer0)

给定时器0初始化

复制定时器中断函数模板到主函数最下面,进行修改,让他1010(二进制)的变化

在TimeShow函数末尾修改为

最终代码:

模块化:

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;void TimeShow(void)//时间显示功能
{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);//显示秒
}void TimeSet(void)//时间设置功能
{if(KeyNum==2)//按键2按下{TimeSetSelect++;//设置选择位加1TimeSetSelect%=6;//越界清零}if(KeyNum==3)//按键3按下{DS1302_Time[TimeSetSelect]++;//时间设置位数值加1if(DS1302_Time[0]>99){DS1302_Time[0]=0;}//年越界判断if(DS1302_Time[1]>12){DS1302_Time[1]=1;}//月越界判断if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)//日越界判断{if(DS1302_Time[2]>31){DS1302_Time[2]=1;}//大月}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]>30){DS1302_Time[2]=1;}//小月}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]>29){DS1302_Time[2]=1;}//闰年2月}else{if(DS1302_Time[2]>28){DS1302_Time[2]=1;}//平年2月}}if(DS1302_Time[3]>23){DS1302_Time[3]=0;}//时越界判断if(DS1302_Time[4]>59){DS1302_Time[4]=0;}//分越界判断if(DS1302_Time[5]>59){DS1302_Time[5]=0;}//秒越界判断}if(KeyNum==4)//按键4按下{DS1302_Time[TimeSetSelect]--;//时间设置位数值减1if(DS1302_Time[0]<0){DS1302_Time[0]=99;}//年越界判断if(DS1302_Time[1]<1){DS1302_Time[1]=12;}//月越界判断if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)//日越界判断{if(DS1302_Time[2]<1){DS1302_Time[2]=31;}//大月if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]<1){DS1302_Time[2]=30;}//小月if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]<1){DS1302_Time[2]=29;}//闰年2月if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]<1){DS1302_Time[2]=28;}//平年2月if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]<0){DS1302_Time[3]=23;}//时越界判断if(DS1302_Time[4]<0){DS1302_Time[4]=59;}//分越界判断if(DS1302_Time[5]<0){DS1302_Time[5]=59;}//秒越界判断}//更新显示,根据TimeSetSelect和TimeSetFlashFlag判断可完成闪烁功能if(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1,"  ");}else {LCD_ShowNum(1,1,DS1302_Time[0],2);}if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4,"  ");}else {LCD_ShowNum(1,4,DS1302_Time[1],2);}if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7,"  ");}else {LCD_ShowNum(1,7,DS1302_Time[2],2);}if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1,"  ");}else {LCD_ShowNum(2,1,DS1302_Time[3],2);}if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4,"  ");}else {LCD_ShowNum(2,4,DS1302_Time[4],2);}if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7,"  ");}else {LCD_ShowNum(2,7,DS1302_Time[5],2);}
}void main()
{LCD_Init();DS1302_Init();Timer0Init();LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示LCD_ShowString(2,1,"  :  :  ");DS1302_SetTime();//设置时间while(1){KeyNum=Key();//读取键码if(KeyNum==1)//按键1按下{if(MODE==0){MODE=1;TimeSetSelect=0;}//功能切换else if(MODE==1){MODE=0;DS1302_SetTime();}}switch(MODE)//根据不同的功能执行不同的函数{case 0:TimeShow();break;case 1:TimeSet();break;}}
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值T0Count++;if(T0Count>=500)//每500ms进入一次{T0Count=0;TimeSetFlashFlag=!TimeSetFlashFlag;//闪烁标志位取反}
}

相关文章:

  • Java-List集合类全面解析
  • CSS- 4.5 css + div 布局 简易网易云音乐 官网布置实例
  • 「NameCraft · 幻想命名器」开发记:我和 CodeBuddy 的一次奇幻共创之旅
  • 易境通散货拼柜系统:提高货代企业货物配载效率
  • CEF源码历史版本编译避坑指南
  • JSON学习笔记
  • 视频监控中的存储方式有哪些?EasyCVR视频监控汇聚平台如何打造高效监控存储
  • 【STM32】ST-Link V2.1制作
  • 【CF】Day62——Codeforces Round 948 (Div. 2) CD (思维 + LCM + 枚举因数 | 思维 + 哈希)
  • Amazon Q 从入门到精通 – 测试与重构
  • Python的传参过程的小细节
  • k8s1.27集群部署mysql8.0双主双从
  • 第二道re
  • UE 材质基础第二天
  • 线光谱共焦传感器:复杂材质检测
  • 【盈达科技】GEO优化实战策略
  • 基于PetaLinux的Zynq PS应用自启动全攻略
  • 浙江大学python程序设计(陈春晖、翁恺、季江民)习题答案-第五章
  • 大模型(1)——基本概念
  • 达梦数据库对json字段进行操作
  • 痴情与真爱
  • 王毅同丹麦外交大臣会谈,表示在格陵兰问题充分尊重丹麦主权和领土完整
  • 澎湃读报丨多家央媒刊文关注拧紧纪律的螺丝:强化监督推动过紧日子要求落到实处
  • 体坛联播|利物浦三轮不胜,孙颖莎/王楚钦晋级混双八强
  • 欧阳娜娜等20多名艺人被台当局列入重要查核对象,国台办回应
  • 半数以上中国人都缺这几种营养,吃什么能补回来?