【祝】最長勤続日数! 勤続日数カウンターをつくった
新卒から2年と3ヶ月が経ち、友達の現職の勤続日数がこれまでで最長になったのでお祝いをしました。
せっかくなので、勤続日数カウンターについてちょっと紹介します。
はじまり
7月4日、ふれっしゅから「お祝いに何か用意する?」と言われて始まったこのプロジェクト。 はじめは盾を贈ろうという話になっていたのですが、盾に勤続日数を表示したくない?という話になり、最終的には勤続日数を表示し続けるカウンターを作ることになりました。 よく考えてみると、日数カウンターのデバイスって世の中で見たことない気がしますね。 7月20日に会う予定だったので、2週間しかなくて結構ギリギリでしたw
そのへんにあった箱で作ったプロトタイプ(?)
概要
仕様
- 開始日からの日数を計測する
- リセットボタンを長押しすると開始日を現在時刻にする
材料
- Arduino nano
- WaveShare E-Ink 電子ペーパーモジュール
- DS1307 I2C RTCモジュール
- MDF 4mm, 2.5mm
- ケミカルウッド 適量
- 塗料、プラ紙(?)
プログラム
ポイント1:電子ペーパー、回路
ディスプレイ選びのポイントとしては、明るいときにはきちんと表示が見え、暗いときにはあまり目立たないという点でした。普通の液晶パネルのように自分が発光するタイプだと夜明るくて邪魔なので、調光機能つけないといけません。その点、コントラストがはっきりしていて文字盤も読みやすく、自分が発光しない電子ペーパーはちょうど良かったです。おかげで部品点数も手間も減り、2週間という短納期を実現できました。 電子ペーパー、初めて使ったんですがやっぱり電源切っても表示されっぱなしというのは面白いですね。
また、この電子ペーパーモジュールのwikiページやデモコードなどが結構ちゃんとしていたので、パーツを買ったその日のうちにすぐに動かせたのもとても楽でした。
初めてディスプレイに文字が出せたシーン
パーツはすべて秋葉原でぱぱっと買えるものを使いました。 モジュールを千石や秋月で買って、ユニバーサル基板にくっつけてあります。今思い出したけど、使ってないピンはんだ付けするの忘れてる気がする・・・・笑
実装後の基板
ポイント2:筐体
初めて3DCADを使ってチュートリアル以外にまともにモノを作りました。 Fusion360ってすごい!
CADで作った外観
中身はこんな感じ。ディスプレイの止め方もポイント。
3DCNCを使って表面パネルを削り出し、他はレーザーカッターで切った板を重ねています。
表面パネルはディスプレイをはめ込むために3DCNCで削り出し
それ以外の筐体はレーザーカッターでさくっと加工
削った部品を貼り合わせたところ
ポイント3:塗装
塗装は完全に素人なので、秋葉原工作室さんに伺って教えてもらいました。
完全に初めてということを伝えると「段差があるから薄いプラ紙(?)を貼るといいよ」とか「缶スプレーで塗るといいんじゃないかな」といったアドバイスがもらえましたし、道具もその場にあるので、行ったその日のうちに塗装ができました!(感謝)
プラ紙を貼っているふれっしゅ
下塗りした後に赤いスプレーをかけたところ
最終形態
ポイント4:プログラム
プログラムはGitHubに公開しておきました。
https://github.com/makotoshimazu/DayCounter
機能としては開始時刻を記録して現在時刻との差分を表示するというだけなのですが、意外と面倒な点がいくつかありました。
フォント
今回はGoogle Fontsからいいフォントをひたすら探して、Ranchersというものを使いました。 inkscapeでピクセル単位でいい位置を探し、書き込んであります。 全部ぶん投げちゃったけど1日でいい感じに仕上げてくれたふれっしゅ、ありがとう!!!!笑
長押し検知・連打検知
チャタリング防止用に、50msごとにスイッチをポーリングしています。 ステートをOFF, ONのほかにLongOFF/LongONという2つを用意し、一定時間より長く同じステートにいたらLongOFF/LongONになるみたいな実装にしてあります。 そうすると、ON -> OFF -> ON -> OFFみたいにLongじゃないステートの行き来をカウントすれば連打検知が結構簡単に実装できるということに今回気づきました。 この辺がそのコードです。 普段からそういう実装する人的には自明かもしれないですが、自分的にちょっとうまく実装できた感あって嬉しくなったポイントですw
EEPROMの寿命検知
EEPROMの書き換え寿命が1万回程度なので、もし1万回リセットボタン押したらEEPROMが壊れて開始時刻が壊れてしまうかもしれません(押さないとは思うけど)。 ということで、データが壊れているか検知するためにCRCを計算することにしました(このへん)。 PyCRCというプログラムをつかって今回はCRCを求めています。 こんな感じの引数でpycrcについてくるpycrc.pyを実行すると、それっぽいCのコードが吐けます。 ちなみに気をつけるポイントは--xor-out=0xAAAA
を指定する部分です。これがないと、全部ゼロのデータのCRCの結果がゼロになってしまうので、EEPROMをゼロで初期化したときにデータがvalidになってしまいます。
$ ./pycrc.py --model crc-16 --algorithm tbl --std=c99 --crc-type=Type --xor-out=0xAAAA --generate h -o crc.h
デフォルトだと8bitずつ計算するので256 * 2byte = 512 byteの領域がメモリに必要です。これはマイコン的に厳しいので、省スペースにするために4bitずつ計算するようにしました(このへん)。
現在時刻の修正
今回はRTCモジュールのサンプルに従って、コンパイル時刻に現在時刻を設定するようにしました。 起動時にEEPROMに保存されているコンパイル時刻と定数として保持しているコンパイル時刻を比較し、異なっていたときだけ更新するようにしています。 まぁ書き込みには1分程度しかかからないので、おおよそうまくいったと思います。
RTCモジュールもArduino用のサンプルプログラムが提供されているので、それを利用するととても簡単に使うことができました。 ただCRCや日付計算のためにかなりコードを書き換えました。このディレクトリにあるものがサンプルコードを書き換えたライブラリになります。
メモリ削減
ATmega328はメモリが2KiBしかないので、プリントする文字列をそのまま定数で保持していくと苦しいことになります。そのため、基本的にすべてのSerialにプリントする文字列をコードと同じフラッシュメモリに入れています。
まとめ
市販の時計はすごい!!!!
渡して数秒でリセットボタンに気づいたしらはまは天才でした。 1000日経ってカンストする画面を見てもらえるのを楽しみにしています!٩( ’ω’ )وヨッシャ!
あと仕事とは別に適当な工作するの楽しいですね。 もう少しCADとか色塗りの技術をつけていきたいです。なんかオススメありますか。