火を使うローソクは危ないので電池式のLEDローソク「OHM LED電池式ローソク Sサイズ 8CM LED-01S」を買いました。ところが実際に点灯させてみたところ、かなり残念な商品でした。まずは実際の動画を見てみましょう。

実際の動作映像

工事現場かよ!!w

100均のLEDキャンドルですら炎の揺らめく表現があるのに、よりにもよって等間隔でチカチカ光ってるとか、もうちょっと考えて作れよww!こういった市販されているLEDのローソクはどれもサイズが大きく、8cmという小さな商品は珍しくて魅力的だったのですが、困ったなぁ。

どんな仕組みなのか?

捨てるのもあれなので、まずはどんな作りになっているのか分解してみることにしました。

349円ということもあってなかなかシンプル。ボタン電池が3つ入っていて、2つのLEDがマイコンらしき基板に繋がっています。

2つのLEDのうち1つは常時点灯で、もう1つが点滅するようになっています。せっかくマイコンらしきもので制御してるのに、どうして等間隔で点滅させてしまったのか…。PWMは難しいとしても、せめて光らせる感覚をずらしてあげればもう少しそれっぽくなったんでしょうけどね。

無ければ作ろう!

ということで自分で作ることにしました。外側のケース部分はそのまま使えるので、中の電子回路を作ります。このLEDローソクはボタン電池LR41で動いているので、残念ながら私の大好きなM5Stackで動かすのは無理がありそうです。調べてみるとATtinyというシリーズのマイコンが小さくて、消費電力も小さくてよさそうです。幅7mmくらいのスペースに入れるため、ATtiny202というAVRマイコンを使うことにしました。

左側のがATtiny202、右側のがATtiny10です。ATtiny10はさらに小さくて魅力的ではあったのですが、プログラムを書き込む環境が大変そうだったので、ATtiny202の方にしました。こちらはUPDIという方式になっていて、VCC, GND, UPDIの3ピンのみでプログラムを書き込めます。

これが書き込み装置。USBのシリアル基板に抵抗とダイオードを足すだけでいいなんて、とてもシンプルでいいですね。開発環境の作り方はこちらのブログがとても参考になりました。

ところが、なぜかうちのPCでは最初の1回目しか書き込みが成功せず、2回目以降はCOMポートの状態がおかしくなって、書き込めなくなってしまいました。Windowsを再起動すると再び書き込みできるようになるんですが、さすがに書き込むたびにPCを再起動するのもねぇ。仕方ないのでArduino UNOを使って書き込むもう一つの方法に変えました。

jtag2updiというのを使うと、Arduinoを書き込み装置にすることができます。この方法でプログラムを書き込んだところ、2回目以降も問題なく書き込むことができました。

ゆらぎのプログラムを作る

今回作成したプログラムは GitHub にアップしました。
ゆらぎ表現については以下のサイトを参考にさせていただきました。
LEDキャンドルについての研究報告—LED2つで、ちょっぴりリッチなゆらぎ表現を—

どうやったらLEDでリアルな炎の表現ができるかを研究されていて、特に2つのLEDを使って逆位相を与えると、影のゆらぎが表現できるというのに感動しました。

これは素晴らしい!LED 1つでは影を動かすことはできませんからね。まるで本物のローソクの炎みたいです。今回はこのアイディアを頂戴して、2つのLEDを光らせるプログラムを作ってみました。

また、点灯してから5分後に自動的に消える機能も追加しました。いちいち消すのも面倒ですし、うっかり消し忘れるとボタン電池なのですぐに電池が空になってしまいます。本体下のボタンを押すとスリープモードから解除されて、再び点灯するようにします。

メモリが足らなくてつらい!

最近はESP32系で開発をやっていて、潤沢なメモリがあるので、プログラムの容量(FLASH)とかメモリの容量(SRAM)とか気にせずに、あーめんどくさいからStringでいいかーみたいに作ってました。ところがこのATtiny202はなんと、容量が2048バイトしかありません。普通にプログラムを書いてたら容量オーバーでエラーになっちゃうんですよ。とほほ

何がそんなに容量を食ってるのかを調べたところ、float型の変数を使って計算するとサイズが大きくなることがわかりました。1/fゆらぎの計算をしている部分です。そこでfloat型を使わずに、long型で計算するように変更しました。

  if (value < 500) {
    value = value + 2000L * value * value / 1000000L;
  } else if (value >= 500) {
    value = value - 2000L * ((1000L - value) * (1000L - value) / 1000L) / 1000L;
  }

1000倍して小数点以下の部分を計算するようにしています。しかしこれでも容量オーバーで書き込めません。どうやらrandom()という関数が巨大なようです。しかしここで使っているrandom()関数はそれほど重要なものではないので、あらかじめ配列に入れておいた値を使うようにしました。その結果…

最大2048バイトのフラッシュメモリのうち、スケッチが1944バイト(94%)を使っています。
最大128バイトのRAMのうち、グローバル変数が20バイト(15%)を使っていて、ローカル変数で108バイト使うことができます。

なんとか2KB以内に収まりました。

消費電流ってどのくらい?

改造前のオリジナルの状態で電流を測ったところ、LED点灯時に15mAくらい流れていました(うろ覚え)。LR41の電池容量35mAhくらいらしいので、1日5分つけると約1か月で無くなる計算です。商品説明でも1日5分で1か月と書いてありました。さすがに毎月3つのボタン電池を交換するのはコスパが悪いので、LEDの電流制限抵抗を110Ωから470Ωに変更して、省電力化をしてみました。電流値は5mAで、これなら3ヶ月近くもちそうです。

以下はPWMの動作をしていてLEDを接続させていないときの値です。今回はボタンを押してスリープ解除する仕様にしたので、マイコンには常時電源が接続されている状態になります。そこでスリープ時と動作時でどのくらい電力を消費するのか、電流値を測定してみました。

スリープのモードは最も作動する機能が少ないPOWER DOWNモードにしました。ボタンに接続されたPA7ピンからの割り込みによって、スリープが解除できる仕組みです。スリープ中の電流値は、うちにあったマルチメーターでは測定できませんでした。ほぼゼロに近い値のようです。

デフォルトの20MHz時は7mAほど食ってますが、1MHzの時は1mAとかなり少ないですね。LEDを含めた電流値が5mAだったので、LED単体で4mAといったところでしょうか。今回はanalogWrite()を使ってLEDにPWM信号を出すだけで、速度は重要ではないので、最も遅い1MHzで動作させるようにしました。

揺らいでる揺らいでる!

開発環境で実際に光らせてみたのがこちらの動画。

わりとそれっぽい感じが出てますね。この動画を撮ったときはまだ計算ミスがあったので、この後にはもうちょっと良い感じになってます。残念ながら動画を撮り忘れてしまいました。

製品に組み込もう!

プログラムもできたので、いよいよLED電池式ローソク本体の改造に移りたいと思います。基板に付いていたマイコンらしき黒い塊や配線をミニルーターで削っていきます。

Amazonで2400円で売ってたこのミニルーター、値段なりでかなり使いにくいんですが、いろんなビットが入っていて便利です。あまり頻繁に使うものではないのでいい買い物でした。

次はATtiny202への書き込み。今まで開発で使っていたのはDIP化キットで基板やヘッダピンが付いているものでしたが、実際に組み込む場合はIC単体でないと本体に収まりません。今回はAmazonで売ってたSOP-8のソケットを使ってプログラムを書き込みました。

同じくSOP-8のソケットで200milというのも売ってて、よくわからなかったんですが、ATtiny202の場合は150milの方でいいみたいですね。パッケージ名が同じなのにソケットが違うなんて罠だー。

両面テープでICを貼り付けて後は空中配線で接続。試しに電源を繋いでみると、あれ、片方のLEDがつかない!?

ICクリップでUPDI端子に接続して修正したプログラムを再度書き込みました。(後にプログラムは正しく、配線を間違えていたことが判明)

さらに電池ボックスのばねとボタンを丸く加工したユニバーサル基板に固定して、本体の基板に接続しました。

内側のケースに填め込みます。元々入っていたスイッチ(トグル型)からプッシュスイッチに変更したので隙間ができ、調整が大変でした。

最後に電池を入れて、外側のケースをかぶせたら完成です!

一見うまくできたように見えますが、ここで謎な現象が…!?

電池駆動にするとLEDが点灯せず、スリープ解除ボタンを押している間だけ点灯するというおかしな動作をするようになりました。外部電源で5Vを与えると正常に動作します。電池の電圧は4V程度。外部から3.3Vを与えると、たまにおかしな動作をするときもありますが、おおむね正常に動作します。安定化電源で2Vくらいに落としても動作します。電池の時だけおかしい。もしかして起動時に電圧降下して誤動作してるとか??

その後電池を付けたり外したり試しているうちに、なぜか正常に動くようになってしまいました。よくわからんがまぁ動いてるからヨシ!

期待と違った改造後の動画

そしてこちらが改造後の様子。

あれ、なんかコレジャナイ感。。。
実は消費電流を抑えようと抵抗値を大きくしたのが失敗で、LEDの光量が減ってしまい、肝である影がわからないほど暗くなってしまいました。もう少し暗いところで見ればそれっぽくは見えますが、ちょっと期待と違う感じになっちゃいました。

かといって毎月3個ずつ電池を交換するのは避けたいところ。とりあえず今回はこのまま行くとして、将来的にはもっと大きな容量の電池を外部接続する形でやりたいと思います。

AVRはつらかった

ということで微妙な感じで終わってしまいましたが、今回はじめてAVRマイコンを使ってみた感想は「つらい」の一言でした。ESP32のような高性能なマイコンを使っていると、プログラム容量もメモリも潤沢に使えて、何不自由なく好きなものが作れます。ATtinyは小型で超消費電力な半面、制約も厳しくて、それを上手く収めるための技術が必要です。またM5Stackならライブラリで簡単にできたようなことが、今回は使いませんでしたがATtinyだとレジスタを操作したり、かなり低レベルな部分まで触る必要があって難しいです。

とはいえ、この小ささはとても魅力的ですね。ATtiny10なんか米粒よりも小さいので、いつか何か作ってみたいと思います。

LINEで送る
Pocket