【AVR ATtiny10】ピンが無ければ ADC を使えばいいじゃない (1)HW編

💡 この記事は 2022.04.29 に公開した記事を再登録したものです
ATtiny10 登場
前に $2 足らずで売ってた 6ボタン学習リモコン、何個か買ったものの使い道が思い当たらず放置してたんですが、考えに考えてついに使い道を思いついたのです。

6ボタン 学習リモコン
部屋の (1)照明の ON/OFF、(2)エアコンの冷房の強、(3)弱、(4)暖房の強、(5)弱、(6)停止、これで 6ボタンぴったり。個別のリモコンを使わなくても、これ一つをベッドに持ち込めば自分の寝床が部屋のコントロールセンターです。この学習リモコンは複数買ってあるので、家族それぞれに持たせることもできます。近年まれに見る良いアイディアです。

学習元のリモコン
もちろんエアコンのリモコンはちょっと特殊なのは知ってます。
テレビのリモコンなんかは、音量を上げるボタンを押すと「音量を上げるボタン」のコードが送られ、それを受信したテレビが音量をひとつ上げるのです。
でもエアコンのリモコンには、「温度を上げるボタン」のコードはありません。リモコン自身が冷暖房等の運転状態や温度などを管理していて、温度を上げるボタンが押されたら自分が管理している温度の値をひとつ上げて、「冷房 25℃ 風量自動 にせよ」と運転状態一切合切を送るのです。
とどのつまり、学習させようとしている「冷房 強」とか「冷房 弱」みたいなのは温度の上下ボタンの話ではなく、「冷房 24℃」と「冷房 28℃」みたいな、特定の温度を決め打ちで学習させるということです。これなら 6ボタンでやれるわけです。
で結論から言うと、このアイディアは失敗に終わりました。例の学習リモコンではエアコンのリモコンを学習できなかったのです。前述のとおりエアコンのリモコンは一度の送信で運転状態を全て送るので、コマンドがとても長いのです。この学習リモコンは、この長いコマンドを覚えきれなかったわけです。
放置していた学習リモコンをなんとかして使う方法を思いついただけでしたが、このアイディアが素晴らしすぎて、それがいざ実現できないとなるとなおさらコントロールセンターの夢が捨てられなくなったのでした。
そんな折、AVR ATtiny10 がここにありました。

下段中央、ATtiny10
このワンチップマイコンで、学習とまではいかなくてもお決まりボタンリモコンを作ってしまえいいのです。見た目とは裏腹のスペックを持つこいつなら、赤外線リモコンの信号なんてたやすく再現してくれるはずです。というわけで早速開発に着手し、かの学習リモコンはまた放置と相成りました。
💡 AVR ATtiny10 の紹介はこちら
もっとピンを!
さて ATtiny10 ですが、乾電池 2本で動かせるので赤外線リモコンとしては丁度いいです。
処理速度も、必要ならば乾電池 2本で 8MHz 出せそうですから多分問題無いでしょう。
パワーダウンによって何もしていないときはほぼ電気を食わずに眠ることができ、この点もリモコンにぴったりです。
GPIO は 4本ですから、1本を赤外線LEDに割り当て、ボタンには残りの 3本を割り当てられそうです。欲しいボタンは 6個なので、ATtiny10 を 2つ使えばカバーできる気がします。安いマイコンですし、デュアルCPU とかカッコイイですし、16bit級とか謳ったらもう最高かもしれません。
…
なんてダサい話がありますか。
タイニーなマイコンを使ってピン(GPIO)が足りないからマイコンおかわりとか、本末転倒の極みです。だったら最初からピンがたくさんあるマイコンを使えばいいという話です。
こういうのとか。

秋月電子の通販ページより
しかしそういうマイコンはとても高性能で、たかだか赤外線リモコンにするにはもったいないです。実装されたハードウェアコンポーネントの大部分が使われずにシリコンの肥やしになるとか、作った人に申し訳が立ちません。
そもそも ATtiny10 にすら使わず余らせてしまうコンポーネントがあるというのにです。
例えばこれとか。

ATtiny10 ブロックダイアグラム
そう、ADC。
アナログ電圧をデジタル化して読み取るコンポーネントで、赤外線リモコンには関係の無いものです。こんなもの内蔵されていても、電源供給を止めて死んでいてもらうだけです。
しかしそもそも、こんな小さなマイコンで作れるアプリケーションで ADC とか何に使うんでしょうね?
たとえばこんな感じ?

アナログ電圧ボタン
おや?
ADC でボタンを読む
ボタンごとに異なるアナログ電圧を割り当てれば、 ADC を使って 1ポートで複数のボタンを読み分けられそうなことは思いつきました。ただしリモコンとして実用化するには、省電力である必要があります。
先ほどの回路

アナログ電圧ボタン
これは Vcc から GND まで抵抗を通じて常にアイドル電流が流れてしまい、省電力ではありません。
また、パワーダウンした ATtiny10 を目覚めさせるためのピンレベル割込み(INT0)をかけるには、どのボタンが押されても入力ピンを Low レベルに引き下げられる必要がありますから、最も高いボタン電圧でも Vcc の 1/3(Low保証電圧、データシートより)以下にする必要があります。これはすなわち VREF を Vcc とする ADC のレンジも 1/3 しか使えないということで、なんかもったいないです。

最も高いボタン電圧でも Low に
💡 なおお気付きだと思いますが、ボタンの同時押しは判別できません。しかしリモコンなどの用途ではこれを許容できると思います
これらを踏まえて改良すると、こうなります。

改良型アナログ電圧ボタン
先ほど Vcc に直結だった抵抗をマイコン自身の出力ピンにつないで、出力を制御することで常時アイドル電流が流れるのを抑制するのです。
制御手順はこうです。
STEP1 待機状態
マイコンはパワーダウン状態です。
INT0ピンはプルアップしてデジタル入力に切り替え、INT0割込みを有効にしておきます。
BTN-OUT(PBx)は Low を出力します。これで、どのボタンが押されても
INT0を Low に引き下げることができますし、抵抗にはボタンの押下まで電流は流れません。
待機状態
ボタン押下時ボタン押下によって
INT0ピンが Low に引き下げられると、INT0割込みによってマイコンは目覚めて動き出します。STEP2 ボタン電圧読み取り
BTN-OUT(PBx)に High を出力します。これでVcc(High)~GNDが抵抗群で分圧され、ボタン毎に異なるアナログ電圧が現れます。
INT0ピンのプルアップをやめた上アナログ入力に切り替え、ADC によってピン電圧を読み取ります。
※プルアップをやめないと、それによってボタン電圧が狂ってしまいます
ボタン電圧読み取りSTEP3 ボタンが離されたことの検出
ボタンの読み取りが終了したら、
BTN-OUT(PBx)は Low にします。
そしてINT0ピンをプルアップしてデジタル入力に切り替え、ピンの状態を読みます。
Low ならボタンはまだ離されておらず、High ならボタンが離されたということです。
High: ボタンが離された状態必要に応じてポーリングするなどして、ボタンが離されたらパワーダウンして STEP1 に戻ります。ポーリングはパワーダウンと WDT を組み合わせてタイミングを作ると省電力にできると思います。
INT0割込みは Low になったことを検出できますが、ここでは High になったことを検出したいのでここでは使えません。
ボタン押下の瞬間はチャタリングなどによってボタン電圧が不安定なことがありますので、読み取りは数回連続で同じボタンが読めるまで繰り返すとよいと思います。
ボタン数の限界
ATtiny10 の ADC は 8bit なので、アナログ電圧を 0~255 の 256段階に読み分けることができます。
ではボタンもそのくらいの数まで増やせるでしょうか?

ボタンは何個までイケる?
答えは No です。
抵抗 R には誤差があるため、上図のような回路でも電圧が全く均等に分圧されることは期待できないからです。
そこで、R として一般庶民にもお求めやすい ±5% くらいの精度の抵抗を念頭に置いて、以下を探ります。
❓ ばらつきのある抵抗値によって各ボタン電圧はどの程度の範囲に分散するのか?
この答えを求めるには、方程式をごりごり解いたり全組み合わせを手計算してみるなど、達成の折には大きな満足感の得られる方法があるのも承知ですが、Excel に計算を押し付けるという手もあります。
GND側のボタンを 0 としてボタンに番号を振ったとき、

ボタン
あるボタンN個(3個)の抵抗があり、上側には ボタン数 – N個(6 – 3 = 3個)の抵抗があります。
ボタン-5% で上側の抵抗全てが +5% のケースです。上限は逆に下側の抵抗全てが +5% で上側の抵抗全てが -5% のケースです。
式にするとこんな感じになるので、
ボタン数を変えながら Excel で表計算させてグラフにしたのがこちらです(偶然見つけた株価っていうグラフを調整したものです)。

グラフは Vcc を 1 としてます。ボタンGND電位なので、ここは動きようがありません)。横軸のボタン番号がズレてるように見えますが、見たいものは見られてるので問題ありません。
各ボタンの電圧範囲が隣のボタンのそれと重ならなければ分離して識別することが可能ということですが、21ボタンはダメで 20ボタンはギリギリ OK といったところですね。
※この計算では最悪値を求めていますが現実的にはこんな偏り方をすることは考えづらくもっとゆとりがあるはずで、あと何個か増やしても大丈夫かもしれませんね
ともかく、探った結果からこう言えます。
📝 5%精度の抵抗を使った場合、20ボタンまで読み分け可能
💡 ちなみにボタン
は _0 GND直結なのに一番上のボタンはなぜ信号線に直結しないかというと、ボタンの同時押し対策です。一番上のボタンが信号線直結だと、そのボタンとボタンを同時に押した場合に信号線が _0 GNDとショートします。その操作を排除できるのであれば、一番上の抵抗の上にボタンを付けることができ、最大ボタン数も 1増えることになります。
抵抗値の選び方
さて、R の値はどう決めたらよいでしょうか。ボタンの読み取り時には BTN-OUT(PBx) に High を出力して抵抗を通じて GND へ電流が流れますから、抵抗が大きい方が省電力になります。でもいくらでも大きくできるかというとそうでもなく、待機状態にボタン押下によって INT0割込みを発生させられる必要があります。

待機状態
待機状態では INT0ピンは内蔵プルアップされていますので、どのボタンを押しても R によってプルアップに打ち勝ってピン電圧を Vcc の 1/3 の Lowレベルまで引き下げられることが条件となります。
ですので、このプルアップ抵抗を基準に R が決まるわけです。
ではこのプルアップ抵抗はどの程度なのかと言えば、それはデータシートに書いてあります。

データシート:電気特性
最小値の 20kΩ で R群合成抵抗(の最大値)について不等式を解くとこんな感じです。
そして R群合成抵抗が一番大きい時というのは真ん中のボタンを押した時です。
真ん中のボタンが押されているので、そのボタンから GNDレベルまでの抵抗の本数は抵抗の数の半数になります。そしてそれが GND 直結と BTN-OUT(PBx) への接続で GNDレベルへ並列して接続されますから、抵抗値はさらに半分になります。つまり全部の抵抗を直列につないだ場合の 1/4 の抵抗値になります。
抵抗の本数はボタンの数に等しいので、
先ほどの解と合わせると
ということになります。
入手しやすい抵抗値から選ぶとして、ボタンが 6個なら R は 5.6kΩ、20個なら 1.5kΩ あたりになります。もちろんこの値は上限値ですからそれ以下であればよく、ボタンが何個であろうと 1kΩ でいくのだ!という方針でも構わないと思います。抵抗に電流が流れるのはボタン電圧読み取り時の一瞬だけですしね。
あり余るボタンの未来
たった 6pin のマイコンに能動的な素子を追加することなく 20個ものボタンを繋げられるとか、すごくないですか?こんなにボタンがあっても、ボタンの動作を書くための ROM の方が足りないなんてことになりかねない事態です。リモコン制作に端を発してますが、他にも応用の効くテクニックであることに間違いありません。GPIO 4本のうち気軽に使えるものは 3本、そのうちの 2本を 20ボタンに割いてもまだ 1本残ります。その 1本には、LED やらスピーカーやらシリアル通信やら、あれこれできるポテンシャルがあります。その上気軽に使えないピンではありますが、まだ 1本 GPIO に置き換え可能な RESETピンが残っていますから、ピンチになった時に本気を出すこともできます。なにか面白いこと、やれそうですよね。
といったところで、ハードウェア面についての考察を終えたところでこの記事は一旦ここまで。
ボタン制御のソフトウェア制作と動作確認、そしてリモコン制作は次以降の記事にします。
このシリーズ
🧩 【AVR ATtiny10】ピンが無ければ ADC を使えばいいじゃない / 全3回


Discussion