DS1302时钟芯片

本文详细介绍了DS1302实时时钟芯片的内部结构、工作原理、常用寄存器及其控制指令,包括单字节读写时序和与单片机的通信方法。还提供了电路图和Keil编程文件示例,展示了如何在实际项目中应用这款低功耗时钟芯片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

DS1302简介

前言

DS1302内部结构

理解:

DS1302引脚图

DS1302常用寄存器

寄存器控制指令

解释:

常用寄存器指令

DS1302控制时序

单字节读

代码辅助理解

单字节写 

代码辅助理解

仿真案例

电路图

keil文件

DS1302简介

前言

  • DS1302 是一个实时时钟芯片,可以提供秒、分、小时、日期、月、年等信息,并且还有软件自动调整的能力,可以通过配置 AM/PM 来决定采用 24 小时格式还是 12 小时格式。
  • 拥有 31 字节数据存储 RAM。
  • 串行 I/O 通信方式,相对并行来说比较节省IO口的使用。
  • DS1302 的工作电压比较宽,在 2.0~5.5V 的范围内都可以正常工作。
  • DS1302 这种时钟芯片功耗一般都很低,它在工作电压 2.0V 的时候,工作电流小于 300nA。
  • DS1302 共有 8 个引脚,有两种封装形式,一种是 DIP-8 封装,芯片宽度(不含引脚) 是 300mil,一种是 SOP-8 封装,有两种宽度,一种是 150mil,一种是 208mil。

DS1302内部结构

理解:

  • 电源控制模块:DS1302 有两个电源输入,一个是主电源VCC2,另外一个是备用电源VCC1,比如可以用电池或者大电容,这样做是为了在系统掉电的情况下,我们的时钟还会继续走。如果使用的是充电电池,还可以在正常工作时设置充电功能,给我们的备用电池进行充电。
  • 时钟电路:X1和X2接的是外部的晶振,并通过内部的电路进行一些设置(频率分频等)最终会输出1Hz的标准计时频率
  • 实时时钟RAM:实时时钟就是我们的寄存器,我们内部的时间都是存在该寄存器里面的,里面有31*8个RAM,我们只需要对寄存器进行读写就可以访问时间了。
  • 命令控制逻辑和输入移位寄存器模块:该模块决定了怎么去读写寄存器(SCLK每来一个上升沿,那么IO数据输入移位一次,数据到达命令控制逻辑后要经过CE开关,CE为高电平时数据移位才是有用的)。

DS1302引脚图

注意:

  • 我们在上电时,时钟芯片会以VCC当做电源,同时会对备用电池进行冲电,一旦掉电他就会自动切换到备用电池,保障时钟继续运行。
  • DS1302与单片机通信只需要RES(复位线)、IO(数据线)、SCLK(串行时钟)三根信号线(利用这三根引脚,单片机就可以把芯片内部的时钟读出来)
  • VCC1为+3V供电;VCC2为+5V供电

DS1302常用寄存器

注意:

  • 这里面日历寄存器的值采用BCD码的存储行式。
  • BCD码转10进制:DEC=BCD/16*10+BCD%16;10进制转BCD码:BCD=DEC/10*16+DEC%10
  • 秒寄存器中D7的CH就是时钟暂停,若把该位给1,那么这个秒就会停止,进而导致时钟整个都暂停了;若该位给0则时钟运行(秒钟导致分钟进位,分钟导致小时进位,以此类推)。
  • 时寄存器中D7为0则设置的为24小时模式,D7为1则设置的为24小时模式;D5为0表示AM,D5为1表示PM
  • 年寄存器只能记录到2000年到2099年(因为只有十位和个位可变)
  • 写保护寄存器可以用来关闭写保护,通过发送数据0x00关闭写保护;发送数据0x80打开写保护

寄存器控制指令

解释:

  • D7:固定为1
  • D6:RAM/CK杠位,片内的RAM或日历、时钟寄存器选择位,1为片内RAM,0为日历时钟寄存器
  • D5——D1:地址位,用于选择进行读写的日历、时钟寄存器或片内RAM
  • D0:RD/W读写位,0为写,1为读

常用寄存器指令

注意:向寄存器写入时,那么写入的命令为特定寄存器的地址,若从寄存器读取时,那么读取的命令为寄存器的地址+1。

DS1302控制时序

单字节读

理解:首先将CE置位高电平开始读,将命令字的最低位设置到IO口中;之后时钟给个上升沿,那么命令字的最低位便会被写入单片机;将时钟再置为0后把数据的第2位放入IO口,时钟再给上升沿如此循环往复将最高位也写入IO口,之后时钟给低电平,此时便完成了对命令字的写入操作;DS1302接收到数据后,就会在紧跟着这个时钟的下降沿将这个数据放在IO线上,单片机此时将IO口释放掉,就开始读出DS1302发来的数据(每个下降沿来一个数据)读取完后时钟置0,CE置0,整个操作结束。

代码辅助理解

//单字节读
unsigned char DS1302_ReadByte(unsigned char Command){
	DS1302_RST=0;
	DS1302_SCLK=0;
	unsigned char i,Data=0x00;
	DS1302_RST=1;
	//写命令字
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=0;
		DS1302_SCLK=1;
		//先0后1那么就会在最后致使DS1302_SCLK=1,进而保障了for循环内都与写入有关
	}
	//单片机开始读取数据
	for(i=0;i<8;i++){
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	//若端口状态为1,那么就相当于把IO的1给了Data(先读低位,后读高位)
	if(DS1302_IO==1){
		Data=Data|(0x01<<i);
		}
	}
	DS1302_RST=0;
	DS1302_IO=0; 
	return Data;
}

单字节写 

理解:首先将CE置高电平开始写;将命令字的最低位设置到IO口中;之后时钟给个上升沿,那么命令字的最低位便会被写入单片机;将时钟再置为0后把数据的第2位放入IO口,时钟再给上升沿如此循环往复将最高位也写入IO口,之后时钟给低电平,此时便完成了对命令字的写入操作(发第二个字节的数据和第一个字节命令字过程一样,只不过操作完后再将CE置0)

代码辅助理解

//单字节写
void DS1302_WriteByte(unsigned char Command,unsigned char Data){
	DS1302_RST=0;
	DS1302_SCLK=0;
	unsigned char i;
	DS1302_RST=1;
	//写命令字
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	//写数据
	for(i=0;i<8;i++){
		DS1302_IO=Data&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_RST=0;
	DS1302_IO=0;
}

注意:

  • SCLK每震荡一次,那么就会读取或写入一位数据,在时钟的上升沿,IO口上的电平将会被写入DS1302,在时钟的下降沿,IO口的数据将会从DS1302读出。
  • IO口中数据分两部分,第一部分为指定那一个地址,后面的阶段为真正的读取/写入数据
  • 无论是命令还是数据,一个字节传送时都是低位在前,高位在后(见时序图)。
  • 向芯片写入数据时,首先关闭写保护。

仿真案例

需求:根据数组设定,LCD液晶屏上显示年月日,时分秒(步进)。

电路图

keil文件

#include "reg51.h"
//注意:想看DS1302代码,请见61行后
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
void delay(unsigned int n){
	unsigned int i=0,j=0;
	for(i=0;i<n;i++){
		for(j=0;j<120;j++);
	}
}
//写指令
void writecom(unsigned char com){
	//写指令
	RS=0;
	RW=0;
	E=0;
	P2=com;
	delay(5);
	E=1;
	E=0;
}
//写数据
void writedat(unsigned char dat){
	//写指令
	RS=1;
	RW=0;
	E=0;
	P2=dat;
	delay(5);
	E=1;
	E=0;
}
//初始化液晶屏
void initlcd(){
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//展示数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	for(i=Length;i>0;i--){
		writedat('0'+Number/LCD_Pow(10,i-1)%10);
	}
}
//DS1302篇
sbit DS1302_RST=P3^3;
sbit DS1302_SCLK=P3^4;
sbit DS1302_IO=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[]={19,11,16,12,59,55,6}; //年月日时分秒,星期
//初始化DS1302
void DS1302_Init(){
	DS1302_RST=0;
	DS1302_SCLK=0;
}
//单字节写
void DS1302_WriteByte(unsigned char Command,unsigned char Data){
	unsigned char i;
	DS1302_RST=1;
	//写命令字
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	//写数据
	for(i=0;i<8;i++){
		DS1302_IO=Data&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_RST=0;
	DS1302_IO=0;
}
//单字节读
unsigned char DS1302_ReadByte(unsigned char Command){
	unsigned char i,Data=0x00;
	Command|=0x01; //因为我想给地址的时候给写的地址
	DS1302_RST=1;
	//写命令字
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i); //取出第i位
		//写入
		DS1302_SCLK=0;
		DS1302_SCLK=1;
		//先0后1那么就会在最后致使DS1302_SCLK=1,进而保障了for循环内都与写入有关
	}
	//单片机开始读取数据
	for(i=0;i<8;i++){
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	//若端口状态为1,那么就相当于把IO的1给了Data(先读低位,后读高位)
	if(DS1302_IO==1){
		Data=Data|(0x01<<i);
		}
	}
	DS1302_RST=0;
	DS1302_IO=0; 
	return Data;
}
//10进制转化BCD码
unsigned char DecToBcd(unsigned char dec){
	return (dec/10*16+dec%10);
}
//BCD码转10进制
unsigned char BcdToDec(unsigned char bcd){
	return (bcd/16*10+bcd%16);
}
//设定时间
void DS1302_SetTime(){
	DS1302_WriteByte(DS1302_WP,0x00); //关闭写保护
	DS1302_WriteByte(DS1302_YEAR,DecToBcd(DS1302_Time[0]));
	DS1302_WriteByte(DS1302_MONTH,DecToBcd(DS1302_Time[1]));
	DS1302_WriteByte(DS1302_DATE,DecToBcd(DS1302_Time[2]));
	DS1302_WriteByte(DS1302_HOUR,DecToBcd(DS1302_Time[3]));
	DS1302_WriteByte(DS1302_MINUTE,DecToBcd(DS1302_Time[4]));
	DS1302_WriteByte(DS1302_SECOND,DecToBcd(DS1302_Time[5]));
	DS1302_WriteByte(DS1302_DAY,DecToBcd(DS1302_Time[6]));
	DS1302_WriteByte(DS1302_WP,0x80); //打开写保护
}
//读取时间
void DS1302_ReadTime(){
	unsigned char temp=0;
	  temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=BcdToDec(temp);
	  temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=BcdToDec(temp);
}
unsigned char Second=0;
void main()
{
	initlcd();
	DS1302_Init();
	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);
	}
}

03-08
### DS1302 芯片概述 DS1302 是一款低功耗、串行接口的日历时钟芯片,具有涓流充电能力。该芯片能提供秒、分、小时、日期、月份以及包含闰年补偿的年份信息。其工作电压范围宽泛,可在2.5V至5.5V之间正常运作,并且具备掉电检测引脚以便于系统设计者监控电源状态。 为了更好地理解和应用此款芯片,在查阅相关技术文档时应关注以下几个方面: #### 技术参数与特性 - 工作温度范围:-40°C 到 +85°C; - 日历功能可自动调整大小月天数并考虑闰年的存在; - 提供电池备份输入端子以维持时间数据在主供电中断期间不失效; - 支持SPI兼容三线制同步通信协议进行读写操作[^1]。 #### 接口说明及编程指南 当涉及到具体的应用电路设计时,了解如何正确连接外部组件至关重要。一般情况下,会将DS1302通过三条信号线(CE, IO, SCLK)接入到微控制器单元(MCU),如STM32F103系列。这些MCU可以通过Keil等集成开发环境(IDE)来进行程序编写和调试[^2]。 ```c // 初始化DS1302配置函数示例 void DS1302_Init(void){ // 设置IO口模式为推挽输出 GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_InitStruct); } ``` #### 应用实例分析 实际项目中可能会遇到需要记录精确的时间戳或者定时触发事件的需求,此时就可以利用DS1302来完成相应的工作。例如在一个基于STM32的家庭自动化控制系统里,可以设置每天特定时间段开启灯光或调节空调温度等功能。此外,还有许多开源硬件平台提供了现成的支持库文件帮助开发者快速构建原型产品。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值