/****************************************************************************** * 文件名: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]); } }