m5stackで組込み!!

Arduinoによるm5stack開発のいろいろと...

時刻の設定

今回は時刻を設定してみましょう。

NTPサーバによる時刻設定

前回は起動時にNTPサーバから時刻情報を取ってきて表示してました。
m5stack-build.hatenablog.com


setTimeによる時刻設定

起動後に時刻を自分で選択して設定するにはsetTime関数を使います。
この関数を使うにはTimeライブラリが必要になります。

GitHub - PaulStoffregen/Time: Time library for Arduino
ここからダウンロードしてください。

時刻を設定するコード

こちらがコードです。

#include <M5Stack.h>
#include <WiFi.h>
#include <time.h>
#include <TimeLib.h>

#define SET_TIME_NUM    4   // 時刻設定可能数

#define SEL_TYPE_TIME   0   // 時刻設定
#define SEL_TYPE_OK     1   // OK
#define SEL_TYPE_CANCEL 2   // CANCEL

const char* ssid       = "YOUR_SSID"; ←変更箇所
const char* password   = "YOUR_PASS"; ←変更箇所

const char* ntpServer = "ntp.nict.jp";      // NTPサーバ
const long  gmtOffset_sec = 3600 * 9;
const int   daylightOffset_sec = 0;

// 矢印表示情報構造体
typedef struct TS_TRIANGLE_POS {
  unsigned char ucX[3];
  unsigned char ucY[3];
  unsigned int  uiColor;
} TS_TRIANGLE_POS;

// 設定時刻情報構造体
typedef struct TS_SET_TIME {
  unsigned char ucMin;
  unsigned char ucMax;
  unsigned char ucVal;
} TS_SET_TIME;

// ▲表示
const TS_TRIANGLE_POS gtsUpArrow[SET_TIME_NUM] = {
  {{ 55, 63, 59},{ 70, 70, 63},WHITE}, // 時 10の位
  {{ 95,103, 99},{ 70, 70, 63},WHITE}, // 時  1の位
  {{185,193,189},{ 70, 70, 63},WHITE}, // 分 10の位
  {{225,233,229},{ 70, 70, 63},WHITE}, // 分  1の位
};

// ▼表示
const TS_TRIANGLE_POS gtsDownArrow[SET_TIME_NUM] = {
  {{ 55, 63, 59},{115,115,122},WHITE}, // 時 10の位
  {{ 95,103, 99},{115,115,122},WHITE}, // 時  1の位
  {{185,193,189},{115,115,122},WHITE}, // 分 10の位
  {{225,233,229},{115,115,122},WHITE}, // 分  1の位
};

// 設定時刻
TS_SET_TIME gtsSetTime[SET_TIME_NUM] = {
  { 0, 2, 0 }, // 時 10の位
  { 0, 9, 0 }, // 時  1の位
  { 0, 5, 0 }, // 分 10の位
  { 0, 9, 0 }, // 分  1の位
};

unsigned char gucGetTime = 0;
unsigned char gucSelNumIdx = 0;
unsigned char gucSelType = SEL_TYPE_TIME;

struct tm timeinfo;

void setup()
{
  // m5stack初期化
  M5.begin();
  //connect to WiFi
  M5.Lcd.print("Connecting to YOUR_SSID ");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      M5.Lcd.print(".");
  }
  M5.Lcd.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  // 設定した時刻を取得
  if(!getLocalTime(&timeinfo)){
    M5.Lcd.println("Failed to obtain time");
    return;
  }
  // 時刻の設定
  setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_mday, timeinfo.tm_mon, timeinfo.tm_year + 1900);

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

  // BLACK Screen
  M5.Lcd.fillScreen(BLACK);
  // 横線
  M5.Lcd.drawFastHLine(0, 220, 320, WHITE);
  // 縦線
  M5.Lcd.drawFastVLine(106, 220, 20, WHITE);
  M5.Lcd.drawFastVLine(219, 220, 20, WHITE);
  // 矢印
  M5.Lcd.fillTriangle(  49, 232,  53, 224,  57, 232,WHITE );
  M5.Lcd.fillTriangle( 159, 224, 163, 232, 167, 224,WHITE );
  M5.Lcd.fillTriangle( 269, 224, 277, 228, 269, 232,WHITE );

  // テキストサイズ指定
  M5.Lcd.setTextSize(2);
  // OK
  M5.Lcd.setCursor(120, 160);
  M5.Lcd.print("OK");
  // Cancel
  M5.Lcd.setCursor(120, 180);
  M5.Lcd.print("CANCEL");
}

void loop()
{
  unsigned char aucSetHour = 0;
  unsigned char aucSetMin = 0;

  delay(100);
//  delay(1);

  M5.update();
  // Aボタン
  if (M5.BtnA.wasPressed()) {
    // 時刻設定中
    if( SEL_TYPE_TIME == gucSelType )
    {
      // 数値を更新
      if( gtsSetTime[gucSelNumIdx].ucVal <  gtsSetTime[gucSelNumIdx].ucMax )
      {
          gtsSetTime[gucSelNumIdx].ucVal++;
      }
    }
    else
    {
        gucSelType = SEL_TYPE_OK;
    }
  }
  // Bボタン
  if (M5.BtnB.wasPressed()) {
    // 時刻設定中
    if( SEL_TYPE_TIME == gucSelType )
    {
      // 数値を更新
      if( gtsSetTime[gucSelNumIdx].ucVal >  gtsSetTime[gucSelNumIdx].ucMin )
      {
          gtsSetTime[gucSelNumIdx].ucVal--;
      }
    }
    else
    {
        gucSelType = SEL_TYPE_CANCEL;
    }
  }
  // Cボタン
  if (M5.BtnC.wasPressed()) {
    // ▲表示を消す
    M5.Lcd.fillTriangle( gtsUpArrow[gucSelNumIdx].ucX[0], gtsUpArrow[gucSelNumIdx].ucY[0],
                         gtsUpArrow[gucSelNumIdx].ucX[1], gtsUpArrow[gucSelNumIdx].ucY[1],
                         gtsUpArrow[gucSelNumIdx].ucX[2], gtsUpArrow[gucSelNumIdx].ucY[2],
                         BLACK );
    // ▼表示を消す
    M5.Lcd.fillTriangle( gtsDownArrow[gucSelNumIdx].ucX[0], gtsDownArrow[gucSelNumIdx].ucY[0],
                         gtsDownArrow[gucSelNumIdx].ucX[1], gtsDownArrow[gucSelNumIdx].ucY[1],
                         gtsDownArrow[gucSelNumIdx].ucX[2], gtsDownArrow[gucSelNumIdx].ucY[2],
                         BLACK );
    // 選択数値更新
    if( gucSelNumIdx < (SET_TIME_NUM - 1))
    {
      gucSelNumIdx++;
    }
    else
    {
      // 時刻設定中
      if( SEL_TYPE_TIME == gucSelType )
      {
        M5.Lcd.fillTriangle( 269, 224, 277, 228, 269, 232,BLACK );
        // テキストサイズ指定
        M5.Lcd.setTextSize(1);
        // ENTER
        M5.Lcd.setCursor(250, 224);
        M5.Lcd.print("ENTER");
        gucSelType = SEL_TYPE_OK;
      }
      else
      {
        // ENTERを黒く塗りつぶし
        M5.Lcd.fillRect(220, 221, 200, 19, BLACK);
        // OK
        if( SEL_TYPE_OK == gucSelType )
        {
            aucSetHour = (gtsSetTime[0].ucVal * 10 + gtsSetTime[1].ucVal);
            aucSetMin  = (gtsSetTime[2].ucVal * 10 + gtsSetTime[3].ucVal);
            // 時刻の設定
            setTime( aucSetHour, aucSetMin, 0 , day(), month(), year() );
        }
        gucSelType = SEL_TYPE_TIME;
        gucSelNumIdx = 0;
        // ▶表示
        M5.Lcd.fillTriangle( 269, 224, 277, 228, 269, 232,WHITE );
      }
    }
  }
  // 時刻設定中
  if( SEL_TYPE_TIME == gucSelType )
  {
    // ▲表示
    M5.Lcd.fillTriangle( gtsUpArrow[gucSelNumIdx].ucX[0], gtsUpArrow[gucSelNumIdx].ucY[0],
                         gtsUpArrow[gucSelNumIdx].ucX[1], gtsUpArrow[gucSelNumIdx].ucY[1],
                         gtsUpArrow[gucSelNumIdx].ucX[2], gtsUpArrow[gucSelNumIdx].ucY[2],
                         gtsUpArrow[gucSelNumIdx].uiColor );
    // ▼表示
    M5.Lcd.fillTriangle( gtsDownArrow[gucSelNumIdx].ucX[0], gtsDownArrow[gucSelNumIdx].ucY[0],
                         gtsDownArrow[gucSelNumIdx].ucX[1], gtsDownArrow[gucSelNumIdx].ucY[1],
                         gtsDownArrow[gucSelNumIdx].ucX[2], gtsDownArrow[gucSelNumIdx].ucY[2],
                         gtsDownArrow[gucSelNumIdx].uiColor );
  }

  // OK選択中
  if( SEL_TYPE_OK == gucSelType )
  {
    M5.Lcd.fillTriangle( 100, 164, 108, 168, 100, 172,WHITE );
    M5.Lcd.fillTriangle( 100, 184, 108, 188, 100, 192,BLACK );
  }
  // Cancel選択中
  if( SEL_TYPE_CANCEL == gucSelType )
  {
    M5.Lcd.fillTriangle( 100, 164, 108, 168, 100, 172,BLACK );
    M5.Lcd.fillTriangle( 100, 184, 108, 188, 100, 192,WHITE );
  }
  // 時刻設定中
  if( SEL_TYPE_TIME == gucSelType )
  {
    M5.Lcd.fillTriangle( 100, 164, 108, 168, 100, 172,BLACK );
    M5.Lcd.fillTriangle( 100, 184, 108, 188, 100, 192,BLACK );
  }
  
  // 時刻表示の更新
  printLocalTime();
  // 設定時刻表示の更新
  setLocalTime();
}

void printLocalTime()
{
  // テキストサイズ指定
  M5.Lcd.setTextSize(2);
  // カーソル位置を設定
  M5.Lcd.setCursor(50,0);
  M5.Lcd.printf("%04d-%02d-%02d %02d:%02d:%02d" 
                ,year()
                ,month()
                ,day()
                ,hour()
                ,minute()
                ,second() );

    // 起動時の時刻を保存
  if( 0 == gucGetTime )
  {
    gucGetTime = 0xff;
    // 時 10の位
    gtsSetTime[0].ucVal = (hour() / 10);
    // 時  1の位
    gtsSetTime[1].ucVal = (hour() % 10);
    // 分 10の位
    gtsSetTime[2].ucVal = (minute() / 10);
    // 分  1の位
    gtsSetTime[3].ucVal = (minute() % 10);
  }
}

void setLocalTime()
{
  // テキストサイズ指定
  M5.Lcd.setTextSize(4);
  // 時 10の位
  M5.Lcd.drawNumber(gtsSetTime[0].ucVal, 50, 80);
  // 時  1の位
  M5.Lcd.drawNumber(gtsSetTime[1].ucVal, 90, 80);
  M5.Lcd.setCursor(130, 80);
  M5.Lcd.print("h");
  // 分 10の位
  M5.Lcd.drawNumber(gtsSetTime[2].ucVal, 180, 80);
  // 分  1の位
  M5.Lcd.drawNumber(gtsSetTime[3].ucVal, 220, 80);
  M5.Lcd.setCursor(260, 80);
  M5.Lcd.print("m");
}

ちゃんと時刻が変更されました。