non vorrei lavorare

2020年度からの小学校プログラミング教育の必修化を親として迎えるブロガーの書く、子供との日常

M5StickCがずいぶん前に届いていた件

こんばんは。夏休みもあと少しです。9月からは給食室が工事のため、引き続きお弁当が必要な長男がいる@kjunichiです。

背景

Apple Watchが欲しくてしかたない今日この頃だが、先立つものが無い。 たまたま、AKIBA PC Hotline!

akiba-pc.watch.impress.co.jp

の記事を見て、2千円程度でM5StickCなるデバイスが存在することを知った。 これなら腕にはめて時計スタイルで使用できると思った。

初期不良と思った

画面の明るさの制御ができない。 サンプルのファクトリーアプリを入れて、ボタンを押すと、 本来は液晶が徐々に暗くなるようなコードが見受けられたが、真っ暗に。。。

しかし、どうも、液晶の明るさ以外はWifiも使えるし、画面描画も問題なさそう。

時計を作ってみた

amazonで購入したのだが、アキバPCで紹介されていたものとは異なり、 腕時計用のアタッチメントやバンドは付属していなかったが、 電源入るとWifiに接続しNTPサーバーより時刻を取得して、これを表示するコードを書いてみた。

M5StickC Nixie tube Clockmacsbug.wordpress.com

lang-ship.com

を参考にして、LAN環境が無いと動かない時計が完成した!

// M5StickC Nixie tube Clock: 2019.06.06 
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiMulti.h>

#include "vfd_18x34.c"
#include "vfd_35x67.c"

const char* ssid       = "ssid";
const char* password   = "password";
const char* ntpServer =  "ntp.jst.mfeed.ad.jp";

RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

WiFiMulti wifiMulti;

int mode_ = 3; // 3:2Lines 2: 2Lines(YYMM), 1:1Line
const uint8_t*n[] = { // vfd font 18x34
  vfd_18x34_0,vfd_18x34_1,vfd_18x34_2,vfd_18x34_3,vfd_18x34_4,
  vfd_18x34_5,vfd_18x34_6,vfd_18x34_7,vfd_18x34_8,vfd_18x34_9
  };
const uint8_t*m[] = { // vfd font 35x67
  vfd_35x67_0,vfd_35x67_1,vfd_35x67_2,vfd_35x67_3,vfd_35x67_4,
  vfd_35x67_5,vfd_35x67_6,vfd_35x67_7,vfd_35x67_8,vfd_35x67_9
  };
const char *monthName[12] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};


void setup(void){ 
  M5.begin();
  pinMode(M5_BUTTON_HOME, INPUT);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setRotation(1);
  
  wifiMulti.addAP(ssid, password);
  if((wifiMulti.run() == WL_CONNECTED)) {
    // Set ntp time to local
    configTime(9 * 3600, 0, 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);
      // rtc setup end -----------------------------------------------
    }
    //disconnect WiFi
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
  
  }
  
}

int showTime = 20;
bool fblank = false;
void loop(void){
  if(showTime<0) {
    if(!fblank) {
      M5.Lcd.fillScreen(BLACK);
      fblank=true;
    }
    if(digitalRead(M5_BUTTON_HOME) == LOW){
      while(digitalRead(M5_BUTTON_HOME) == LOW);
      Serial.println("display.");
      M5.Axp.DeepSleep(SLEEP_MSEC(1));
      showTime=10;
      fblank=false;
      vfd_3_line();
      //if (mode_ == 3){mode_ = 1;M5.Lcd.fillScreen(BLACK);return;}
      //if (mode_ == 2){mode_ = 3;M5.Lcd.fillScreen(BLACK);return;}
      //if (mode_ == 1){mode_ = 2;M5.Lcd.fillScreen(BLACK);return;}
    } else {        
        M5.Axp.LightSleep(SLEEP_MSEC(800));
        //delay(6);
        //M5.Axp.DeepSleep(SLEEP_MSEC(300));
        //M5.Lcd.setCursor(60, 30);
        //M5.Lcd.fillScreen(WHITE);
        //M5.Lcd.setCursor(60, 30);
        //M5.Lcd.print("unsleep");
        //Serial.println("test.");
    }
    delay(100); 
  } else {
    showTime--;
    if ( mode_ == 3 ){ vfd_3_line();}   // hh,mm,ss
    if ( mode_ == 2 ){ vfd_2_line();}   // yyyy,mm,dd,hh,mm,ss
    if ( mode_ == 1 ){ vfd_1_line();}   // mm,ss
    delay(1000);
  }
}
 
void vfd_3_line(){
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  int h1 = int(RTC_TimeStruct.Hours / 10 );
  int h2 = int(RTC_TimeStruct.Hours - h1*10 );
  int i1 = int(RTC_TimeStruct.Minutes / 10 );
  int i2 = int(RTC_TimeStruct.Minutes - i1*10 );
  int s1 = int(RTC_TimeStruct.Seconds / 10 );
  int s2 = int(RTC_TimeStruct.Seconds - s1*10 );
  
  M5.Lcd.pushImage(  2,0,35,67, (uint16_t *)m[h1]);
  M5.Lcd.pushImage( 41,0,35,67, (uint16_t *)m[h2]);
  M5.Lcd.drawPixel( 79,22, ORANGE); M5.Lcd.drawPixel( 79,48,ORANGE); 
  M5.Lcd.drawPixel( 79,21, YELLOW); M5.Lcd.drawPixel( 79,47,YELLOW); 
  M5.Lcd.pushImage( 83,0,35,67, (uint16_t *)m[i1]);
  M5.Lcd.pushImage(121,0,35,67, (uint16_t *)m[i2]);
  M5.Lcd.pushImage(120,45,18,34, (uint16_t *)n[s1]);
  M5.Lcd.pushImage(140,45,18,34, (uint16_t *)n[s2]);
  
  if ( s1 == 0 && s2 == 0 ){ fade();}
}

void vfd_2_line(){
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  //Serial.printf("Data: %04d-%02d-%02d\n",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date);
  //Serial.printf("Week: %d\n",RTC_DateStruct.WeekDay);
  //Serial.printf("Time: %02d : %02d : %02d\n",RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds);
  // Data: 2019-06-06
  // Week: 0
  // Time: 09 : 55 : 26
  int y1 = int(RTC_DateStruct.Year    / 1000 );
  int y2 = int((RTC_DateStruct.Year   - y1*1000 ) / 100 );
  int y3 = int((RTC_DateStruct.Year   - y1*1000 - y2*100 ) / 10 );
  int y4 = int(RTC_DateStruct.Year    - y1*1000 - y2*100 - y3*10 );
  int j1 = int(RTC_DateStruct.Month   / 10);
  int j2 = int(RTC_DateStruct.Month   - j1*10 );
  int d1 = int(RTC_DateStruct.Date    / 10 );
  int d2 = int(RTC_DateStruct.Date    - d1*10 );
  int h1 = int(RTC_TimeStruct.Hours   / 10) ;
  int h2 = int(RTC_TimeStruct.Hours   - h1*10 );
  int i1 = int(RTC_TimeStruct.Minutes / 10 );
  int i2 = int(RTC_TimeStruct.Minutes - i1*10 );
  int s1 = int(RTC_TimeStruct.Seconds / 10 );
  int s2 = int(RTC_TimeStruct.Seconds - s1*10 );
   
  M5.Lcd.pushImage(  0, 0,18,34, (uint16_t *)n[y1]); 
  M5.Lcd.pushImage( 19, 0,18,34, (uint16_t *)n[y2]);
  M5.Lcd.pushImage( 38, 0,18,34, (uint16_t *)n[y3]);
  M5.Lcd.pushImage( 57, 0,18,34, (uint16_t *)n[y4]);
  M5.Lcd.drawPixel( 77,13, ORANGE); M5.Lcd.drawPixel( 77,23,ORANGE);
  M5.Lcd.pushImage( 80, 0,18,34, (uint16_t *)n[j1]);
  M5.Lcd.pushImage( 99, 0,18,34, (uint16_t *)n[j2]);
  M5.Lcd.drawPixel(118,13, ORANGE); M5.Lcd.drawPixel(119,23,ORANGE);
  M5.Lcd.pushImage(120, 0,18,34, (uint16_t *)n[d1]);
  M5.Lcd.pushImage(140, 0,18,34, (uint16_t *)n[d2]);
                                                    
  M5.Lcd.pushImage( 00,40,18,34, (uint16_t *)n[h1]);
  M5.Lcd.pushImage( 20,40,18,34, (uint16_t *)n[h2]);
  M5.Lcd.drawPixel( 48,54, ORANGE); M5.Lcd.drawPixel( 48,64,ORANGE); 
  M5.Lcd.pushImage( 60,40,18,34, (uint16_t *)n[i1]);
  M5.Lcd.pushImage( 80,40,18,34, (uint16_t *)n[i2]);
  M5.Lcd.drawPixel(108,54, ORANGE); M5.Lcd.drawPixel(108,64,ORANGE);
  M5.Lcd.pushImage(120,40,18,34, (uint16_t *)n[s1]);
  M5.Lcd.pushImage(140,40,18,34, (uint16_t *)n[s2]);
 
  if ( i1 == 0 && i2 == 0 ){ fade();}
}
 
void vfd_1_line(){
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Rtc.GetData(&RTC_DateStruct);
  int i1 = int(RTC_TimeStruct.Minutes / 10 );
  int i2 = int(RTC_TimeStruct.Minutes - i1*10 );
  int s1 = int(RTC_TimeStruct.Seconds / 10 );
  int s2 = int(RTC_TimeStruct.Seconds - s1*10 );
  
  M5.Lcd.pushImage(  2,6,35,67, (uint16_t *)m[i1]);
  M5.Lcd.pushImage( 41,6,35,67, (uint16_t *)m[i2]);
  M5.Lcd.drawPixel( 79,28, ORANGE); M5.Lcd.drawPixel( 79,54,ORANGE); 
  M5.Lcd.drawPixel( 79,27, YELLOW); M5.Lcd.drawPixel( 79,53,YELLOW); 
  M5.Lcd.pushImage( 83,6,35,67, (uint16_t *)m[s1]);
  M5.Lcd.pushImage(121,6,35,67, (uint16_t *)m[s2]);
 
  if ( s1 == 0 && s2 == 0 ){ fade();}
}

void fade(){
  //for (int i=7;i<16;i++){M5.Axp.ScreenBreath(i);delay(25);}
  //for (int i=15;i>7;i--){M5.Axp.ScreenBreath(i);delay(25);}
  //M5.Axp.ScreenBreath(12);
}

残念な点

バッテリーが持たなすぎ。 1時間ももたない。

実は、正常品だった

Arduino IDEでダウンロードしたフォルダをごっそりGithubからクローンしたフォルダに差し替える

macOS環境ではに~/Documents/Arduino/libraries/配下のM5StickCフォルダをクローンしたフォルダに入れ替えることで 対応できた。

関連記事

2年前の記事

1年前の記事