目录

1.前言

1.1 实验现象

2. DS1302的介绍

2.1 DS1302的引脚定义以及应用电路

2.2 DS1302内部结构

2.21  DS1302内部特殊寄存器

2.22 时序

2.3 BCD码

3.源码

3.1 main.c

3.2 DS1302.c

3.3 DS1302.h

3.4 LCD1602.c

3.5 Delay.c

3.6 Delay.h


1.前言

之前我们已经使用了定时器做过了简易的时钟了,为什么还要用DS1302制作时钟呢?

定时器计时的缺点:

1.精度没有时钟芯片高

2.它会占用单片机cpu时间

3.单片机的定时器时钟不能掉电后继续运行;

DS1302时钟芯片带有备用电池,如果掉电,它的内部逻辑判断就会自动把电源切换到备用电池;

由于开发板上vcc1没有接备用电源,掉电继续走时的现象就看不到了

1.1 实验现象

第一行显示年— 月— 日 第二行显示时:分:秒

2. DS1302的介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能
RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片

2.1 DS1302的引脚定义以及应用电路

2.2 DS1302内部结构

x1,x2 接外部晶振,通过内部电路输出1HZ标准计时频率;

右下角:内部寄存器,内部时间存在这里;

CE:芯片使能 这里的CE相当于一个中介开关,CE高电平有效。

输入移位寄存器与74HC595差不多,进行串行数据的交互的;

2.21  DS1302内部特殊寄存器

内部不止这些寄存器还有一些通用寄存器 ,这些特殊寄存器是与时钟有关的

寄存器都有一个地址,每个地址下就是一个数据,数据是一个字节一个字节存储的;

wp:写保护,置高电平,写入的操作是无效的,但可以读取数据;

TCS TCS...涓细电流充电的,开发板没有这个寄存器就不用配置了;

80H,81H是命令字,也代表了它的地址;

完成时钟显示的基本流程:

在哪里  写入 什么

在哪里 读出 什么

命令字任务:

在哪里  写入

在哪里 读出

2.22 时序

单字节写为16个脉冲,单字节读为15个脉冲,编写代码时需注意;单字节读:写完指令后,单片机释放对I/O口的控制,把I/O口控制权交给DS1302;我们只要写完指令后重复置高电平就可以过滤掉一个脉冲了;

 单字节写:

首先把CE置高电平,开始写,第二步命令字发两个字节,第一个:命令字;第二个字节数据

命令字:第一位先发R/(--W)设置到I/O口上 别问为什么,问就是内部芯片就是这样设计的。

上升沿数据写入;依次循环,直到最高位被写入;

CE置高电平后,第一个写入的就是命令字(告诉它在哪里读,还是在哪里写)操作完成后CE置低电平

单字节读:

写入完成命令字后,下降沿把I/O口线释放掉,就不再操作I/O口了,就开始读出数据

每一个下降沿来一个数据,把数据一个一个读出来;注意单字节读D1到D7是不用操作I/O口的;

2.3 BCD码

内部寄存器数据不是以正常二进制进行存储的,而是以BCD码进行存储的(方便译码)

BCD码(Binary Coded Decimal‎),用4位二进制数来表示1位十进制数

例:0001 0011表示13,1000 0101表示85,0001 1010不合法

在十六进制中的体现:0x13表示13,0x85表示85,0x1A不合法

BCD码转十进制:DEC=BCD/16*10+BCD%16; (2位BCD)
十进制转BCD码:BCD=DEC/10*16+DEC%10; (2位BCD)

注:这个方法只能转化2位BCD,所以下面代码中显示年份2022的只显示为22年

3.源码

3.1 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();//不断循环读取DS1302中的时间数据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.2 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[]={22,11,16,12,59,55,6};//单片机上电后默认置高电平,所以初始化
void DS1302_Init()
{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; //写完指令后,单片机释放对I/O口的控制,把I/O口控制权交给DS1302;
}/*** @brief  DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中* @param  无* @retval 无*/
void DS1302_SetTime()  //十进制转BCD码后写入
{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);
}/*** @brief  DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中* @param  无* @retval 无*/
void DS1302_ReadTime()  //BCD码转十进制后读取
{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.3 DS1302.h

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

3.4 LCD1602.c

#include <REGX52.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief  返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');}
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif

3.5 Delay.c


void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}

3.6 Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int xms);#endif

51单片机——DS1302时钟相关推荐

  1. 基于51单片机ds1302时钟、ds18b20、lcd12864的恒温器

    目录 项目:基于51单片机ds1302时钟.ds18b20的恒温器 功能说明: 运行流程: 效果展示: 供电方式: 用途: 提高: 附: ​                              ...

  2. 51单片机DS1302时钟LCD1602显示(可以按键设置时钟)

    DS1302实时时钟具有能计算2100年之前的秒.分.时.日.日期.星期.月.年的能力,还有闰年调整的能力. 图1:DS1302引脚示意图 其中: X1.X2:32.768KHz晶振接入引脚. GND ...

  3. (九)51单片机——DS1302时钟

    目录 DS1302介绍 引脚定义和应用电路 寄存器定义 命令字 时序定义 代码编写 今天,我们的任务是要编写一个用51开发板编写的可调小时钟,接下来就让我们一步一步来实现它吧! DS1302介绍 DS ...

  4. 51单片机DS1302时钟芯片应用Proteus仿真

    系列文章目录 第一章 51单片机Proteus仿真(一) DS1302使用 文章目录 系列文章目录 前言 一.DS1302时序解读 二.BCD码转十进制解读 三.Proteus仿真 四.详细代码 前言 ...

  5. (给自己看)51单片机DS1302时钟芯片

    老规矩先上DS1302.c的代码 #include <regx52.h>//首先 DS1302_Init(); // DS1302_SetTime();//再在while中DS1302_R ...

  6. 51单片机DS1302数字时钟

    51单片机DS1302数字时钟 #include <reg52.h> #define uchar unsigned char #define uint unsigned intsbit R ...

  7. 51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能)

    51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能) AT89C52.LCD1602.DS1302.speaker. Proteus仿真 实例代码 #include<reg52.H ...

  8. 51单片机实时时钟显示

    51单片机+DS1302+DS18B20+LCD12864 用的IIC通信,写的一个ds3231时钟模块的程序,可更改时间,下面是.h文件里面的部分代码 #ifndef __ds3231_h #def ...

  9. 蓝桥杯单片机DS1302时钟芯片驱动代码注释

    蓝桥杯单片机DS1302时钟芯片驱动代码之前的疑惑注释了下 /* DS1302 芯片包含一个 实时时钟/日历和 31 字节的静态 RAM. 与时钟/RAM 通讯只需要三根线: CE,I/O (数据线) ...

最新文章

  1. java读取excel数据保存到数据库中_java读取excel的内容(可保存到数据库中)
  2. VMware新装CentOS无法连接外网解决方法
  3. JavaScript学习(三十四)—事件委托
  4. 计算时间:一个运算符重载示例
  5. sql azure 语法_Azure SQL –弹性作业代理
  6. 网上图书商城项目学习笔记-034订单管理
  7. 解决U盘安装Win10报错:No bootbale devices found.
  8. 【CTR】ESMM:多任务联合学习
  9. FFmpeg 视频旋转处理命令
  10. 【HAVENT原创】VUE2 经验问题汇总
  11. Win11 鼠标右键后怎么设置让其显示更多可操作的选项
  12. C语言程序设计学习笔记:P1-程序设计与C语言
  13. 石油化工行业智能供应链管理系统解决方案:数智化供应链平台推动企业转型智能化发展
  14. java 生成csv文件_Java生成CSV文件实例详解
  15. 智能呼叫系统关键技术(一)
  16. xshell 密钥身份验证_使用密钥斗篷和大使边缘堆栈进行集中式身份验证
  17. macM1安装tensorflow和torch教程(python3.8环境)
  18. C语言实现人物动态移动效果
  19. VBA 函数计算date之间的天数工作日
  20. 用Excel制作不一样的百分比信息图表(3)

热门文章

  1. Python 学习笔记之 networkx 使用
  2. ShellExecute, WinExec, CreateProcess的使用
  3. 如果用计算机名共享打印机,当IP地址经常变动时,使用计算机名连接共享打印机...
  4. 计算机的性能指标概念,cpu性能指标有哪些及其概念是什么
  5. uni-app混合原生安卓开发
  6. 店宝宝:淘宝特价版怎么玩?
  7. Java面向对象三大特性之【多态性】
  8. leaflet叠加多个面(面的数据结构)(leaflet篇.62)
  9. 搭载高通3040芯片的澎湃音质,NANK南卡N2S无线蓝牙耳机评测!
  10. Linux开发之Makefile简明教程及示例