時計としても使えるM5StickC

 今回はM5StickCのRTC(リアルタイムクロック)機能を使ってオリジナル時計を作成します。なお、腕時計として使用したい場合はスイッチサイエンス社の腕時計バンド&マウンタ付きのものを購入すればよいでしょう。

・M5StickC(腕時計バンド付き)
https://www.switch-science.com/catalog/5517/

 オリジナル時計と言っても盤面表示のみで特に電子工作をするわけではありません。
 前々回のM5StickCのプログラムでは待ち時間(ウェイト)を調整してタイマーの時間を表示していました。この方法では誤差が多くなります。
より正確に計測する場合は内蔵クロックタイマーを利用する方法があります。これは前回のM5Stack Core2で作成したプログラムが該当します。ちなみに前回のプログラムはM5Stack Core2だけでなくM5StickCでも変更することなく動作します。(UIFlowのバージョンは問いません)


前々回のプログラムを内蔵タイマーを使ったものに変更

 まず、前回のプログラムを改良して前々回のように3分タイマーと1分タイマーになるようにしてみます。前回のプログラムは図のようになっていました。

 このプログラムと先ほどの内蔵タイマーを使ったものを組み合わせます。異なるのはボタンを押した場合の処理です。秒数を設定してタイマーをスタートさせるだけです。
 タイマーをスタートさせてしまえば、あとは1秒ごとにラベルの表示と四角形(バー)の表示処理を実行します。四角形のサイズ(縦幅)は「カウンタ÷設定した秒数×160」で求めることができます。160はM5StickCの画面の縦幅のサイズ(ドット、ピクセル)です。なお、UIFlow 1.4.5では描画時に四角形の塗りの設定をしないと2回目以降の描画で塗り潰した色が表示されないことがあります。再描画または再々描画されると表示されることもあります。
 カウンタが0より小さくなったらタイマーを停止させます。
 ウェイトによる処理を内蔵タイマーの処理に変更したプログラムは以下のようになります。


 なお、プログラムをPythonコードに変換すると以下のようになります。

from m5stack import *
from m5ui import *
from uiflow import *

setScreenColor(0x111111)

label0 = M5TextBox(75, 63, "0", lcd.FONT_DejaVu40,0xFFFFFF, rotate=90)
rectangle0 = M5Rect(0, 0, 40, 160, 0x18ff00, 0xff0000)

from numbers import Number

sec = None
counter = None

def buttonA_wasPressed():
  global sec, counter
  sec = 180
  counter = sec
  timerSch.run('timer1', 1000, 0x00)
  pass
btnA.wasPressed(buttonA_wasPressed)

def buttonB_wasPressed():
  global sec, counter
  sec = 60
  counter = sec
  timerSch.run('timer1', 1000, 0x00)
  pass
btnB.wasPressed(buttonB_wasPressed)

@timerSch.event('timer1')
def ttimer1():
  global sec, counter
  label0.setText(str(counter))
  counter = (counter if isinstance(counter, Number) else 0) + -1
  rectangle0.setSize(height=int(((counter / sec) * 160)))
  rectangle0.setBgColor(0x33ff33)
  if counter < 0:
    timerSch.stop('timer1')
  pass

RTC(リアルタイムクロック機能)を使う(時刻の設定)

 それでは次にM5StickCに搭載されているRTC(リアルタイムクロック機能)を使って時間を表示してみましょう。
 最初に現在の時刻を表示するプログラムを作成しますが、その前に一つ設定しないといけない事があります。それは、現在の時刻を設定する事です。購入した段階のM5StickCには正しい時刻が設定されていないからです。
 時刻を設定するには図のブロックを使います。ブロックは図で示すハードウェア、RTCのカテゴリにあります。なお、このカテゴリはUIFlowでM5StickCでプログラムを作成する場合以外は出てきません。もし、間違ってM5Stackなどを選択してしまった場合は、画面左下のAPI Keyの文字をクリックして表示される設定画面でM5StickCを選択してください。
 ブロックを配置したらブロック内の数値の所に設定する年月日と時刻を入れます。

 このままプログラムを実行させても構いませんし、設定されたことがわかるように画面の色を変えてもよいでしょう。

 より正確にしたいなら以下のようにAボタンを押したら時刻を設定するようにすることもできます。

 一度設定すれば電源を落としても時刻は保持されます。ただし、完全にバッテリーが放電してしまうと駄目です。
 なお、プログラムをPythonコードに変換すると以下のようになります。

from m5stack import *
from m5ui import *
from uiflow import *

setScreenColor(0x111111)

def buttonA_wasPressed():
  # global params
  rtc.setTime(2020, 9, 20, 11, 34, 00)
  setScreenColor(0x33ff33)
  pass
btnA.wasPressed(buttonA_wasPressed)

時刻の表示

 時刻を設定してしまえば後はラベルに時刻を表示するだけです。年月日や時刻は先ほど使用したブロックと同じカテゴリにあります。

 まず、時刻を表示するラベルを図のように配置します。文字のサイズはわかりやすいように大きくしてあります。

 次に図のようにブロックを組み立てます。これで現在の時刻が表示されます。なお、タイマーの間隔は0.1秒ごとにしてありますが、これは誤差を軽減するためで、誤差が気にならないのであれば1秒間隔にしても構いません。


 プログラムをPythonコードに変換すると以下のようになります。

from m5stack import *
from m5ui import *
from uiflow import *

setScreenColor(0x111111)

label0 = M5TextBox(50, 10, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label1 = M5TextBox(52, 49, ":", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label2 = M5TextBox(50, 64, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label3 = M5TextBox(52, 102, ":", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label4 = M5TextBox(50, 116, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)

@timerSch.event('timer1')
def ttimer1():
  # global params
  label0.setText(str(rtc.now()[3]))
  label2.setText(str(rtc.now()[4]))
  label4.setText(str(rtc.now()[5]))
  pass

timerSch.run('timer1', 100, 0x00)

 これに腕時計のバンドを付けると図のような感じで使用できます。

残り時間をバーで表示

 それでは最後に残り時間をバーで表示してみましょう。バーで表示する事で一日の残り時間がどのくらいなのか見た目にわかりやすくなります。バーの表示処理はこれまでと同じ方式です。UIFlow 1.4.5の都合上、バーが表示時刻と重なるとうまく表示されないので、前々回と同様に時刻の下側に配置しています。

 残りの時間はRTCの時間と分から計算します。1日の分数は24時間×60分=1440分になります。M5StickCの画面サイズは80x160なので1440分÷160ピクセルで1ピクセルあたり9分になります。計算式としては以下のようになります。

((23-時)×60+(59-分))÷9

 バーの長さが分かれば、これまでと同じ方式で表示することができます。後は図のようにブロックを配置すれば時刻とバーがリアルタイムに表示されます。

なお、実行ボタンを押して試験的に長時間動かしていると止まってしまうことがあります。その場合は、プログラムをM5StickCにダウンロード&インストールして実行してください。ダウンロード&インストール方法については第41回を参照してください。

・UIFlowでM5StickCに文字を表示してみよう https://news.mynavi.jp/article/makeprogram-41/

また、ダウンロードして実行しても長時間動かすと止まってしまう場合は仕方ないので本体左側の電源ボタンを1回押して定期的にリセットし再起動してください。多分UIFlow 1.4.5の不具合ではないかと思われますので、最新バージョンのUIFlow(β版)で同じように作成してみるとよいかもしれません。


 プログラムをPythonコードに変換すると以下のようになります。

from m5stack import *
from m5ui import *
from uiflow import *

setScreenColor(0x111111)

label0 = M5TextBox(50, 10, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label1 = M5TextBox(52, 49, ":", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label2 = M5TextBox(50, 64, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label3 = M5TextBox(52, 102, ":", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
label4 = M5TextBox(50, 116, "00", lcd.FONT_DejaVu24,0xFFFFFF, rotate=90)
rectangle0 = M5Rect(0, 0, 20, 160, 0x0fff00, 0x00ff00)

minutes = None

@timerSch.event('timer1')
def ttimer1():
  global minutes
  label0.setText(str(rtc.now()[3]))
  label2.setText(str(rtc.now()[4]))
  label4.setText(str(rtc.now()[5]))
  minutes = (23 - (rtc.now()[3])) * 60 + (59 - (rtc.now()[4]))
  rectangle0.setSize(height=int((minutes / 9)))
  pass

timerSch.run('timer1', 100, 0x00)

 仕組みが分かれば後は自分なりの盤面を表示することができます。時分秒が1桁の場合には2桁にする、残りの分数が少なくなったらバーを黄色にする、赤色にするなど改良点はいろいろ見つかります。このプログラムをベースにいろいろ改良してみてください。また、バッテリー切れを防ぎたい場合はUSB Type-C電源から供給するか、以下のTailBatを使う方法もあります。なお、TailBatはM5ATOM用なので高さが不揃いになります。

・ATOM TailBAT https://www.switch-science.com/catalog/6348/
著者 古籏一浩
プログラミングをベースにして面白そうなものはとりあえずやってみるというスタンス。複雑なものよりシンプルで楽しめるものが好み。最近は30年前に移植したゲーム(mz-700版 SPACE HARRIER)の話などを書いたりしています。
著者サイト:http://www.openspc2.org/