极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 13238|回复: 2

对DS1302时钟模块的补正

[复制链接]
发表于 2015-1-6 14:57:16 | 显示全部楼层 |阅读模式
    DS1302时钟模块由于有些缺陷,所以用的不多,很多人情愿用DS3231,
而事实上稍微进行一些补正,其实也堪一用。

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

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

下面就是程序:
[pre lang="arduino" line="1" file="DS1302-2"]// 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[0]) {
  case 'J': t.mon = date[1] == 'a' ? 1 : t.mon = date[2] == 'n' ? 6 : 7; break;
  case 'F': t.mon = 2; break;
  case 'A': t.mon = date[2] == 'r' ? 4 : 8; break;
  case 'M': t.mon = date[2] == '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);
}
[/code]
回复

使用道具 举报

发表于 2015-1-8 18:01:38 | 显示全部楼层
谢谢分享学习一下
回复 支持 反对

使用道具 举报

发表于 2015-5-31 10:06:57 | 显示全部楼层
求DS1302库函数。我的是Arduino1.0.5.走时不准啊。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-17 06:15 , Processed in 0.036961 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表