LoginSignup
7
7

More than 3 years have passed since last update.

M5StickC Plusで時報付きの時計を作る

Last updated at Posted at 2020-11-29

はじめに

子供の頃、家に振り子がついた壁掛け時計がありました。毎正時になると時刻の数だけチャイムがなるのです。(例えば3時になるとボーン、ボーン、ボーンと3回鳴る。)今はあまり見かけなくなりましたね。M5StickC Plusは本体のみでビープを鳴らせるので、時刻の数だけピロ、ピロっと音が鳴る時計を作りました。

構想(実現したいこと)

・M5StickC Plusの内蔵ブザーを使って毎正時に時刻の数だけ音を鳴らす。
・LEDも時刻の数だけ点滅させる。
・画面のデザインは、以前、作成した時計のスケッチ(7セグ液晶風)を流用する。
・常時電源接続、またはモバイルバッテリーで運用する。(M5StickC Plusはスリープできないため)

動作中の画面

IMG_4060 2.jpg
(期せずしてクリスマスっぽい色合いの写真に…笑)

スケッチ

Local_Clock7_Plus.ino
#include <M5StickCPlus.h>
#include <WiFi.h>
#include <time.h>

// wifiの設定
const char* ssid     = "xxxxxxxxxxxxxxx"; // WiFiのSSID
const char* password = "xxxxxxxxxxxxxxx"; // WiFiのパスワード

// 時計の設定
const char* ntpServer = "ntp.jst.mfeed.ad.jp"; // NTPサーバー
const long  gmtOffset_sec = 9 * 3600;          // 時差9時間
const int   daylightOffset_sec = 0;            // サマータイム設定なし

RTC_TimeTypeDef RTC_TimeStruct; // 時刻
RTC_DateTypeDef RTC_DateStruct; // 日付

int sMin = 0; // 画面書き換え判定用(分)
int countHour = 0; // 時報のカウンター

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
  M5.Axp.ScreenBreath(9);
  M5.Lcd.fillScreen(BLACK);

  pinMode(10, OUTPUT);    // LEDを使用する
  digitalWrite(10, HIGH); // LED消灯
}

void loop() {
  M5.update();
  printLocalTime();
  delay(980); // 0.98秒待ち

  if (M5.BtnA.wasPressed()) { // Aボタン1回押し
    wifiConnect(); // WiFi接続してNTPサーバーから時刻取得
  }
}

void printLocalTime() {
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
  M5.Rtc.GetTime(&RTC_TimeStruct); // 時刻の取り出し
  M5.Rtc.GetData(&RTC_DateStruct); // 日付の取り出し

  if (sMin == RTC_TimeStruct.Minutes) {
    M5.Lcd.fillRect(185,35,40,20,BLACK); // 秒の表示エリアだけ書き換え(Plusの解像度:135x240)
  } else {
    M5.Lcd.fillScreen(BLACK); // 「分」が変わったら画面全体を書き換え
  }

  M5.Lcd.setTextColor(GREEN);
  M5.Lcd.setCursor(45,35,7);  //x,y,font 7:48ピクセル7セグ風フォント

  M5.Lcd.printf("%02d:%02d", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes); // 時分を表示

  M5.Lcd.setTextFont(2); // 2:16ピクセルASCIIフォント
  M5.Lcd.printf(" : %02d\n",RTC_TimeStruct.Seconds); // 秒を表示

  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setCursor(50, 90, 2);  //x,y,font 2:16ピクセルASCIIフォント
  M5.Lcd.printf("Date: %04d.%02d.%02d %s\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date, wd[RTC_DateStruct.WeekDay]);

  sMin = RTC_TimeStruct.Minutes; // 「分」を保存

  if (RTC_TimeStruct.Minutes == 0){ // 毎時0分のときだけ判定する
    if (countHour == 0){ // 時報をまだ鳴らしていないとき

      int jihouHour = 0;

      // 音を鳴らす回数を設定
      if (RTC_TimeStruct.Hours == 0){ // 夜中の0時
        jihouHour = 12;
      } else if (RTC_TimeStruct.Hours > 12) { // 13時から23時
        jihouHour = RTC_TimeStruct.Hours - 12;
      } else {
        jihouHour = RTC_TimeStruct.Hours;
      }

      // 時刻の数だけ音を出す
      while (jihouHour > countHour) {

        digitalWrite(10, LOW); // LED点灯
        M5.Beep.tone(3300); // 329.628
        delay(40);
        M5.Beep.mute();

        M5.Beep.tone(2600); // 261.626
        delay(60);
        M5.Beep.mute();
        digitalWrite(10, HIGH); // LED消灯

        delay(800);
        countHour = countHour + 1;
      }

    } else {
      // 時報を一度鳴らしたら、0分の間は鳴らさない
    }

  } else { // 毎時0分以外のとき
    countHour = 0; // 時報カウンターをリセット
  }

}

void wifiConnect() {

  // connect to WiFi
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0, 1);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(1);
  M5.Lcd.print("WiFi connecting");
  WiFi.begin(ssid, password);

  int lCount = 0; // WiFi試行判定回数カウンター

  while (lCount < 10) { // 10回接続状態を判定する
    if (WiFi.status() == WL_CONNECTED) { // 接続できたとき

      M5.Lcd.println("\nconnected");

      // Set ntp time to local
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

      // Get local time
      struct tm timeInfo;
      if (getLocalTime(&timeInfo)) {
        M5.Lcd.print("NTP : ");
        M5.Lcd.println(ntpServer);

        // Set RTC time
        RTC_TimeTypeDef TimeStruct;
        TimeStruct.Hours   = timeInfo.tm_hour;
        TimeStruct.Minutes = timeInfo.tm_min;
        TimeStruct.Seconds = timeInfo.tm_sec;
        M5.Rtc.SetTime(&TimeStruct);

        RTC_DateTypeDef DateStruct;
        DateStruct.WeekDay = timeInfo.tm_wday;
        DateStruct.Month = timeInfo.tm_mon + 1;
        DateStruct.Date = timeInfo.tm_mday;
        DateStruct.Year = timeInfo.tm_year + 1900;
        M5.Rtc.SetData(&DateStruct);
      }

      // disconnect WiFi as it's no longer needed
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);

      M5.Lcd.println("WiFi disconnected");
      delay(1000);
      M5.Lcd.fillScreen(BLACK);

      break; // while を抜ける
    }

    // WiFi未接続のとき
    delay(1000);
    M5.Lcd.print(".");
    lCount = lCount + 1;
  }
}

所感など

電源オン直後はRTCから取り出した時刻を表示するようにしました。その上で、Aボタンを押せば、タイムサーバーから時刻を取得してRTCに保存できるようにしました。RTCの時刻は電源を切っても消えないので、日常的にはこれで十分と思います。

M5StickC Plusは、現時点で(2020年11月現在)スリープができません。これを逆手に取って、常時電源接続、またはモバイルバッテリーを使用する前提で、時刻を音で知らせてくれる、ちょっと懐かしい感じの(布団の中でまどろみながら時刻が分かる)時計ができました。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7