##はじめに
子供の頃、家に振り子がついた壁掛け時計がありました。毎正時になると時刻の数だけチャイムがなるのです。(例えば3時になるとボーン、ボーン、ボーンと3回鳴る。)今はあまり見かけなくなりましたね。M5StickC Plusは本体のみでビープを鳴らせるので、時刻の数だけピロ、ピロっと音が鳴る時計を作りました。
##構想(実現したいこと)
・M5StickC Plusの内蔵ブザーを使って毎正時に時刻の数だけ音を鳴らす。
・LEDも時刻の数だけ点滅させる。
・画面のデザインは、以前、作成した時計のスケッチ(7セグ液晶風)を流用する。
・常時電源接続、またはモバイルバッテリーで運用する。(M5StickC Plusはスリープできないため)
##動作中の画面
(期せずしてクリスマスっぽい色合いの写真に…笑)
##スケッチ
#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月現在)スリープができません。これを逆手に取って、常時電源接続、またはモバイルバッテリーを使用する前提で、時刻を音で知らせてくれる、ちょっと懐かしい感じの(布団の中でまどろみながら時刻が分かる)時計ができました。