NTPサーバーから正確な時間を取得する
時間を知るためにはいろいろ方法があります。
マイコン内でカウンタを設けて時間を計ったり、リアルタイムクロック(RTC)モジュールで時間を計ったり、JSTグループのサーバーにアクセスして時間を読み取ったり、、、など
その中でも正確に時間の測定が出来るNTP(Network Time Protocol)にアクセスして時刻を取得したいと思います。
マイコンはArduino環境で動いてWifiが使えれば何でもいいです。本記事ではESP32を使用しました。
NTP(Network Time Protocol)
NTPとはネットワーク上に接続されている機器たちの時刻同期に用いられるプロトコルです。さらにNTPはネットワークの送信/受信の時間を考慮することで遅延時間を推測し誤差の少ない時刻同期を実現することが出来ます。
公開されているNTPサーバーは何種類かありますが、今回は【情報通信研究機構】の公開NTPサーバーを使用していきますね。
NTPサーバー名:ntp.nict.jp
ちなみに、送受信の時間を考慮して同期を取っているといっても全く誤差がない訳ではなく自身のネット環境によっては数ミリ~数百ミリまでは誤差が出る可能性があると書いてあります。
時刻取得コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <WiFi.h> #include "time.h" const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASS"; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 3600; const int daylightOffset_sec = 0; void printLocalTime() { struct tm timeinfo; if(!getLocalTime(&timeinfo)){ Serial.println("Failed to obtain time"); return; } Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); } void setup() { Serial.begin(115200); //connect to WiFi Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" CONNECTED"); //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); //disconnect WiFi as it's no longer needed WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop() { delay(1000); printLocalTime(); } |
実はNTPサーバーから時刻を同期させるコードはESP32の標準ライブラリの中にサンプルコードとして存在します。
このコードからいじる箇所は5つです。
変更箇所
- YOUR SSIDに自身のWifiルーターのSSIDを入れる
- YOUR_PASSに自身のWifiルーターのPASSを入れる
- pool.ntp.orgにntp.nict.jpを入れる
- 時刻オフセットを9時間とする。const long gmtOffset_sec = 3600*9;とする
- サマータイムを0とする。const int daylightOffset_sec = 0;
これでコードを走らせれはシリアルモニタに時刻が表示れるはずです。
ちなみにこのサンプルコードは<time.h>ライブラリの上に成り立っていまして、”tm”という構造体の中に時刻情報が格納されております。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; #ifdef __TM_GMTOFF long __TM_GMTOFF; #endif #ifdef __TM_ZONE const char *__TM_ZONE; #endif }; |
そして、Arduinoコード上でtimeinfoという実体を持たせています。なので、時刻の要素(時, 分, 秒)を取り出す場合はtimeinfo.tm_secの様にtmのメンバを呼び出すことで使用可能となります。ポインタを使用して取り出しても構いません。
1 2 3 4 5 6 |
tm *p1; p1 = &timeinfo;//実体のアドレス Serial.print("time:");Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); Serial.print("class:");Serial.println(timeinfo.tm_sec); Serial.print("pointer:");Serial.println(p1->tm_sec); Serial.println(""); |
おわりに
今回はNTPサーバーにアクセスして標準時刻と同期させる方法を紹介いたしました。
ESP32内のサンプルにあるために値を表示させる分には問題なくできると思います。最後にtimeinfoから各時刻要素を取り出す方法を書きました。個別にLCDや7セグLED(シリアル通信タイプのモジュールが使いやすいと思います)に表示するときに使ってみてください。
今回はここまでで終わりたいと思います。
ではでは~
コメント