目次

RTC処理

 Arduinoで、次のRTC(Real Time Clock)を扱えたので
 備忘録として、残しておきます。



 回路は、次のようにプルアップ抵抗を入れて、Arduinoの
 IICバスに接続。



 最初は、IICバスを利用した独自関数を製作していました。

 WEBで検索すると、DS1307を扱うライブラリがあったので
 こちらでどの程度のことができるのかを調べることに。

 サンプルスケッチは、次のようになっています。

#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;

void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
}
void loop () {
    DateTime now = RTC.now(); 
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println(); 
    delay(1000);
}

 RTCをオブジェクトで扱えるようにし、クラス
 インスタンスのメソッドで、情報を引き出す
 仕様。

 RTCは、どこかで年月日時分秒を設定しないと
 使い物にならないので、それがどうなっている
 のかを調べました。

 C++のソースコードを読むのは面倒なので、ヘッダ
 ファイルの内容を見てみました。

// Code by JeeLabs http://news.jeelabs.org/code/
// Released to the public domain! Enjoy!

// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
public:
    DateTime (uint32_t t =0);
    DateTime (uint16_t year, uint8_t month, uint8_t day,
                uint8_t hour =0, uint8_t min =0, uint8_t sec =0);
    DateTime (const char* date, const char* time);
    uint16_t year() const       { return 2000 + yOff; }
    uint8_t month() const       { return m; }
    uint8_t day() const         { return d; }
    uint8_t hour() const        { return hh; }
    uint8_t minute() const      { return mm; }
    uint8_t second() const      { return ss; }
    uint8_t dayOfWeek() const;

    // 32-bit times as seconds since 1/1/2000
    long secondstime() const;   
    // 32-bit times as seconds since 1/1/1970
    uint32_t unixtime(void) const;

protected:
    uint8_t yOff, m, d, hh, mm, ss;
};

// RTC based on the DS1307 chip connected via I2C and the Wire library
class RTC_DS1307 {
public:
  static uint8_t begin(void);
    static void adjust(const DateTime& dt);
    uint8_t isrunning(void);
    static DateTime now();
};

// RTC using the internal millis() clock, has to be initialized before use
// NOTE: this clock won't be correct once the millis() timer rolls over (>49d?)
class RTC_Millis {
public:
    static void begin(const DateTime& dt) { adjust(dt); }
    static void adjust(const DateTime& dt);
    static DateTime now();

protected:
    static long offset;
};

 クラスRTC_DS1307のパブリックメソッドに
 adjustがあるので、これで年月日時分秒を
 調整するのだと合点。

 クラスメソッドのadjustの引数が、DateTimeと
 クラスを使うので、DateTimeに関して眺めます。

    DateTime (uint16_t year, uint8_t month, uint8_t day,
                uint8_t hour =0, uint8_t min =0, uint8_t sec =0);

 年月日時分秒を指定するメソッドが定義されている
 ことから、初期化は以下の記述すればよいと判断。

      RTC.adjust(DateTime(year,month,day,hh,mm,ss));

 RTCに関係するコンストラクタ、メソッドを試験する
 ために、次のスケッチを定義しました。

#include <MsTimer2.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include "RTClib.h"

/* Real Timer Clock */
RTC_DS1307 RTC;

/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd(28,29,30,31,32,33);

/* Real Time Clock address */
#define RTC_ADRSX  0x68

#define OFF 0
#define ON  OFF+1

#define XINTERVAL 25
#define RSIZE     8

#define BSIZE     32
#define BSIZEX    52

#define LED_BIT        13
#define RST_WDT        26
#define ENTRY_LCD      28
#define ENTRY_LCD_EXIT 34
#define MON_OUT        46

/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
char get_asc(byte x);
byte get_hex(char x);
void show_value_byte(byte x);
void show_value_word(word x);

void init_led();
void init_rst_wdt();
void init_lcd();

void put_lcd_line(byte lx,char *ptr);
void put_lcd_open();

void getCDateTime();

/* variables */
boolean tflag ;
boolean uflag ;
boolean xflag ;
boolean aflag ;

char sbuf[16] ;
byte sindex ;

char cmd ;

word year ;
byte month ;
byte day ;
byte hh ;
byte mm ;
byte ss ;

/* system timer counter */
byte xcnt ;
byte ycnt ;
byte zcnt ;

void setup()
{
  /* initialize serial port */
  Serial.begin(9600);  /* Firmware or Debug */
  rs_puts("Hello !");
  crlf();
  show_help();
  sindex = 0 ;
  /* clear flags */
  tflag = OFF ;
  uflag = OFF ;
  aflag = OFF ;
  /* initialize port */
  init_led();
  init_rst_wdt();
  init_lcd();
  /* variables */
  xcnt = 0 ;
  ycnt = 0 ;
  zcnt = 0 ;
  /* enable RTC */
  Wire.begin();
  RTC.begin();
  if ( !RTC.isrunning() ) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  /* enable LCD */
  init_lcd();
  /* 25ms period */
  MsTimer2::set(XINTERVAL,update_trigger);
  /* enable */ 
  MsTimer2::start();
  /* WDT power control */
  digitalWrite(A3,LOW);
  pinMode(A3,OUTPUT);
  digitalWrite(A3,HIGH);
}

void loop()
{
  /* command interpreter (debug) */
  if ( uflag ) {
    /* clear flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* ? */
    if ( cmd == '?' ) { show_help(); }
    /* T set date and time */
    if ( cmd == 'T' ) {
      /* get information from receive buffer */
      getCDateTime();
      /* get information from receive buffer */
      RTC.adjust(DateTime(year,month,day,hh,mm,ss));
    }
    /* t show date and time */
    if ( cmd == 't' ) { 
      DateTime now = RTC.now();
      /* get values */
      year  = now.year();
      month = now.month();
      day   = now.day();
      hh    = now.hour();
      mm    = now.minute();
      ss    = now.second();
      /* */
      show_value_word(year); rs_putchar('/');
      show_value_byte(month); rs_putchar('/');
      show_value_byte(day); rs_putchar(' ');
      show_value_byte(hh); rs_putchar(':');
      show_value_byte(mm); rs_putchar(':');
      show_value_byte(ss); crlf();
    }
    /* L check LCD */
    if ( cmd == 'L' ) {
      put_lcd_line(0,"RTC TEST            ");
      put_lcd_line(1,"  LCD DISPLAY       ");
      put_lcd_line(2,"    MINOR TEST      ");
      put_lcd_line(3,"      CAPITAL LETTER");
    }
    /* l check LCD */
    if ( cmd == 'l' ) {
      put_lcd_line(0,"rtc test            ");
      put_lcd_line(1,"  lcd display       ");
      put_lcd_line(2,"                    ");
      put_lcd_line(3,"******* test *******");
    }
    /* start auto test */
    if ( cmd == 'A' ) { aflag = ON ; }
    /* ext auto test */
    if ( cmd == 'a' ) { aflag = OFF ; }
    /* new line */
    crlf();
  }
  /* timer handling */
  if ( tflag ) {
    /* clear flag */
    tflag = OFF ;
    /* flash LEDs */
    xflag = bitRead( zcnt , 0 );
    digitalWrite( LED_BIT , xflag );
    digitalWrite( MON_OUT , xflag );
    /* auto test */
    if ( aflag == ON && xflag == ON ) {
      DateTime cur = RTC.now();
      /* */
      show_value_word(cur.year()); rs_putchar('/');
      show_value_byte(cur.month()); rs_putchar('/');
      show_value_byte(cur.day()); rs_putchar(' ');
      show_value_byte(cur.hour()); rs_putchar(':');
      show_value_byte(cur.minute()); rs_putchar(':');
      show_value_byte(cur.second()); crlf();
    }
    /* increment */
    zcnt++ ;
  }
}

void update_trigger()
{
  if ( xcnt == 39 ) {
    xcnt = 0 ;
    tflag = ON ;
  }
  /* increment */
  xcnt++ ;
  /* WDT handling */
  digitalWrite( RST_WDT , LOW );
  if ( ycnt & ON ) { digitalWrite( RST_WDT , HIGH ); }
  /* increment */
  ycnt++ ;
}

void show_help()
{
  rs_puts("? help")                  ; crlf();
  rs_puts("T set date and time")     ; crlf();
  rs_puts("t show date and time")    ; crlf();
  rs_puts("L test LCD")              ; crlf();
  rs_puts("l test LCD")              ; crlf();
  rs_puts("A start auto clock show") ; crlf();
  rs_puts("a exit  auto clock show") ; crlf();
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

char get_asc(byte x)
{
  char result ;
  /* default */
  result = '0' ;
  /* judge */
  if ( x > 9 ) { result = x - 10 + 'A' ; }
  else         { result = x + '0' ;      }

  return result;
}

byte get_hex(char x)
{
  byte result ;
  /* default */
  result = 0 ;
  /* judge */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }

  return result;
}

void show_value_byte(byte x)
{
  char msg[4];
  byte xtmp ;
  /* copy */
  xtmp = x ;
  /* default */
  *(msg+3) = 0 ;
  /* separate */
  *(msg+2) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+1) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+0) = get_asc( xtmp % 10) ;
  /* zero surpress */
  if ( *(msg+0) == '0' ) {
    *(msg+0) = ' ';
  }
  /* show */
  rs_puts( msg );
}

void show_value_word(word x)
{
  char msg[6];
  word xtmp ;
  /* copy */
  xtmp = x ;
  /* default */
  *(msg+5) = 0 ;
  /* separate */
  *(msg+4) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+3) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+2) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+1) = get_asc( xtmp % 10) ; xtmp /= 10 ;
  *(msg+0) = get_asc( xtmp % 10) ;
  /* zero surpress */
  if ( *(msg+0) == '0' ) {
    *(msg+0) = ' ';
    if ( *(msg+1) == '0' ) {
      *(msg+1) = ' ';
      if ( *(msg+2) == '0' ) {
        *(msg+2) = ' ';
        if ( *(msg+3) == '0' ) {
          *(msg+3) = ' ';
        }
      }
    }
  }
  /* show */
  rs_puts( msg );
}

void init_led()
{
  /* set initial value */
  digitalWrite( LED_BIT , LOW );
  digitalWrite( MON_OUT , LOW );
  /* pin direction */
  pinMode( LED_BIT , OUTPUT );
  pinMode( MON_OUT , OUTPUT );
}

void init_rst_wdt()
{
  /* set initial value */
  digitalWrite( RST_WDT , LOW );
  /* pin direction */
  pinMode( RST_WDT , OUTPUT );
}

void init_lcd()
{
  byte ii ;
  /* pinMode */
  for ( ii = ENTRY_LCD ; ii < ENTRY_LCD_EXIT ; ii++ ) {
    pinMode(ii,OUTPUT);
  }
  /* 20 columns x 4 lines */
  lcd.begin( 20, 4 );
  lcd.clear();
  put_lcd_open();
}

void put_lcd_line(byte lx,char *ptr)
{
  /* judge */
  if ( lx > 3 ) return ;
  /* select line */
  lcd.setCursor(0,lx);
  /* put strings */
  lcd.print( ptr );
}

void put_lcd_open()
{
  put_lcd_line(0,"Hello , World !     ");
  put_lcd_line(1,"  RTC TEST          ");
  put_lcd_line(2,"    OTARU           ");
  put_lcd_line(3,"      HOKKAIDO      ");
}

void getCDateTime()
{
  byte ii ;
  byte jj ;
  byte xx[12];
  byte xtmp ;
  /* copy and convert */
  for ( ii = 1 ; ii < 13 ; ii++ ) {
    jj = ii - 1 ;
    *(xx+jj) = get_hex( *(sbuf+ii) );
  }
  /* deliver */
  for ( ii = 0 ; ii < 6 ; ii++ ) {
    jj = 2 * ii ;
    xtmp = xx[jj] * 10 + xx[jj+1] ;
    /* year */
    if ( ii == 0 ) { year = xtmp ; }
    /* month */
    if ( ii == 1 ) { month = xtmp ; }
    /* day */
    if ( ii == 2 ) { day = xtmp ; }
    /* hh */
    if ( ii == 3 ) { hh = xtmp ; }
    /* mm */
    if ( ii == 4 ) { mm = xtmp ; }
    /* day */
    if ( ii == 5 ) { ss = xtmp ; }
  }
}

/* receive interrupt (debug) */
void serialEvent()
{
  char ch;

  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 端末ソフトTeraTermで、年月日時分秒の設定と
 読み出しをすると、次のようになりました。



 年月日時分秒の設定と読み出しを、1文字の
 コマンドで実現できてます。

 クラスメソッドの使い方は、正しいと判断できました。


目次

inserted by FC2 system