ds1302
注意事项
在日历/时钟寄存器中都是以 BCD 码存放数据,往相关寄存器中写入数据时先要转化为BCD码格式在进行写入;读取数据时,读到的是BCD码,使用时需要转化为相应的十进制或十六进制;
注: 在操作 DS1302 之前关闭写保护;不然指令无法进入控制寄存器;
ds1302
DS1302 有一个控制寄存器、12 个日历、时钟寄存器和 31 个 RAM。
DS1302是一种低功耗实时时钟芯片,实时时钟计算年、月、日、时、分、秒、星期,直到 2100 年,并有闰年调节功能。每月的天数和闰年的天数可自动调整。时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与 单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:1、CE使能线;2、I/O 数据线;3、SCLK 串行时钟线;
晶振
一个 32.768kHz 晶振可以通过管脚2和3(X1,X2)直接连接到DS1302
管脚
管脚 | 名称 | 功能 |
---|---|---|
1 | VCC2 | 双供电配置中的主电源供应管脚(单片机供电); |
2 | X1 | DS1302 外部晶振引脚,通常需外接 32.768K 晶振; |
3 | X2 | DS1302 外部晶振引脚,通常需外接 32.768K 晶振; |
4 | GND | 电源地; |
5 | CE | 使能引脚,也是复位引脚,CE信号在读写时必须保持高电平; |
6 | I/O | 串行数据引脚,数据输出或者输入 |
7 | SCLK | 串行数据引脚 |
8 | VCC1 | 备用电源 |
控制寄存器
控制寄存器用于存放 DS1302 的控制命令字,DS1302 的CE引脚回到高电平后写入的第一个字节就为控制命令。它用于对 DS1302 读写过程进行控制:
每一次启动数据传输. MSB (位 7)必须是逻辑1,如果是 0,则禁止对DS1302写入;位 6 在逻辑0时规定为时钟/日历数据,逻辑1时为RAM数据;位 1 至 位 5 表示了输入输出的指定寄存器,LSB (位 0) 在逻辑0时为写操作(输出),逻辑1时为读操作(输入);控制寄存器以LSB (位 0)开始总是输入
控制命令
读取适当的寄存器字节可以得到时间和日历信息
写入适当的寄存器字节可以设置或初始化时间和日历
时间和日历寄存器的内容是二进制编码的十进制(BCD)格式的
秒寄存器:低四位为秒的个位,高的次三位为秒的十位。最高位 CH 为 DS1302 的运行标志,当 CH=0 时,DS1302 内部时钟运行,反之 CH=1 时停止 ;
数据格式
时寄存器:最高位为 12/24 小时的格式选择位,该位为 1 时 表示 12 小时格式。当设置为 12 小时显示格式时,第 5 位的高电平表示下午 (PM);而当设置为 24 小时格式时,第 5 位位具体的时间数据;
**写保护寄存器:**当该寄存器最高位 WP 为 1 时,DS1302 只读不写,所以要在往 DS1302 写数据之前确保 WP 为0;
读写时序
电气特性(延时)
CE(RST):复位时序,即在RST引脚产生一个正脉冲,在整个读写器件, RST要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;
**单字节写入:**在CE为高电平后,SCLK会输出周期脉冲,每一个上升沿,IO线的数据就会进入控制寄存器,当控制寄存器配置完成(为写入数据,并且地址已给),紧接着的脉冲IO线的数据就会在上升沿进入对应地址的寄存器;
**单字节读出:**在CE为高电平后,SCLK会输出周期脉冲,每一个上升沿,IO线的数据就会进入控制寄存器,当控制寄存器配置完成(为读出数据,并且地址已给),紧接着对应地址的寄存器的数据就会在下降沿进入IO线;
//管脚定义
sbit DS1302_RST=P3^5;//复位管脚
sbit DS1302_CLK=P3^6;//时钟管脚
sbit DS1302_IO=P3^4 ;//数据管脚
//变量声明
extern u8 gDS1302_TIME[7];//存储时间
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2021年5月20日星期四13点51分47秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
u8 gDS1302_TIME[7] = {0x47, 0x51, 0x13, 0x20, 0x04, 0x05, 0x21};
//函数声明
void ds1302_init(void);
void ds1302_read_time(void);
/*******************************************************************************
* 函 数 名 : ds1302_write_byte
* 函数功能 : DS1302写单字节
* 输 入 : addr:地址/命令
dat:数据
* 输 出 : 无
*******************************************************************************/
void ds1302_write_byte(u8 addr,u8 dat)
{
u8 i=0;
DS1302_RST=0;
;
DS1302_CLK=0;//CLK低电平
;
DS1302_RST=1;//RST由低到高变化
;
for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
{
DS1302_IO=addr&0x01;
addr>>=1;
DS1302_CLK=1;
;
DS1302_CLK=0;//CLK由低到高产生一个上升沿,从而写入数据
;
}
for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
{
DS1302_IO=dat&0x01;
dat>>=1;
DS1302_CLK=1;
;
DS1302_CLK=0;
;
}
DS1302_RST=0;//RST拉低
;
}
/*******************************************************************************
* 函 数 名 : ds1302_read_byte
* 函数功能 : DS1302读单字节
* 输 入 : addr:地址/命令
* 输 出 : 读取的数据
*******************************************************************************/
u8 ds1302_read_byte(u8 addr)
{
u8 i=0;
u8 temp=0;
u8 value=0;
// uart_init(0XFA);
DS1302_RST=0;
;
DS1302_CLK=0;//CLK低电平
;
DS1302_RST=1;//RST由低到高变化
;
for(i=0;i<8;i++)//循环8次,每次写1位,先写低位再写高位
{
DS1302_IO=addr&0x01;
addr>>=1;
DS1302_CLK=1;
;
DS1302_CLK=0;//CLK由低到高产生一个上升沿,从而写入数据
;
}
for(i=0;i<8;i++)//循环8次,每次读1位,先读低位再读高位
{
temp=DS1302_IO;
value=(temp<<7)|(value>>1);//先将value右移1位,然后temp左移7位,最后或运算
DS1302_CLK=1;
;
DS1302_CLK=0;
;
}
// DS1302_RST=0;//RST拉低,当DS1302与DS18B20同时使用时,注释掉该调语句
;
DS1302_CLK=1;//对于实物中,P3.4口没有外接上拉电阻的,此处代码需要添加,使数据口有一个上升沿脉冲。
;
DS1302_IO = 0;
;
DS1302_IO = 1;
;
// SBUF=value;
return value;
}
/*******************************************************************************
* 函 数 名 : ds1302_init
* 函数功能 : DS1302初始化时间
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void ds1302_init(void)
{
u8 i=0;
ds1302_write_byte(0x8E,0X00);//关闭写保护
for(i=0;i<7;i++)
{
ds1302_write_byte(gWRITE_RTC_ADDR[i],gDS1302_TIME[i]);
}
ds1302_write_byte(0x8E,0X80); //打开写保护
}
/*******************************************************************************
* 函 数 名 : ds1302_read_time
* 函数功能 : DS1302读取时间
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void ds1302_read_time(void)
{
u8 i=0;
for(i=0;i<7;i++)
{
gDS1302_TIME[i]=ds1302_read_byte(gREAD_RTC_ADDR[i]);
}
}