51单片机入门:DS1302时钟

51单片机内部含有晶振,可以实现定时/计数功能。但是其缺点有:精度往往不高、不能掉电使用等。 我们可以通过DS1302时钟芯片来解决以上的缺点。


DS1302时钟芯片

功能:DS1302是一种低功耗实时时钟芯片,内部有自动的计时功能,其范围包括:年、月、日、时、分、秒、星期。(且每个月的天数和闰年的天数可以内部自动调整)。

结构以及引脚定义

常见的DS1302时钟芯片有DIP(直插式)和SO(表贴式)两种封装 。

引脚定义
引脚名称功能
X1、X2DS1302外部晶振引脚,通常接32.768K晶振
VCC1备用电源,在主电源使用时可被充电
VCC2主电源供应管脚(与单片机共用一个电源)
GND电源地
CE使能端,也是复位引脚,在进行读写时CE要保持高电平
I/O串行数据输入或输出
SCLK串行时钟

通常通过单片机直接与CE、I/O、SCLK这3个引脚相连,控制其高低电平,进而控制DS1302时钟芯片。

DS1302电路图

其中,C2和C3为旁路电容,目的是消除晶振起振时产生的电感干扰。对于此电路,没有接入备用电池,可自行将外部备用电源接入VCC1。


 DS1302内部寄存器

控制寄存器

功能:通过给控制寄存器数据,来决定:进入年月日等具体哪一个寄存器、进行读/写操作。

 上图为控制寄存器样式。

最高位一直为1;

第6位:1表示RAM,寻址内部存储器;0为CK,寻址内部寄存器。

第5位~第1位:为年月日等日历寄存器的地址。

最低位:1表示下一步操作为“读”;0表示下一步操作为“写”。

日历/时钟寄存器

上图为年月日等相关寄存器的地址(绿框内)、功能等。以下对其进行详细说明:

相关寄存器的位说明
寄存器名称取值范围D7D6D5D4D3D2D1D0
秒寄存器00~59CH秒的十位秒的个位
分寄存器00~590分的十位分的个位
小时寄存器

1~12或

00~23

12小时制/

24小时制

0AM/PMHour小时的个位
日寄存器01~3100日的十位日的个位
月寄存器01~120001或0月的个位
星期寄存器01~070000星期几
年寄存器01~9920XX年的十位年的个位
写保护寄存器WP0000000

需特别注意以下部分:

秒寄存器:CH为DS1302的运行标志,当CH=0时,DS1302内部才能工作;当CH=1时,DS1302停止工作。

写保护寄存器:当WP为1时,DS1302只读不写。所以进行写操作时要确保WP为0。


 DS1302初始时间设置

举个例子,如果想将2024.05.04—周7—23:59:49这个时间写入DS1302内部,具体操作如下:

1、对0x8E地址操作,关闭写保护;

2、对秒寄存器0x80操作,写入0x49;

3、对分寄存器0x82操作,写入0x59;

4、对时寄存器0x84操作,写入0x23;

......以此类推,最后对0x8E地址操作,打开写保护。

BCD码

BCD码:用4位二进制数来表示1位十进制数。

例如:0001 0011表示13、1000 0101表示85、0001 1010不合法。

日历/时钟寄存器内部都是以BCD码来存放数据。因此要设置DS1302的时间,要写入BCD码格式。同时读取数据时,读到的也是BCD码,使用时需转换为对应十进制。

0000050101
1000160110
2001070111
3001181000
4010091001

 转换公式:

读写时序

前面提到:单片机与DS1302相连的线有3根,分别为:CE、SCLK和I/O引脚;如何通过这3根线进行数据写入和读出呢?

CE:初始化使其为低电平,在整个读写过程中,要保持高电平;一次读写操作完毕后,再回到低电平。

//  功能:DS1302初始化
void DS1302_Init(){
	DS1302_CE=0;    //使能端置0
	DS1302_SCLK=0;  //时钟脉冲置0
}

单字节写入:(先关闭写保护)当CE为高电平时,通过单片机控制SCLK产生脉冲,每一个上升沿,I/O线的数据就进入控制寄存器;当控制寄存器配置完成后,紧接着的I/O线数据会在上升沿时进入对应地址的寄存器。

/**
   *@breaf DS1302单字节写入函数
   *@param command:写入命令字,包含要写入寄存器的地址;
   *@param Data:将要写入的数据内容;
   *@retval 无
   */
void  DS1302_WriteBety(unsigned char command,Data)
{
			unsigned char i;
			DS1302_CE=1;//使能位置高电平;


//设置控制寄存器
			for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入
		{
				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;	
}

单字节读出:当CE为高电平时,通过单片机控制SCLK产生脉冲,每一个上升沿,I/O线的数据就进入控制寄存器;当控制寄存器配置完成后,紧接着对应地址的寄存器数据会在下降沿时进入I/O线。

/**
   *@breaf  DS1302单字节读出函数
   *@param command:写入控制指令的指令,包含要读出寄存器的地址;
   *@retval Data:读出的数据;
   */
unsigned char   DS1302_ReadBety(unsigned char command)
{
	unsigned i,Data=0X00;
	    command|=0X01;//写入指令与读出指令只在最后一位相差1,故在此利用或运算消除;
			DS1302_CE=1;//使能位置高电平;
		for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入
		{
				DS1302_IO=command&(0x01<<i);
				DS1302_SCLK=0;	
				DS1302_SCLK=1;
		}
				DS1302_IO=0;
			for(i=0;i<8;i++)//数据读出
		{
					DS1302_SCLK=1;
					DS1302_SCLK=0;			
					if(DS1302_IO)  
					{Data |=(0X01<<i);}
		}
		DS1302_CE=0;
		return Data;
}

注意数据输入从低位开始。


代码设计

main.c

#include <REGX52.H>
#include "lcd1602.h"//包含LCD1602头文件
#include "DS1302.h"//包含DS1302头文件
void main ()//定义主函数
{
	
		LCD_Init();	//LCD1602初始化
		DS1302_Init();//DS1302初始化
		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);//显示秒
					LCD_ShowNum(2,13,DS1302_Time[6], 1);//显示星期
    	}
}

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 
 
//定义数组,用于存放设定的时间,年月日时分秒星期
unsigned char DS1302_Time[]={23,10, 28,19,00,59,6};//顺序:年月日时分秒星期
/**
   *@breaf DS1302初始化
   *@param无
   *@retval无
   */
void  DS1302_Init()
{
	DS1302_CE=0;//将使能位置0,低电平;
	DS1302_SCLK=0;//将时钟位置0,低电平;
}
 
/**
   *@breaf DS1302单字节写入函数
   *@param command:写入控制指令的指令,包含要写入寄存器的地址;
	 *@param Data:将要写入的数据内容;
   *@retval 无
   */
void  DS1302_WriteBety(unsigned char command,Data)
{
			unsigned char i;
			DS1302_CE=1;//使能位置高电平;
			for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入
		{
				DS1302_IO=command&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;
				DS1302_SCLK=1;
				DS1302_SCLK=0;
		}
		
				for(i=0;i<8;i++)//数据写入
		{
				DS1302_IO=Data&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;
				DS1302_SCLK=1;
				DS1302_SCLK=0;
		}
			DS1302_CE=0;	
}
 
/**
   *@breaf  DS1302单字节读出函数
   *@param command:写入控制指令的指令,包含要读出寄存器的地址;
   *@retval Data:读出的数据;
   */
unsigned char   DS1302_ReadBety(unsigned char command)
{
	unsigned i,Data=0X00;
	    command|=0X01;//写入指令与读出指令只在最后一位相差1,故在此利用或运算消除;
			DS1302_CE=1;//使能位置高电平;
		for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入
		{
				DS1302_IO=command&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;
				DS1302_SCLK=0;	
				DS1302_SCLK=1;
		}
				DS1302_IO=0;
			for(i=0;i<8;i++)//数据读出
		{
					DS1302_SCLK=1;
					DS1302_SCLK=0;			
					if(DS1302_IO)  
					{Data |=(0X01<<i);}
		}
		DS1302_CE=0;
		return Data;
}
 
 
/**
   *@breaf 向DS1302内设定时间
   *@param无
   *@retval无
   */
void DS1302_SetTime()
{
		DS1302_WriteBety(DS1302_WP,0x00);//操作 DS1302 之前,关闭写保护,不然指令无法进入控制寄存器;
		DS1302_WriteBety(DS1302_YEAR, DS1302_Time[0]/10*16+DS1302_Time[0]%10);//写入年,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_MONTH, DS1302_Time[1]/10*16+DS1302_Time[1]%10);//写入月,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_DATE, DS1302_Time[2]/10*16+DS1302_Time[2]%10);//写入日,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_HOUR, DS1302_Time[3]/10*16+DS1302_Time[3]%10);//写入时,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_MINUTE, DS1302_Time[4]/10*16+DS1302_Time[4]%10);//写入分,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_SECOND, DS1302_Time[5]/10*16+DS1302_Time[5]%10);//写入秒,并将10进制转化BCD码;
		DS1302_WriteBety(DS1302_DAY, DS1302_Time[6]/10*16+DS1302_Time[6]%10);//写入星期,并将10进制转化BCD码;
		DS1302_WriteBety( DS1302_WP,0x80);//写入结束,开启写保护;
}
 
/**
*@breaf 读取DS1302内时间
*@param无
*@retval无
*/
void DS1302_ReadTime()	
{
	unsigned char Temp;//定义变量,用于暂时存储BCD码
    Temp=DS1302_ReadBety(DS1302_YEAR);//读取年BCD码;
		DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_MONTH);//读取月BCD码;
		DS1302_Time[1]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_DATE);//读取日BCD码;
		DS1302_Time[2]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_HOUR);//读取小时BCD码;
		DS1302_Time[3]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_MINUTE);//读取分钟BCD码;
		DS1302_Time[4]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_SECOND);//读取秒BCD码;
		DS1302_Time[5]=Temp/16*10+Temp%16;//BCD码转十进制;
	 Temp=DS1302_ReadBety(DS1302_DAY);//读取星期BCD码;
		DS1302_Time[6]=Temp/16*10+Temp%16;//BCD码转十进制;
}

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__
 
extern unsigned char DS1302_Time[];//声明设置时间的数组
void  DS1302_Init();//声明初始化函数
void  DS1302_WriteBety(unsigned char command,Data);//声明时间写入函数
unsigned char   DS1302_ReadBety(unsigned char command);//声明时间读出函数
void DS1302_SetTime();//声明设置内部时间函数
void DS1302_ReadTime();//声明读取内部时间函数

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/594368.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

裸金属服务器,云用户的新体验

定义 裸金属服务器&#xff08;Bare Metal Server&#xff09;&#xff0c;是一台既具有传统物理服务器特点的硬件设备&#xff0c;又具备云计算技术的虚拟化服务功能&#xff0c;是硬件和软件优势结合的产物。可以为企业提供专属的云上物理服务器&#xff0c;为核心数据库、关…

15_Scala面向对象编程_访问权限

文章目录 Scala访问权限1.同类中访问2.同包不同类访问3.不同包访问4.子类权限小结 Scala访问权限 知识点概念 private --同类访问private[包名] --包私有&#xff1b; 同类同包下访问protected --同类&#xff0c;或子类 //同包不能访问(default)(public)默认public --公…

学习大数据,所需要的shell基础(1)

文章目录 Shell概述shell脚本入门变量系统预定义变量自定义变量特殊变量$n$#\$*、$$&#xff1f; 运算符条件判断流程控制&#xff08;重点&#xff09;if判断case语句for循环while循环 Shell概述 shell是一个命令解释器&#xff0c;他接受应用程序/用户命令&#xff0c;然后调…

【Python项目】基于opencv的的【疲劳检测系统】

技术简介&#xff1a;使用Python技术、OpenCV图像处理库、MYSQL数据库等实现。 系统简介&#xff1a;用户可以通过登录系统平台实现实时的人脸照片的拍摄和上传&#xff0c;结合上传图像的内容进行后台的图像预处理和运算分析&#xff0c;用户可以通过照片分析界面查看到当前检…

【iOS】KVO

文章目录 前言一、KVO使用1.基本使用2.context使用3.移除KVO通知的必要性4.KVO观察可变数组 二、代码调试探索1.KVO对属性观察2.中间类3.中间类的方法3.dealloc中移除观察者后&#xff0c;isa指向是谁&#xff0c;以及中间类是否会销毁&#xff1f;总结 三、KVO本质GNUStep窥探…

虚拟化技术 使用Vsphere Client管理ESXi服务器系统

使用Vsphere Client管理ESXi服务器系统 一、实验目的与要求 1.掌握使用vSphere Client管理ESXi主机 2.掌握将CentOS的安装介质ISO上传到ESXi存储 3.掌握在VMware ESXi中创建虚拟机 4.掌握在所创建的虚拟机中安装CentOS6.5操作系统 5.掌握给CentOS6.5安装VMware Tools 6.掌…

HCIP的学习(11)

OSPF的LSA详解 LSA头部信息 ​ [r2]display ospf lsdb router 1.1.1.1----查看OSPF某一条LSA的详细信息&#xff0c;类型以及LS ID参数。 链路状态老化时间 指一条LSA的老化时间&#xff0c;即存在了多长时间。当一条LSA被始发路由器产生时&#xff0c;该参数值被设定为0之后…

RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决方法二

参考 RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决 前言 rk3568 rockchip 提供的 u-boot&#xff0c;默认的设备树需要读取 单独分区 resouce.img 镜像中的 设备树文件&#xff0c;也就是 Linux 内核的设备树 dtb 文件&#xff0c;gmac 网络才能正常的 ping 通…

知识图谱和大语言模型的共存之道

导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织新KG视点系列文章—…

Microsoft Remote Desktop Beta for Mac:远程办公桌面连接工具

Microsoft Remote Desktop Beta for Mac不仅是一款远程桌面连接工具&#xff0c;更是开启远程办公新篇章的利器。 它让Mac用户能够轻松访问和操作远程Windows计算机&#xff0c;实现跨平台办公的无缝衔接。无论是在家中、咖啡店还是旅途中&#xff0c;只要有网络连接&#xff0…

如何使用DEEPL免费翻译PDF

如何使用DEEPL免费翻译PDF 安装DEEPL取消PDF限制 安装DEEPL 安装教程比较多&#xff0c;这里不重复。 把英文pdf拖进去&#xff0c;点翻译&#xff0c;在下面的框中有已经翻译完毕的文档。 但是存在两个问题 问题1&#xff1a;这些文档是加密的。 问题2&#xff1a;带有DeepL标…

Golang | Leetcode Golang题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; func climbStairs(n int) int {sqrt5 : math.Sqrt(5)pow1 : math.Pow((1sqrt5)/2, float64(n1))pow2 : math.Pow((1-sqrt5)/2, float64(n1))return int(math.Round((pow1 - pow2) / sqrt5)) }

Java基于Spring Boot框架的课程管理系统(附源码,说明文档)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

【微服务】分布式事务(通过Seata解决分布式事务问题)

分布式事务 分布式事务Seata微服务集成SeataXA模式XA模式使用 AT模式AT模式实现 分布式事务 在分布式系统中&#xff0c;如果一个业务需要多个服务合作完成&#xff0c;而且每一个服务都有事务&#xff0c;多个事务必须同时成功或失败&#xff0c;这样的事务就是分布式事务&am…

解决Maven本地仓库存在依赖包还需要远程下载的问题

背景 公司有自己maven私服&#xff0c;正在在私服可以使用的情况&#xff0c;打包是没问题的。但是这次是由于公司大楼整体因电路检修而停电&#xff0c;所有服务器关机&#xff0c;包括maven私服服务器。然后当天确有一个包需要打&#xff0c;这个时候发现死活打不了&#xf…

自然语言处理(NLP)原理、用法、案例、注意事项

自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;领域的一个重要分支&#xff0c;旨在让计算机能够理解、理解和生成人类语言。 NLP的原理是基于统计建模和机…

list 的模拟实现

目录 1. list 的实现框架 2. push_back 3. 迭代器 4. constructor 4.1. default 4.2. fill 4.3. range 4.4. initializer list 5. insert 6. erase 7. clear 和 destructor 8. copy constructor 9. operator 10. const_iterator 10.1. 普通人的处理方案 10.2. …

物联网小demo

机智云生成代码 具体参考之前的文章 初始化 ADC用来使用光敏电阻 连续采样开启 采样的周期调高 定时器 定时器1用来实现延时 为了只用温湿度模块DHT11 定时器4用来和51进行交互 实现定时的发送和检测心跳信号 IIC 用来使用oled屏幕 USART 串口1和串口2是机智云自己…

Linux —— 信号初识

Linux —— 信号初识 什么是信号测试几个信号signal函数函数原型参数说明返回值注意事项示例 后台程序前台转后台检测输入中断向量表 我们今天来继续学习Linux的内容&#xff0c;今天我们要了解的是Linux操作系统中的信号&#xff1a; 什么是信号 信号是操作系统内核与进程之…

Hash Function(fft)

链接&#xff1a;H-Hash Function_2024牛客五一集训派对day4 (nowcoder.com) 题意&#xff1a;给定一个序列&#xff0c;求使得任意两数的hash值不同的最小模数&#xff1b; 分析&#xff1a;ab(mod seed) |a-b|%seed0; 也就是说seed不能是任意两数差的因子。 如果暴力求解…