|
|
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] |
|