07.CoreInkで実用時計


7.CoreInkで実用時計

wifi経由で時刻をntp.nict.jpから取得して時計を作成します。15秒ごとに更新しているので年月日・曜日・時分秒が実際と十数秒以内で違っている場合があります。

説明

スケッチ例にあるRTC_BM8563.inoを改良しました。

西暦y年m月d日の曜日を求める式。
  • 1月と2月は、前年の13月と14月とする。例) 2021/1/15→2020/13/15
  • [x]は、xを超えない最大の整数
  • x mod n は、xをnで割った剰余
  • Y=y mod 100
  • h=0(土),1(日),2(月),…,6(金)
とすると、ツェラーの公式より
h={d+[26(m+1)/10]+Y+[Y/4]-2[y/100]+[[y/100]/4]} mod 7
で求まります。ただし、実際の計算は、
  • m<=2 なら y=y-1; m=m+12
  • [x]=floor(x)で、#include <math.h>が必要
  • y2=y%100
  • 上式 -2 の所は7加算した +5 でも可。(全部加算になる)
とすると、
h=(d + floor(2.6*(m+1)) + y2 + floor(y2*0.25) + 5*floor(y*0.01) + floor(y*0.0025)) % 7
となります。
https://ja.wikipedia.org/wiki/%E3%83%84%E3%82%A7%E3%83%A9%E3%83%BC%E3%81%AE%E5%85%AC%E5%BC%8F

スケッチ

スケッチ内のxxxxxに、自分のwifiのSSIDとそのパスワードを記入します。

// 時計 wifi経由して時刻をntpから取得
#include <M5CoreInk.h>  // M5Stack CoreInk使用
#include <WiFi.h>       // wifi使用
#include <time.h>       // time.hの構造体使用
#include <math.h>       // floor関数を使用
const char* ssid = "xxxxx";     // 自分のwifiのSSID
const char* password = "xxxxx"; // wifiのパスワード
static const char *wd[7] = {"SAT", "SUN", "MON", "TUE", "WED", "THU", "FRI"};//曜日配列
char timeStr[64];       // 表示文字列 64文字の配列の宣言
int y, y2, m, d, youbi; // 年4桁,年下2桁,月,日,曜日の変数
Ink_Sprite InkPageSprite(&M5.M5Ink);  //
RTC_TimeTypeDef RTCtime;              // 定義
RTC_DateTypeDef RTCDate;              // 定義

void inkSet() {                        // お決まり
  M5.begin();                  // E-Ink,RTC,I2C,ブザーを初期化
  if (!M5.M5Ink.isInit()) {            // 初期化出来なければ
    Serial.println("エラー Ink Init"); // シリアルモニタに表示
    while (1) delay(100);              // ずっと待つ
  }
  M5.M5Ink.clear();                    // 画像クリア
  delay(1000);                         // 1秒待つ
  if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) {
    // 画像領域が作成できなければ
    Serial.println("エラー Ink Sprite creat"); // シリアルモニタに表示
  }
}

void wifiSet() {                           // お決まり
  Serial.print(ssid);                      // シリアルモニタに表示
  Serial.print("に接続中");                // シリアルモニタに表示
  WiFi.begin(ssid, password);              // ネット設定を初期化
  while (WiFi.status() != WL_CONNECTED) {  // 接続状態が接続完でない時
    delay(500);                            // 0.5秒待つ
    Serial.print(".");                     // シリアルモニタに表示
  }
  Serial.println("ok");                    // シリアルモニタに表示
}

void setup() {
  struct tm timeInfo;                // 構造体定義
  inkSet();                          // CoreInkの設定
  wifiSet();                         // wifiの設定
  configTime(9 * 3600L, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
  // ntpの設定 (UTC→JSTのオフセット秒,夏時間オフセット,日本標準時刻サーバー)
  getLocalTime(&timeInfo);           // 時刻取得
  RTCDate.Year = timeInfo.tm_year;   // 年
  RTCDate.Month = timeInfo.tm_mon;   // 月
  RTCDate.Date = timeInfo.tm_mday;   // 日
  M5.rtc.SetData(&RTCDate);          // RTC日付構造体を設定
  RTCtime.Hours = timeInfo.tm_hour;  // 時
  RTCtime.Minutes = timeInfo.tm_min; // 分
  RTCtime.Seconds = timeInfo.tm_sec; // 秒
  M5.rtc.SetTime(&RTCtime);          // RTC時刻構造体を設定
  WiFi.disconnect(true);             // ネットワークから切断
  WiFi.mode(WIFI_OFF);               // wifiの動作モード
  Serial.print("wifi offか=");       // シリアルモニタに表示
  Serial.println(WiFi.status());     // wifiの接続状態
  // 0(WiFi.beginが呼出され3or4になるまで),1(使用可能なSSIDがない)
  // 2(スキャン完了),3(WiFi接続),4(すべての試行で接続失敗)
  // 5(接続が失われた),255(WiFiシールドがない)
}

void loop() {
  M5.rtc.GetData(&RTCDate);  // RTC日付構造体を取得
  M5.rtc.GetTime(&RTCtime);  // RTC時刻構造体を取得
  y = RTCDate.Year + 100;    // 年
  m = RTCDate.Month + 1;     // 月
  if (m <= 2) {              // ツェラーの公式参照
    y = y - 1;
    m = m + 12;
  }
  y2 = y % 100;
  d = RTCDate.Date;          // 日
  youbi = (d + (int)(floor(2.6 * (m + 1))) + y2 + (int)(floor(y2 * 0.25)) + 5 * (int)(floor(y * 0.01)) + (int)(floor(y * 0.0025))) % 7;
  sprintf(timeStr, "%04d/%02d/%02d(%3s) %02d:%02d:%02d",
          RTCDate.Year + 100, RTCDate.Month + 1, RTCDate.Date,
          wd[youbi], RTCtime.Hours, RTCtime.Minutes,
          RTCtime.Seconds);                // 文字列を作る
  Serial.println(timeStr);                 // シリアルモニタに表示
  InkPageSprite.drawString(4, 5, timeStr); // (x,y)に文字列を描く
  InkPageSprite.pushSprite();              // 画面更新
  delay(15000);                   // 15秒(=最小間隔)ごとに時刻更新
}