Arduino UNO R4で、RTCをNTPから取得した時刻に設定する

Arduino UNO R4

RTCをNTPから取得した時刻に設定する

以前、インターネット上のNTPサーバから時刻を取得する実験を行いました。この時刻を用いてRTCの時刻合わせを行う方法を試してみましょう。

プログラム

#include "WiFiS3.h"
#include "RTC.h"

// 無線LAN接続情報は別ファイルに移した
#include "arduino_secrets.h"
char ssid[] = _SSID;
char pass[] = _PASS;

// NTPアクセス関係
char ntpServer[] = "pool.ntp.org";
int ntpPort = 123;

// 送受信用バッファの用意
const int NTP_PACKET_SIZE = 48;
byte buffer[NTP_PACKET_SIZE];

// クライアントのインスタンスの生成
WiFiUDP client;

void setup(){
  // シリアルインターフェイスの初期化
  Serial.begin(9600);
  delay(1000);

  // WiFiモジュールの存在確認
  if(WiFi.status() == WL_NO_MODULE){
    Serial.println("WiFiモジュールがありません");
    while(true);
  }

  // WiFiファームウェアバージョンの確認
  String fv = WiFi.firmwareVersion();
  if(fv < WIFI_FIRMWARE_LATEST_VERSION){
    Serial.println("ファームウェアが最新のものではありません");
  }

  // 無線LANへの接続
  Serial.print("接続中...");
  while(true){
    if(WiFi.begin(ssid, pass) == WL_CONNECTED)break;
    Serial.print(".");
    delay(1000);
  }
  Serial.println("完了");

  // Arduinoに割り当てられたIPアドレスの確認
  Serial.print("IPアドレス:");
  Serial.println(WiFi.localIP().toString());

  // UDPポートを開く
  client.begin(ntpPort);

    // NTPサーバに対してリクエストを送信
  memset(buffer, 0, NTP_PACKET_SIZE);
  buffer[0] = 0b00001011;
  client.beginPacket(ntpServer, ntpPort);
  client.write(buffer, NTP_PACKET_SIZE);
  client.endPacket();

  // NTPサーバからのレスポンスを受信
  unsigned long transTime;
  while(true){
    if(client.parsePacket()){
      client.read(buffer, NTP_PACKET_SIZE);
      // 時刻(Transmit Timestamp)の取得
      transTime = buffer[40]<<24 | buffer[41]<<16 | buffer[42]<<8 | buffer[43];
      break;
    }
  }

  // RTC開始と時刻の設定
  RTC.begin();
  unsigned long unixTime = transTime - 2208988800L + 32400L;
  RTCTime time(unixTime);
  RTC.setTime(time);
}

void loop(){
  // 時刻の取得
  RTCTime currentTime;
  RTC.getTime(currentTime);

  char buffer[20];
  sprintf(buffer,"%04d/%02d/%02d %02d:%02d:%02d",
    currentTime.getYear(), ((int)currentTime.getMonth())+1, currentTime.getDayOfMonth(),
    currentTime.getHour(), currentTime.getMinutes(), currentTime.getSeconds());
  Serial.println(buffer);
  delay(1000);
}

※WiFi接続の記事を参考にして、arduino_secrets.h を作成してください。

プログラムの解説

NTPの実験のプログラムと、RTCの実験のプログラムを組み合わせたような内容です。どちらにもない部分のみ解説します。

RTCの開始と時刻の設定
  // RTC開始と時刻の設定
  RTC.begin();
  unsigned long unixTime = transTime - 2208988800 + 32400;
  RTCTime time(unixTime);
  RTC.setTime(time);

変数transTimeには、受信したNTPデータから取り出した『NTPサーバからの送信時刻』が入っています。これを用いてRTCの時刻を設定します。

実はRTCTimeクラスのコンストラクタの中には、Unix時間を引数として与えることができるものがあります。これを使えば非常に簡単です。

NTPが表す時刻は、1900年1月1日0時0分0秒からの経過時間(秒)
Unix時間は、1970年1月1日0時0分0秒からの経過時間(秒)

というわけで、NTPが表す時刻から70年分の秒数を引けばUnix時間になるのです。

1900年1月1日~1970年1月1日の間には、閏年が17回あることを考慮すると、

365×70 + 17 = 25,567 日

の日数があります。さらにこれを秒に直すと、

25,567×24×60×60 = 2,208,988,800 秒

となります。これをNTPが表す時刻から引き算すれば、Unix時間となります。

この例ではさらに9時間= 32,400 秒を足すことで、UST(協定世界時)からJST(日本標準時)に直しています。Arduino UNO R4のRTCには時差を表す設定値がないようなので…。

この計算を行っているのが、

  unsigned long unixTime = transTime - 2208988800L + 32400L;

の部分です。

こうして求めたUnix時刻を使ってRTCの時刻を設定します。

  RTCTime time(unixTime);
  RTC.setTime(time);

RTCTimeクラスのコンストラクタにunsigned long型の引数を与えると、それをUnix時刻として時刻を初期化します。あとはRTC.setTime()関数をつかってRTCに時刻を設定するだけです。

実行結果

このように、WiFiに接続すると自動的に時刻設定を行います。NTPサーバへの接続は最初の1回だけで、その後はRTCが時刻を刻んでいます。

まとめ

  • RTCTimeクラスは、Unix時間で時刻を設定することができる

コメント

タイトルとURLをコピーしました