157 lines
4.0 KiB
C
157 lines
4.0 KiB
C
/******************************************************************************
|
||
* 文件名:ds1302.c
|
||
* 功能:DS1302 实时时钟驱动
|
||
* 说明:提供读写 DS1302 的底层函数,以及时间和闹钟参数的存取。
|
||
* 时间以 BCD 码格式存储于 TIME 数组中。
|
||
* 硬件接口:DSIO=P3^4,RST=P3^5,SCLK=P3^6
|
||
* 编译器:Keil C51
|
||
******************************************************************************/
|
||
|
||
#include"ds1302.h"
|
||
|
||
/* DS1302 读写地址(存储顺序:秒、分、时、日、月、周、年) */
|
||
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
|
||
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
|
||
|
||
/* DS1302 默认时间:2013 年 1 月 1 日 星期二 12:00:00 */
|
||
/* 存储顺序:秒、分、时、日、月、周、年(BCD 码) */
|
||
uchar TIME[7] = {0, 0, 0x12, 0x01, 0x01, 0x02, 0x13};
|
||
|
||
/******************************************************************************
|
||
* 函数名:Ds1302Write
|
||
* 功能:向 DS1302 写入一字节数据(先写地址,再写数据)
|
||
* 输入:addr = 寄存器地址,dat = 要写入的数据
|
||
* 输出:无
|
||
* 时序:RST 置高 → 写入 8 位地址(低位在前)→ 写入 8 位数据(低位在前)→ RST 置低
|
||
******************************************************************************/
|
||
void Ds1302Write(uchar addr, uchar dat)
|
||
{
|
||
uchar n;
|
||
|
||
RST = 0;
|
||
_nop_();
|
||
|
||
SCLK = 0; /* 时钟先置低 */
|
||
_nop_();
|
||
RST = 1; /* 使能 DS1302 */
|
||
_nop_();
|
||
|
||
for(n = 0; n < 8; n++) /* 发送 8 位地址(低位在前) */
|
||
{
|
||
DSIO = addr & 0x01; /* 输出当前位 */
|
||
addr >>= 1;
|
||
SCLK = 1; /* 时钟上升沿,DS1302 锁存数据 */
|
||
_nop_();
|
||
SCLK = 0;
|
||
_nop_();
|
||
}
|
||
|
||
for(n = 0; n < 8; n++) /* 发送 8 位数据(低位在前) */
|
||
{
|
||
DSIO = dat & 0x01;
|
||
dat >>= 1;
|
||
SCLK = 1;
|
||
_nop_();
|
||
SCLK = 0;
|
||
_nop_();
|
||
}
|
||
|
||
RST = 0; /* 结束通信 */
|
||
_nop_();
|
||
}
|
||
|
||
/******************************************************************************
|
||
* 函数名:Ds1302Read
|
||
* 功能:从 DS1302 读取一字节数据(先写地址,再读数据)
|
||
* 输入:addr = 寄存器地址
|
||
* 输出:返回读取到的数据
|
||
* 时序:RST 置高 → 写入 8 位地址(低位在前)→ 读取 8 位数据(高位在前)→ RST 置低
|
||
******************************************************************************/
|
||
uchar Ds1302Read(uchar addr)
|
||
{
|
||
uchar n, dat, dat1;
|
||
|
||
RST = 0;
|
||
_nop_();
|
||
|
||
SCLK = 0; /* 时钟先置低 */
|
||
_nop_();
|
||
RST = 1; /* 使能 DS1302 */
|
||
_nop_();
|
||
|
||
for(n = 0; n < 8; n++) /* 发送 8 位地址(低位在前) */
|
||
{
|
||
DSIO = addr & 0x01;
|
||
addr >>= 1;
|
||
SCLK = 1;
|
||
_nop_();
|
||
SCLK = 0; /* 下降沿后 DS1302 输出数据 */
|
||
_nop_();
|
||
}
|
||
_nop_();
|
||
|
||
for(n = 0; n < 8; n++) /* 读取 8 位数据(高位在前) */
|
||
{
|
||
dat1 = DSIO; /* 采样数据线 */
|
||
dat = (dat >> 1) | (dat1 << 7); /* 高位在前,依次移入 */
|
||
SCLK = 1;
|
||
_nop_();
|
||
SCLK = 0;
|
||
_nop_();
|
||
}
|
||
|
||
RST = 0; /* 结束通信 */
|
||
_nop_();
|
||
|
||
SCLK = 1; /* 确保时序完整 */
|
||
_nop_();
|
||
DSIO = 0;
|
||
_nop_();
|
||
DSIO = 1;
|
||
_nop_();
|
||
|
||
return dat;
|
||
}
|
||
|
||
/******************************************************************************
|
||
* 函数名:Ds1302Init
|
||
* 功能:初始化 DS1302 时钟芯片
|
||
* 输入:无
|
||
* 输出:无
|
||
* 说明:检查秒寄存器的 CH 位。如果 CH=1 表示时钟停止(首次上电),
|
||
* 则关闭写保护并写入默认时间;如果 CH=0 表示时钟已在运行,跳过初始化。
|
||
******************************************************************************/
|
||
void Ds1302Init()
|
||
{
|
||
uchar n;
|
||
uchar sec;
|
||
|
||
sec = Ds1302Read(0x81); /* 读取秒寄存器,检查 CH 位(最高位) */
|
||
if(!(sec & 0x80)) /* CH=0:时钟正在运行,无需初始化 */
|
||
return;
|
||
|
||
/* CH=1:时钟停止,系统首次上电,写入默认时间 */
|
||
Ds1302Write(0x8E, 0x00); /* 关闭写保护 */
|
||
for(n = 0; n < 7; n++)
|
||
{
|
||
Ds1302Write(WRITE_RTC_ADDR[n], TIME[n]);
|
||
}
|
||
Ds1302Write(0x8E, 0x80); /* 开启写保护 */
|
||
}
|
||
|
||
/******************************************************************************
|
||
* 函数名:Ds1302ReadTime
|
||
* 功能:读取 DS1302 当前时间到 TIME 数组
|
||
* 输入:无
|
||
* 输出:无(结果存入全局 TIME 数组)
|
||
******************************************************************************/
|
||
void Ds1302ReadTime()
|
||
{
|
||
uchar n;
|
||
|
||
for(n = 0; n < 7; n++)
|
||
{
|
||
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
|
||
}
|
||
}
|