作者:BrightBell 时间:2016年1月初
单片机:STC89C52RC            时钟芯片:DS1302
测温元件:DS18B20            显示元件:LCD1602
信息保持:STC单片机内部EEPROM
备注:
1.DS1302没有第二电源,掉电不走时,误差 < 1s/5天
2.时间、背光开关时间、蜂鸣器整点报时时间、LCD背光亮度、按键音皆可设置
3.长按KEY0马上开/关LCD背光,长按KEY1进入系统设置界面,长按KEY2进入时间设置界面
4.每3秒读取一次DS18B20温度
5.每一小时更新一次EEPROM中的时间信息,重新设置时间后马上更新
6.进行一次系统设置后,马上更新EEPROM中的系统设置信息,下次启动时会先加载


部分源文件预览:
#ifndef _DS1302_H_
#define _DS1302_H_
void DS1302ByteWrite(unsigned char dat) //向DS1302写入一个字节
{
 unsigned char mask; 
 for(mask=0x01; mask!=0; mask<<=1) //低位在先
 {
 if((mask&dat) != 0)
 DS1302IO = 1;
 else
 DS1302IO = 0;
 DS1302CK = 1;
 DS1302CK = 0;
 }
 DS1302IO = 1;
}
unsigned char DS1302ByteRead(void) //从DS1302读取一个字节
{
 unsigned char mask;
 unsigned char dat = 0;
 for(mask=0x01; mask!=0; mask<<=1)
 {
 if(DS1302IO != 0)
 dat |= mask;
 DS1302CK = 1;
 DS1302CK = 0;
 }
 return dat;
}
void DS1302SingleWrite(unsigned char reg, unsigned char dat) //写入DS1302的某一寄存器
{
 DS1302CE = 1;
 DS1302ByteWrite((reg<<1)|0x80);
 DS1302ByteWrite(dat);
 DS1302CE = 0;
}
unsigned char DS1302SingleRead(unsigned char reg) //读取DS1302的某一寄存器
{
 unsigned char dat;
 DS1302CE = 1;
 DS1302ByteWrite((reg<<1)|0x81);
 dat = DS1302ByteRead();
 DS1302CE = 0;
 return dat;
}
void DS1302BurstWrite(unsigned char *dat) //Brust模式写入时间信息
{
 unsigned char i;
 DS1302CE = 1;
 DS1302ByteWrite(0xBE);
 for(i=0; i<8; i++)
 {
 DS1302ByteWrite(dat[i]);
 }
 DS1302CE = 0;
}
void DS1302BurstRead(unsigned char *dat) //Brust模式读出时间信息
{
 unsigned char i;
 DS1302CE = 1;
 DS1302ByteWrite(0xBF);
 for(i=0; i<8; i++)
 {
 dat[i] = DS1302ByteRead();
 }
 DS1302CE = 0;
}
//欲写入的是十进制的时间信息,不是BCD码,已进行转换
struct TIME Bcd1302ToDec(struct TIME *time)
{
 struct TIME dectime;
 dectime.year = (time->year >> 4) * 10;
 dectime.year = (time->year & 0x0F) + dectime.year;
 dectime.mon = (time->mon >> 4) * 10;
 dectime.mon = (time->mon & 0x0F) + dectime.mon;
 dectime.day = (time->day >> 4) * 10;
 dectime.day = (time->day & 0x0F) + dectime.day;
 dectime.hour = (time->hour >> 4) * 10;
 dectime.hour = (time->hour & 0x0F) + dectime.hour;
 dectime.min = (time->min >> 4) * 10;
 dectime.min = (time->min & 0x0F) + dectime.min;
 dectime.sec = (time->sec >> 4) * 10;
 dectime.sec = (time->sec & 0x0F) + dectime.sec;
 
 dectime.week = time->week & 0x0F;
 
 return dectime;
}
//获取到的是十进制的时间信息,不是BCD码,获取后已进行转换
void GetRealTime(struct TIME *time) //获取时间信息,并保存在时间结构体中
{
 unsigned char buf[8];
 struct TIME temp;
 DS1302BurstRead(buf);
 temp.year = buf[6];
 temp.mon = buf[4];
 temp.day = buf[3];
 temp.hour = buf[2];
 temp.min = buf[1];
 temp.sec = buf[0];
 temp.week = buf[5];
 
 *time = Bcd1302ToDec(&temp); //将BCD码转为十进制
}
struct TIME DecToBcd1302(struct TIME *time)
{
 struct TIME bcdtime;
 bcdtime.year = (time->year / 10 % 10) * 16;
 bcdtime.year = (time->year % 10) + bcdtime.year;
 bcdtime.mon = (time->mon / 10 % 10) * 16;
 bcdtime.mon = (time->mon % 10) + bcdtime.mon;
 bcdtime.day = (time->day / 10 % 10) * 16;
 bcdtime.day = (time->day % 10) + bcdtime.day;
 bcdtime.hour = (time->hour / 10 % 10) * 16;
 bcdtime.hour = (time->hour % 10) + bcdtime.hour;
 bcdtime.min = (time->min / 10 % 10) * 16;
 bcdtime.min = (time->min % 10) + bcdtime.min;
 bcdtime.sec = (time->sec / 10 % 10) * 16;
 bcdtime.sec = (time->sec % 10) + bcdtime.sec;
 
 bcdtime.week = time->week % 10;
 
 return bcdtime;
}
void SetRealTime(struct TIME *time) //通过时间结构体设置时间
{
 unsigned char buf[8];
 struct TIME temp;
 temp = DecToBcd1302(time);
 buf[7] = 0;
 buf[6] = temp.year;
 buf[5] = temp.week;
 buf[4] = temp.mon;
 buf[3] = temp.day;
 buf[2] = temp.hour;
 buf[1] = temp.min;
 buf[0] = temp.sec;
 DS1302BurstWrite(buf);
}
void InitDS1302(void) //初始化DS1302
{
 unsigned char dat;
 struct TIME eepromtime;
 DS1302CE = 0;
 DS1302CK = 0;
 dat = DS1302SingleRead(0);
 if((dat & 0x80) != 0) //检测时间在掉电时是否停止过,停1走0,如果停过就从新写入初始化时间
 {
 GetE2promTime(&eepromtime); //停止过,获取EEPROM里的时间
 DS1302SingleWrite(7, 0x00); //撤销保护
 SetRealTime(&eepromtime);
 }
 
 lcdShowStr(0, 0, "20 - -");
 lcdShowStr(3, 1, ": :"); 
}
void lcdShowWeek(unsigned char x, unsigned char y, unsigned char week)
{
 unsigned char str[5];
 lcdShowStr(x-4, y, "week");
 str[0] = week % 10 + '0';
 str[1] = '\0';
 lcdShowStr(x, y, str);
}
void RefreshTime(struct TIME *time)
{
 static unsigned char dayBF = 88;
 if(dayBF != time->day) //日期发生变化,更新年月日周
 {
 lcdShowNum(2, 0, time->year);
 lcdShowNum(5, 0, time->mon);
 lcdShowNum(8, 0, time->day);
 lcdShowWeek(15,0, time->week);
 dayBF = time->day;
 }
 lcdShowNum(1, 1, time->hour);
 lcdShowNum(4, 1, time->min);
 lcdShowNum(7, 1, time->sec);
}
void HourlyWork(struct TIME *time) //小时事件
{
 static char hourBF = 88;
 static char lightlevelBF = 3;
 if(time->hour != hourBF) //时有变
 { 
 if(time->hour==lcdlighton) //判断是否有背光开关
 {
 lcdlight = 0;
 if(lightlevelBF != 0)
 lcdlightlevel = lightlevelBF;
 else
 lcdlightlevel = 4;
 }
 else if(time->hour==lcdlightoff) //判断是否有背光开关
 {
 lcdlight = 1;
 lightlevelBF = lcdlightlevel;
 lcdlightlevel = 0;
 }
 
 if((time->hour>=ZDBSbegin)&&(time->hour<=ZDBSend))
 {
 if(hourlybuzz != 0) //整点报时开
 flagZD = 1;
 }
 
 SaveTimeToE2prom(time); //每小时更新EEPROM里的时间信息
 
 hourBF = time->hour; //更新备份值
 }
}
void LedWaterShow() //流水灯效果
{
 static unsigned char ledshow = 0x01;
 static bit dir = 0;
 ledDB = ledshow;
 if(dir == 0)
 {
 ledshow = ledshow << 1;
 if(ledshow == 0x00)
 {
 dir = 1;
 ledshow = 0x40;
 }
 }
 else
 {
 ledshow = ledshow >> 1;
 if(ledshow == 0x00)
 {
 dir = 0;
 ledshow = 0x02;
 }
 }
}
/*******************************************************************************
 补偿值计算方法:当X秒后时间慢Y秒,则:实减=X/当前值;应减=实减-Y; 补偿值=X/应减
********************************************************************************/
void TimeBuChang(struct TIME *time)
{
 static char flagBC = 0;
 static unsigned int BCcnt = 0;
 static struct TIME BCtime;
 if(flagBC != 0)
 {
 flagBC = 0;
 SetRealTime(&BCtime); //写入上一秒时间,相当于减一秒
 }
 
 BCcnt++;
 if(BCcnt > secBuChang) //每X秒减1秒 
 {
 timemenu = 88; //禁止时间更新
 BCcnt = 0;
 BCtime = *time; //备份上一秒时间
 flagBC = 1;
 timemenu = 0; //开时间更新
 }
}
void UpdateTime()
{
 static unsigned char secBF = 88;
 static unsigned int ds18b20cnt = 0;
 struct TIME buftime; //从DS1302中读取出来的值
 GetRealTime(&buftime);
 if(buftime.sec != secBF)
 {
 RefreshTime(&buftime);
 secBF = buftime.sec;
 
 ds18b20cnt++;
 if(ds18b20cnt > GetTempSpace)
 {
 ds18b20cnt = 0;
 RefreshTemp();
 }
 
 HourlyWork(&buftime);
 LedWaterShow();
 
 TimeBuChang(&buftime); //时间补偿
 }
}
void RefreshTimeNow()
{
 struct TIME buftime;
 GetRealTime(&buftime);
 lcdShowStr(0, 0, "20 - -");
 lcdShowStr(3, 1, ": :"); 
 lcdShowNum(2, 0, buftime.year);
 lcdShowNum(5, 0, buftime.mon);
 lcdShowNum(8, 0, buftime.day);
 lcdShowNum(1, 1, buftime.hour);
 lcdShowNum(4, 1, buftime.min);
 lcdShowNum(7, 1, buftime.sec);
 lcdShowWeek(15,0, buftime.week);
 if(hourlybuzz != 0)
 lcdShowImage(0, 1, image0, 0);
 else
 lcdShowStr(0, 1, " ");
 lcdShowImage(15, 1, image1, 1);
}
#endif
完整版下载: