Pyrrhus 发表于 2015-1-6 14:57:16

对DS1302时钟模块的补正

    DS1302时钟模块由于有些缺陷,所以用的不多,很多人情愿用DS3231,
而事实上稍微进行一些补正,其实也堪一用。

    DS1302时钟模块最大的2个问题,
第一是时间不准,需要经常校准,GPS授时不实用(总不能经常拿出屋外对时吧),
网络授时代价太高,只有电波授时才是最理想的方式,等以后有空研究一下。
而串口或按键设时太繁琐,我想到了一个偷懒方式,把编译时间设到DS1302上。
而且DS1302里有31byte的RAM,在设时间成功以后把时间也保存到RAM里,
那么只有编译时间有变化才把时间设进去,防止Reset时也设时间。

第二是星期单独设置,如果星期设错,那就会一直错下去,
而事实上根据年月日通过蔡勒公式是可以计算出来的,
所以我在设星期前补了一段星期算法,当然,这个算法只适用1582年10月15日以后,
当时钟足够了。

下面就是程序:
// DS1302_LCD5110 (C)2015 Pyrrhus
// 使用DS1302模块显示实时时间在Nokia5110上
//
// DS1302:CE pin    -> Arduino Digital 6
//          I/O pin   -> Arduino Digital 5
//          SCLK pin-> Arduino Digital 4
// LCD:   SCK       -> Arduino Digital 8
//          MOSI      -> Arduino Digital 9
//          DC      -> Arduino Digital 10
//          RST       -> Arduino Digital 11
//          CS      -> Arduino Digital 12
#include <LCD5110_Graph.h>
#include <DS1302.h>

DS1302 rtc(6, 5, 4);            // Init the DS1302
LCD5110 myGLCD(8,9,10,11,12);   // Init the LCD5110
extern uint8_t SmallFont[];
Time t;

void setup()
{
uint8_t h,m,s,dow;

// Set the clock to run-mode, and disable the write protection
rtc.halt(false);
rtc.writeProtect(false);

myGLCD.InitLCD(60);
myGLCD.clrScr();
myGLCD.setFont(SmallFont);

// 取出上次保存到DS1302的RAM里的时分秒
h=rtc.peek(0);
m=rtc.peek(1);
s=rtc.peek(2);
// 如果与编译时间不同的话就将编译时间设到DS1302上,并将时分秒保存到RAM中
DateTime(__DATE__, __TIME__);
if(t.hour!=h || t.min!=m || t.sec!=s) {
    rtc.setDate(t.date, t.mon, t.year);
    rtc.setTime(t.hour, t.min, t.sec);
    dow = dayOfWeek(t.year, t.mon, t.date);
    dow = (dow == 0) ? 7 : dow;
    rtc.setDOW(dow);
    rtc.poke(0, t.hour);
    rtc.poke(1, t.min);
    rtc.poke(2, t.sec);
}
}

void loop()
{
myGLCD.print(rtc.getDateStr(FORMAT_LONG,FORMAT_BIGENDIAN,'/'), 0, 0);
myGLCD.print(rtc.getDOWStr(FORMAT_SHORT), 66, 0);
myGLCD.print(rtc.getTimeStr(), 0, 16);
myGLCD.update();

delay(1000);
}

// 将2位字符串转成整数
static uint8_t conv2d(const char *p)
{
uint8_t v = 0;
if('0' <= *p && *p <= '9') v = *p - '0';
return (10*v + (*++p - '0'));
}

// 计算星期,0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
static uint8_t dayOfWeek(uint16_t year, uint8_t month, uint8_t date)
{
if(month < 3) {
    year -= 1;
    month += 12;
}
uint8_t c = year / 100;
uint8_t y = year - 100 * c;
uint8_t w = (c>>2) - 2*c + y + (y>>2) + (26 * (month + 1)/10) + date - 1;

return ((w+21) % 7);
}

// 将编译时间转换成DS1302时间格式
// sample input: date="Dec 26 2009", time="12:34:56"
void DateTime(const char *date, const char *time)
{
t.year = conv2d(date + 7);
t.year = t.year*100 + conv2d(date + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date) {
case 'J': t.mon = date == 'a' ? 1 : t.mon = date == 'n' ? 6 : 7; break;
case 'F': t.mon = 2; break;
case 'A': t.mon = date == 'r' ? 4 : 8; break;
case 'M': t.mon = date == 'r' ? 3 : 5; break;
case 'S': t.mon = 9; break;
case 'O': t.mon = 10; break;
case 'N': t.mon = 11; break;
case 'D': t.mon = 12; break;
}
t.date = conv2d(date + 4);
t.hour = conv2d(time);
t.min = conv2d(time + 3);
t.sec = conv2d(time + 6);
}

suoma 发表于 2015-1-8 18:01:38

谢谢分享学习一下

微风青草 发表于 2015-5-31 10:06:57

求DS1302库函数。我的是Arduino1.0.5.走时不准啊。
页: [1]
查看完整版本: 对DS1302时钟模块的补正