DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。工作电压宽达2.5~5.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。DS1302的外部引脚分配如下图所示。DS1302用于数据记录,特别是对某些具有特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录,因此广泛应用于测量系统中
各引脚的功能为:
Vcc1:主电源;
Vcc2:备份电源。当Vcc2>Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2< Vcc1时,由Vcc1向DS1302供电。
SCLK:串行时钟,输入,控制数据的输入与输出;
I/O:三线接口时的双向数据线;
CE:输入信号,在读、写数据期间,必须为高。
外部MCU与DS1302通讯时序如下所示
1. 读取写入操作CE必须为高,写入时,应该在SCLK低电平时完成,SCLK上升沿芯片采样data引脚上的数据,读取时,芯片在下降沿之后将数据写入dat总线上,高电平是数据不变
由此,写入超过过程
SCLK低电平à延时等待电平稳定à写入数据到dataàsclk上升沿,芯片采样(0à1)à延时2usà等待芯片重新回到0à写入下一个数据
读出过程
下降沿芯片将数据放在dat总线上,低电平时读取
具体过程请查看驱动代码
#ifndef __DS1302_H #define __DS1302_H #include "stm32f10x.h" #include "delay.h" extern u8 ascii_time[7]; //保存ascii格式数据 extern u8 bcd_time[7]; //保存bcd码数据 typedef struct DS1302DATA { u8 year; //年 u8 month; //月 u8 day; //日 u8 hour; //时 u8 min; //分 u8 sec; //秒 u8 week; //周 }DS1302DATA; extern struct DS1302DATA ds1302Data; #define DS1302_RST PDout(12) #define DS1302_CLK PDout(10) #define DS1302_DATIN PDin(11) #define DS1302_DATOUT PDout(11) #define DS1302_DAT_INPUT() {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=8<<12;} #define DS1302_DAT_OUTPUT() {GPIOD->CRH &= 0XFFFF0FFF;GPIOD->CRH|=3<<12;} //芯片寄存器地址定义 定义的写地址,读需要+1 #define DS1302_SEC_REG 0x80 //秒数据地址 #define DS1302_MIN_REG 0x82 //分数据地址 #define DS1302_HR_REG 0x84 //时数据地址 #define DS1302_DATE_REG 0x86 //日数据地址 #define DS1302_MONTH_REG 0x88 //月数据地址 #define DS1302_DAY_REG 0x8a //星期几数据地址 #define DS1302_YEAR_REG 0x8c //年数据地址 #define DS1302_CONTROL_REG 0x8e //写保护寄存器地址 #define DS1302_CHARGER_REG 0x90 //涓流充电寄存器 #define DS1302_CLKBURST_REG 0xbe //脉冲串寄存器 #define DS1302_RAM_BASE 0X30 //RAM基础地址 #define CLOCKSTOP 0X80 #define CLOCKSTART 0X00 void Ds1302_Gpio_Init(void); void Ds1302_Write_Time_All(u8 start); void Ds1302_Readtime(void); #endif
#include "ds1302.h" struct DS1302DATA ds1302Data = {0,0,0,0,0,0,0}; u8 ascii_time[7] = {0}; //保存ascii格式数据 u8 bcd_time[7] = {0}; //保存bcd码数据 static u8 AsciiToBcd(u8 asciiData) { u8 bcdData = 0; bcdData = (((asciiData/10)<<4)|((asciiData%10))); return bcdData; } static u8 BcdToAscii(u8 bcdData) { u8 asciiData = 0; asciiData = (((bcdData&0xf0)>>4)*10 + (bcdData&0x0f)); return asciiData; } //IO口初始化 void Ds1302_Gpio_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //RST GPIO_InitStructure.GPIO_Pin =GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_Init(GPIOD, &GPIO_InitStructure); //CLK GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_Init(GPIOD, &GPIO_InitStructure); //IO GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 GPIO_Init(GPIOD, &GPIO_InitStructure); } //读取一个字节的时序 u8 Ds1302_ReadByte(void) { u8 i = 0, dat = 0; DS1302_DAT_INPUT(); delayUs(5); for(i = 0; i <8; i++) { dat >>= 1; if(DS1302_DATIN == 1)dat |= 0x80; DS1302_CLK = 1; delayUs(2); DS1302_CLK = 0; delayUs(2); } return dat; } //写入一个字节的时序 void Ds1302_WriteByte(u8 dat) { u8 i = 0, data = dat; DS1302_DAT_OUTPUT(); DS1302_CLK = 0; delayUs(2); for(i = 0; i < 8; i++) { DS1302_DATOUT = data&0x01; delayUs(2); DS1302_CLK = 1; delayUs(2); DS1302_CLK = 0; data >>= 1; } } //写入一个寄存器 void Ds1302_Write(u8 address,u8 dat) { DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; Ds1302_WriteByte(address); Ds1302_WriteByte(dat); DS1302_CLK = 1; DS1302_RST = 0; } //单个写入时间 void Ds1302_Write_Time_Singel(u8 address,u8 dat) { Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消写保护 Ds1302_Write(address,dat); Ds1302_Write(DS1302_CONTROL_REG,0x80); //打开写保护 } //一次完成所有时间更新 //start当前时钟运行还是停止 void Ds1302_Write_Time_All(u8 start) { Ds1302_Write(DS1302_CONTROL_REG,0x00); //取消写保护 Ds1302_Write(DS1302_SEC_REG,(AsciiToBcd(ds1302Data.sec)|start)); Ds1302_Write(DS1302_MIN_REG,AsciiToBcd(ds1302Data.min)); Ds1302_Write(DS1302_HR_REG,AsciiToBcd(ds1302Data.hour)); Ds1302_Write(DS1302_DATE_REG,AsciiToBcd(ds1302Data.day)); Ds1302_Write(DS1302_MONTH_REG,AsciiToBcd(ds1302Data.month)); Ds1302_Write(DS1302_DAY_REG,AsciiToBcd(ds1302Data.week)); Ds1302_Write(DS1302_YEAR_REG,AsciiToBcd(ds1302Data.year)); Ds1302_Write(DS1302_CONTROL_REG,0x80); //打开写保护 } //读取一个字节 u8 Ds1302_Read(u8 address) { u8 data = 0; DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; Ds1302_WriteByte(address|0x01); //读取地址需要与0x01相或,最低为变成1 data = Ds1302_ReadByte(); DS1302_CLK = 1; DS1302_RST = 0; return data; } //读取时间的时候默认让时间走起来 void Ds1302_Readtime(void) { ds1302Data.sec = BcdToAscii(Ds1302_Read(DS1302_SEC_REG)); //秒 ds1302Data.min = BcdToAscii(Ds1302_Read(DS1302_MIN_REG)); //分 ds1302Data.hour = BcdToAscii(Ds1302_Read(DS1302_HR_REG)); //小时 ds1302Data.day = BcdToAscii(Ds1302_Read(DS1302_DATE_REG)); //日 ds1302Data.month = BcdToAscii(Ds1302_Read(DS1302_MONTH_REG)); //月 ds1302Data.week = BcdToAscii(Ds1302_Read(DS1302_DAY_REG)); //星期几 ds1302Data.year = BcdToAscii(Ds1302_Read(DS1302_YEAR_REG)); //年 }
DS1302有下列几组寄存器:
DS1302 ①有关日历、时间的寄存器共有12个,其中有7个寄存器
(读时81h~8Dh,写时80h~8Ch),存放的数据格式为BCD码形式,我们读取之后需要修改为acsii码模式,如下
小时寄存器(85h、84h)的位7用于定义DS1302是运行于12小时
模式还是24小时模式。当为高时,选择12小时模式。在12小时模式时,
位5是 ,当为1时,表示PM。在24小时模式时,位5是第二个10小时
位。
秒寄存器(81h、80h)的位7定义为时钟暂停标志(CH)。当该
位置为1时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为
0时,时钟开始运行。
控制寄存器(8Fh、8Eh)的位7是写保护位(WP),其它7位均置
为0。在任何的对时钟和RAM的写操作之前,WP位必须为0。当
WP位为1时,写保护位防止对任一寄存器的写操作。
DS1302中附加31字节静态RAM的地址如图
所谓突发模式是指一次传送多个字节的时钟信号和RAM数据。
突发模式寄存器如图