RTCとは

データロガーには、データそのものとともに、データを取得した時刻を記録する機能が必要です。Arduinoには時計が内蔵されていますが、電源が切れるたびにリセットされます(1970年1月1日などにタイムスリップします)。これでは不便なので、時計(RTC: Real Time Clock)モジュールを取り付けます。このRTCモジュールにはコイン電池をつなぎ、常に給電させておきます。RTCモジュール自体は非常に省電力なので、コイン電池で数年持ちます。

 

 

 

RTCにはいろいろなモデルがありますが、DS1307やDS3231がよく使われるようです。前者はArduino IDEに最初から入っているRTC.hライブラリで動かせます。後者には、管理人は別のライブラリを使っています。以下からダウンロードしてください。

https://github.com/JChristensen/DS3232RTC

DS3232とありますが、DS3231にも使えます。このGitHubというサイトは、いろいろなライブラリやソフトのレポジトリーサイトです。”Clone or download”をクリックすると(Internet Explorerには非対応になったようです。ChromeやEdgeを使ってください)、zipファイルとしてダウンロードできるので解凍してください。DS3232RTC-masterというフォルダになるので、これを("-master”をフォルダ名からとるのが通常のようですが、残しておいても動作には問題ありません)Arduinoのlibrariesフォルダに移します。このフォルダの場所ですが、Windows 10で言われるがままArduino IDEをインストールした場合、以下にあると思います。

C:\Program Files (x86)\Arduino\libraries

これでこのライブラリが使えるようになります。

 

ここからはDS3231を使って説明します。このモジュールはI2C通信で動きます。第5回で説明したように、I2C通信用のモジュールは、すべて固有のアドレスをもっています。このRTC(DS3231)のアドレスは0x68です。これをプログラム(スケッチ)に書く必要はないのですが(先ほどダウンロードしたライブラリのプログラムの中にすでに書いてあります。” DS3232RTC.h”の49行目を見てみてください)、他にI2Cモジュールをつなぐ場合、競合しないように注意が必要です。

 

さて、前回までの作品に、以下のようにDS3231をつないでください。ここで、ブレッドボードを使います。いろいろ部品をつないでいくと、Arduino上のVcc(5V)やGNDの端子が足りなくなることに気付くと思います。このようにつなぐと、第4回で説明したように、一番上の列が全てGND、上から二番目の列が全て5Vとつながります。

 

 

 

 ここでSDA・SCLという端子がありますが、このSDAがデータ送受信、SCLがクロックに使われます。Arduino UNOの場合、SDA・SCLと書いた端子があるので、そこに繋げばいいですし、あるいはそれぞれA4・A5につないでも構いません。UNOではA4・A5がI2C通信用端子を兼ねています。

 

DS3231(を実装したモジュール)にはコイン電池をはめる部分があるので、ここにCR2032を入れれば計時が始まります。CR2032はTOSHIBAなど一流ブランドなら1個200円くらい、100円ショップなら2個で100円です。

 

 

参考1:

電子工作を始めたころに他のサイトで知ったのですが、実はこのモジュール、VCC端子がコイン電池の端子につながっているそうです。つまり、Arduinoへの給電から電気をおすそ分けしてもらって、コイン電池を充電しようという設計になっているそうです。ただし、CR2032は充電池ではないので、この状態が続くと電池が「重くなる」そうで、液漏れなどの危険もあるとのこと(つないですぐにどうこうなるというわけではなさそうですし、公式には充電池ではない電池も、実は充電が全くできないわけではないのですよね)。実は、コイン充電池であるLIR2032を使うことを想定しているようです。このLIR2032、数年前はなぜか非常に手に入れづらく、Amazonにすらありませんでした。しかしこのブログを書いたのをきっかけに検索したら、しこたま売っているようです。どういう事情があったのでしょう?とにかく、LIR2032を買えばよいのですが、CR2032を使う場合(100円ショップで買えるのは便利)、以下のようにパターンカット(カッターでガリガリと基盤上の結線を断線させる)すればよいらしいです。

 

 

いずれにしても、このブログの終盤でつくるロガーでは、電源は1時間に数秒しか入らなくなるので、このようなことをしなくてもコイン電池を過充電する心配はありませんが。

 

参考2:

ZS-042と名前のついたこのDS3231のブレークアウトモジュール、両端にVcc・GND・SCL・SDAが1組ずつありますが、それぞれ基板上でつながっているようで、どちら側にあるものを使っても問題ありません。

 

RTCの時間合わせをする

ここまでで物理的な作業は終わりで、ここからはスケッチの話になります。まずはRTCの時間合わせをしないといけないので、時間を合わせる以下のプログラムを書き込みます。ここでは2020年2月9日23:08:00に合わせています。

 

#include <ds3232rtc.h>    //http://github.com/JChristensen/DS3232RTC
#include <time.h>         //http://www.arduino.cc/playground/Code/Time  
#include <timelib.h>
#include <wire.h>         //http://arduino.cc/en/Reference/Wire (included with Arduino IDE)

void setup(void)
{
    Serial.begin(9600);
    while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
    }
    
    /* ----- Initialisation of time ----- */
    setTime(23, 8, 00, 9, 2, 2020);   // set the system time in Arduino [Hour, Min, Sec, Day, Month, Year]
    RTC.set(now());   // set the RTC time according to Arduino (Need to activate only when the RTC module has to be re-set)
     
    if(timeStatus() != timeSet) 
       Serial.println("Unable to sync with the RTC");
    else
       Serial.println("RTC has set the system time");
    
    delay(1000);
}

void loop(void)
{

}

 

このあと、本来入れたいプログラムを迅速に入れます。「迅速に」というのは以下の理由です。Arduinoは、電源が入ると、メモリに書き込んであるスケッチを実行します。ここまでの時点で、メモリには「今、何月何日何時何分何秒に設定しろ」という上記のスケッチが入っています。これに、本来入れたいプログラムを入れようとしてPCにつなぐと、その瞬間に給電され、時間設定のプログラムがまた走り、上記の時間にリセットされてしまうからです。ですので、本来入れたいプログラムを入れる時間をあらかじめ見計らって時間を先に設定しておかなければなりません。言いたいことわかります?

 

前回からの続き:時間をRTCから読み、電池の電圧を、測った時間とともにSDカードに記録

上記のスケッチに続き、以下のスケッチを入れて下さい。前回までの電圧を読んでSDカードに記録する機能(第5回:1チャネルだけ電圧を読み込むもの)に、時間の書き込みも加えたものです。今回書き加えた部分を赤く示しています。また、青字の部分も、前回のスケッチを修正することで、SDカードに書き込まれるデータの改行を減らしています。

 

#include <SPI.h>
#include <SD.h>
#include <DS3232RTC.h>    //http://github.com/JChristensen/DS3232RTC
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>

const int chipSelect = 10; // Arduino UNOでは10、Arduino MEGAでは53

void setup(void)
{
    /* ----- Setting up serial communication with PC ------ */
    /* ここでUSBを介してPCとシリアル通信を始める。9600はシリアル通信のボーレート */
    Serial.begin(9600);
    while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
    //何らかの問題があってシリアルポートに接続できないときは、このループにトラップされる    
    }

    /* ----- Initialisation of SD card ------ */
    Serial.print("Initializing SD card...");
     //see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
       Serial.println("Card failed, or not present");
       // don't do anything more:
      return;
    }
    Serial.println("card initialized.");
    
    /* ----- Setting time based on RTC ----- */
    setSyncProvider(RTC.get);   // ここでRTCの時刻をもとにArduinoの時刻を合わせる
    if(timeStatus() != timeSet) 
        Serial.println("Unable to sync with the RTC");
    else
        Serial.println("RTC has set the system time");
    delay(1000);
}

void loop(void)
{
    int ainput; //読み取ったbit数:intは整数
    float vinput; //bit数を電圧に変換したもの:floatは浮動小数点数

    /* データの読み取り */
    ainput=analogRead(A0); //ピンA0から電圧をbitとして読む
    vinput=5000.0*ainput/1024; //上記を電圧mVに変換
    //ここで5000.0でなく5000とすると、整数としてvinputにキャストされてしまう)
    //粗い値になったり、おかしな値になったりする

    /* PCのシリアルモニタに表示 */
    Serial.print(year());Serial.print("/");Serial.print(month());Serial.print("/");Serial.print(day());Serial.print(" ");
    Serial.print(hour());Serial.print(":");Serial.print(minute());Serial.print(":");Serial.print(second());Serial.println("");
    Serial.print(ainput);
    Serial.println(" bit"); //" bit"と表示、printではなくprintlnとすることで改行する
    Serial.print(vinput);
    Serial.println(" mV"); //" mV"と表示、printではなくprintlnとすることで改行する

    /* SDカードに書き込み */
    File dataFile = SD.open("datalog.csv", FILE_WRITE);
    if (dataFile)
    {
      dataFile.print(year());dataFile.print("/");dataFile.print(month());dataFile.print("/");dataFile.print(day());dataFile.print(" ");
      dataFile.print(hour());dataFile.print(":");dataFile.print(minute());dataFile.print(":");dataFile.print(second());dataFile.print("  ");
      dataFile.print(ainput);
      dataFile.print(" bit, "); //" bit"と表示
      dataFile.print(vinput);
      dataFile.println(" mV"); //" mV"と表示、printではなくprintlnとすることで改行する
    }    
    dataFile.close();
    
    delay(2000); //2000ミリ秒=2秒の停止
}

 

この結果、シリアルモニタ―を開くと

 

SDカードには

 

今回はここで終わりにしましょう。このDS3232には、SQW端子を通してAlarm interruptということをできる機能があります。これは、Arduinoをスリープさせて省電力モードに入れたときに、決まった時間に叩き起こす、目覚まし時計の機能で、非常に便利なものです。Arduinoのスリープの話もしないといけないので、次回以降にします。

 

1回を更新するのがだいぶ大変になってきました。正直、この季節にやるものではないです。