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数据。
突发模式寄存器如图