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時間で時刻を設定することができる
コメント