ESP32をデフォルトのままで時計機能を使う

■ESP32をデフォルトのままで時計機能を使う

 ESP32を外付けのRTCを使わずに、時計機能を使おうというお話です。
 開発環境はAduino IDEを用いています。

 私のように、昔から組み込み機器に携わっているものは、時計機能を使おうとすると、真っ先にRTCを思い浮かべるのではないでしょうか。
 ESP32で時計機能を使う、例えば測定したデータを時刻情報と共にクラウドへ上げようとする場合、まずはRTCをくっつけることを考えます。
 事実ESP32にRTCをくっつけた記事はたくさん見かけます。

 ところが色々記事を見ていくと、ESP32にはデフォルトでRTCが内蔵されているらしいということです。
 しかし、RC発振のため、精度がよろしくない、バックアップもされていないとのことです。
 バックアップされていないと時計を合わせても、電源を切るたびに初期状態に戻ってしまいます。

 それならば、ESP32はWiFiを接続することが出来ます。NTPサーバーで時々、自動的に時計を合わせながら運用すれば良いのではないかという発想にいたります。
 まあこれって、結論的には、1行付け足すだけで出来ました。
 頭の古い組み込みやは別として、今のIoT社会では当たりまえの発想だったようです。標準の機能に組み込まれていて、何も苦労もすることはありませんでした。

■ESP32内蔵のRTC機能を使う

 ESP32に外付けのRTCをつないでみたという記事は多いのですが、内蔵のRTCをプログラムから、どのように使うかの記事が見当たりませんでした。

 調べていくうちに、もしかすると<time.h>がそのまま使えるのか?と思い、やってみるとその通りでした。
 <time.h>はC言語の、いにしえからある標準関数で、古めかしいし、それなりにトリッキーです。
 時計機能は必ずしもRTCでなくてもできます。ソフトウェアだけで実現することもできますが、とにかくこれで、時計機能が使えることは分かりました。

 つぎのようにすると、現在時刻がシリアルコンソールに表示されます。
 ただこれだけでは、時計は初期状態から進んでいくだけです。時刻を合わせたとしても、電源を切ると失われてしまいます。

#include <time.h>

static void print_time(void)
{
  time_t time_now;
  struct tm* tm_local;
  char s_time[100];

  time_now = time(NULL);            //現在時刻を得る。
  tm_local = localtime(&time_now);  //ローカル時間に変換する。
  strftime(s_time, sizeof s_time, "%F %T", tm_local); //文字列に変換する。
  Serial.println(s_time);           //シリアルコンソールに表示する。
}

■WiFiを開通させる

 NTPサーバーにつなごうとすると、まずはWiFiを開通させなければなりません。ESP32のWiFiを、アクセスポイントに接続させます。

 WiFi機能をプログラムから使うには<WiFi.h>をインクルードします。
 「WiFi.begin(ssid, password);」を呼び出すことで、アクセスポイントへの接続が開始できます。
 接続状態は、「WiFi.status();」を呼び出すことで得られます。接続が成功するとWL_CONNECTEDが返ります。
 WiFi.status()からWL_CONNECTEDが返るまでループさせる方式も良くとられますが、接続できない場合や、途中で途切れる場合などを考慮して、loop()の中で状態をスキャンする方式を採用します。

#include <WiFi.h>

static wl_status_t wifi_status;

void setup() {
  wifi_status = WiFi.begin(ssid, password);	//接続を開始し、最初の接続状態を得ます。
}

void loop(void)
{
  wl_status_t status;
  status = WiFi.status();				//接続状態を得ます。
  if( status != wifi_status )			//接続状態に変化があったときだけ処理をします。
  {
    switch(status)
    {
      case WL_CONNECTED:				//接続できたとき。
      Serial.println("WL_CONNECTED");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());	//自身のIPアドレスを表示します。
      break;
    }
  }
  wifi_status = status;
}

動作確認

途中でWiFiルータの電源を切り、WiFi接続が途切れて、再接続しても対応できることを確認しています。

WL_CONNECTED
IP address: 192.168.1.10
WL_CONNECTION_LOST		<<WiFiルータの電源を切る。
WL_NO_SSID_AVAIL
WL_IDLE_STATUS
WL_NO_SSID_AVAIL
WL_IDLE_STATUS
WL_CONNECTED			<<WiFiルータの電源を再投入したあと。
IP address: 192.168.11.3

■NTPを開通させる。

 NTPによる自動補正を行なわせるためには、つぎの1行を呼び出します。
 最初これはWiFi接続後に呼び出すものかと考えましたが、そうではなく、最初に1度だけ呼び出せば有効です。

void setup() {

  //NTPサーバで自動補正を行わせる。
  configTzTime("JST-9", "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");

}

動作確認

sketch_ntp
WL_IDLE_STATUS
WL_CONNECTED
IP address: 192.168.1.10
1970-01-01 09:00:01		<<初期状態の時刻で立ち上がる。
WL_CONNECTED
IP address: 192.168.1.10
1970-01-01 09:00:02
1970-01-01 09:00:03
1970-01-01 09:00:04
2024-10-20 21:20:44		<<NTPによる自動補正が働く。
2024-10-20 21:20:45
2024-10-20 21:20:46
2024-10-20 21:20:47
2024-10-20 21:20:48

■全ソースコード

ここから先は

2,373字

¥ 150

この記事が気に入ったらチップで応援してみませんか?