AVR ATtiny2313 ビデオ出力 ブロック崩し〜アナログ入力〜
2008年11月製作/11〜12月記事 前回の「AVR ATtiny2313 ビデオ出力 ブロック崩し」はビデオ信号出力をテーマとした製作で、画面出力の内容としてブロック崩しのアプリを開発しました。これはスイッチで操作するものでした。参考としてボリューム(可変抵抗)で操作する実験もしました。 今回は、ATMEL社のサイト内Application Notesのページにある、アナログコンパレータをA/Dコンバータに応用する方法を使って、ブロック崩しのバーを操作できるようにします。 http://www.atmel.com/dyn/products/app_notes.asp?family_id=607#General%20Purpose AVR400: Low Cost A/D Converter 回路図と部品一覧、ソフトを公開しています。 記事中の写真はクリックすると大きく表示されます。 |
A/Dコンバータとアナログコンパレータ
アナログコンパレータ応用のA/Dコンバータ
実験 前回の製作でPB0,PB1につなげていたスイッチをPB3,PB4に移し、AIN0(PB0),AIN1(PB1)にそれぞれコンデンサとボリューム、抵抗をつなげました。 左の写真で、中央手前の小さい水色の部品が主役となるコンデンサです。 右下の4つの抵抗は直列につながっていて、黒い線を挿す位置によって10k,20k,30k,40kΩになります。実験しながら値を検討しているところです。 |
(動画) ATtiny2313でA/Dコンバータ ※TV画面の撮影ではなくPCでキャプチャした動画です。 |
A/Dコンバータの動作を目で見る ブレッドボード上で完成したA/Dコンバータの様子を見てください。 動画のバーはスイッチではなくボリューム(可変抵抗)で操作しています。コンデンサの充電時間を16ビットカウンタTCNT1で計測し、上位8ビットをブロック部分に表示しています。2進数で灰色が1、黒が0です。 AIN1の入力電圧を最小〜最大まで滑らかに変化させると、その様子が2進数の桁そのままの形で見えて面白いです。A/Dコンバータがちゃんと動作しているということです。 バー左端〜右端に対して変換値はおよそ0b00000100〜0b01000000です。6bitのA/Dコンバータと言えるでしょうか。 このA/Dコンバータは常に充電/放電を繰り返していて、TCNT1の下位8ビットくらいは不規則に変化しています。そのため変換値としては下位8ビット(不安定な成分)を捨てています。 バーの移動範囲は11マスなので、分解能が6bit(64段階)なら用は足ります。 このA/Dコンバータができるまでの経過を次に説明します。 |
お手本とは違う容量のコンデンサでやってみる アナログコンパレータを応用したA/Dコンバータの作り方について、ATMELの資料には次のことが書かれています。 ・動作クロックと抵抗値とコンデンサ容量の関係式。 ・その関係式から導かれた値をまとめた一覧表。 ・計測できる電圧の範囲。「Measurement Range: 0 - 2 V」 これに従えば高い精度のA/Dコンバータを作れると思います。 しかし今回の製作で回路はお手本通りとしますが、次の理由から部品の値は自分で決めました。 ・一覧表には動作が16MHzまでの値しか載っていなかった。 →今製作している回路の動作は20MHz ・一覧表のコンデンサはどれも数十nFで手持ちになかった。 →普段使っているパスコン0.1uFの1/10〜1/100の容量 そこで、容量0.1uFのコンデンサに合わせて関係式から抵抗値の当たりを付け、実験しながら値を決めました。 コンデンサを充電するとき、流れる電流が多いほど、またコンデンサの容量が小さいほど、充電満タンまでの時間は早くなります。速やかに充電/放電ができるということです。資料の一覧表でコンデンサの容量がどれも小さいのはこのような理由でしょう。 A/Dコンバータに応用するには、0.1uFは容量が大きいようです。それでも適当な抵抗を通して実験したところ、充電時間は1画面描画する時間(1画面は262ライン、1ラインは63.56us)よりずっと短いことが分かりました。 |
|
ビデオ信号出力との兼ね合い コンデンサの充電時間を計測するには、アナログコンパレータで監視している電圧が目標値になったら割り込みをかけてカウンタを止める、という方法が考えられます。 ところでブロック崩しのアプリでは、走査線を描画するタイミングをスリープ機能で計っています。スリープは何らかの割り込みがかかると解除されます。 ということはカウンタ停止のために割り込み処理を呼び出すと、走査線の周期と関係ないタイミングで描画が始まり、ビデオ信号の出力タイミングがめちゃくちゃになってしまいます。 解決策として、割り込みを使わない方法を考えます。 走査線の描画周期でアナログコンパレータの状態を取得します。コンデンサの充電を開始した後、目標の電圧に到達した瞬間(AIN0 > AIN1)にカウンタを止めることはできませんが、走査線1本を描画する時間単位でなら止められます。もともと測定器のような正確な値は求めておらず、ブロック崩しのバーの移動に利用できればよいので、この方法で問題ありません。 余談ですが、この時点でアナログコンパレータのキャプチャ連携を使う考えはなくなりました。 |
|
抵抗値を決定する さて、このような実装ゆえ、充電速度が速すぎると難ありとなります。 バーの移動範囲は11マスです。A/Dコンバータで取得できる値が少なくとも11段階必要ということです。つまり、バーが左端/右端にあるときの(=入力電圧が最小値/最大値のときの)充電時間の差が、走査線を11本描画する時間より小さいと困るわけです。 また、充電時間(カウンタの値)からバーの位置に換算する過程で整数除算があります。充電時間のばらつきによる計算誤差の影響を小さくするため、カウンタの値(割られる数)は大きいほどよいです。 その一方でカウンタは16bitです。計測する時間はこの範囲に収まらなくてはならず、充電がゆっくりすぎても困ります。 充電の速さを決める抵抗(コンデンサに直列につなぐ抵抗)の値はこの辺のバランスを見ながら決めることになります。 実験の結果、この抵抗を10kΩとしました。 逆にこのことによって、AIN1には0〜2.5Vの電圧を入力することになります。ボリュームが10kΩ、VCCが5Vなので、ちょうど半分に分圧されるのです。入力電圧の範囲として資料で示された2V(VCCの2/5)を超えますが、ゲームをプレイして特に違和感はありませんでした。 |
回路図とプログラム
ATtiny2313 Video出力 ブロック崩し アナログコンパレータ応用A/Dコンバータ版 回路図はここをクリック。 部品一覧はこのページの一番下にあります。 プログラムはここをクリック。(VBlockAC ver1.00) プログラムはZIPで圧縮してあります。解凍するとVBlockAC.c(プログラム本体)、aryPaint.s(ブロックの描画関数)が出てきます。 AVR StudioでVBlockACというプロジェクトを新規作成し、2つのソースをプロジェクトに加え、最適化オプション「-O2」でビルドしてください。ソースが不要な人は同梱のVBlockAC.hexをATtiny2313に書き込めばok. |
|
ボリュームの端子と回路図の対応 |
回路図について 当初試みていた「シリアル通信で文字列を受け取ってTV画面に出力」という使い方を考慮して(やるかどうかは別として)、ビデオ信号出力のピンを前回製作時のPD0(RxD),PD1(TxD)から、今回はPD2,PD3に移しました。これに合わせてプログラムも一部変更しています。 ※2個作ってシリアル通信すれば対戦ゲームが作れるな。 ボリューム(可変抵抗)の端子と接続先は左図の通りです。これを間違えると軸の回転とバーの移動が逆向きになったり、回転量と移動量の割合が不自然になったりするので注意してください。 PB2からはVCCと同じ電圧が出力されてコンデンサを充電します。その点で回路図のボリューム部とコンデンサ部はそっくりな構造をしています。ここから「コンデンサとボリュームの電位が等しくなる瞬間を検出する」という仕組みが想像できます。 またそのことで、R4,R5の抵抗値を同じにしています。この値は先述の実験から10kΩとしました。 2倍の20kΩではボリューム最大(入力電圧最大)での充電に時間がかかり、カウンタで計りきれませんでした。 半分の4.7kΩでは充電時間が短く、A/Dコンバータの分解能が低くなり(入力電圧最大と最小のカウンタ値の差が小さい)、実用的ではありませんでした。 |
VRとR5の抵抗値の関係 |
ボリュームの抵抗値 ボリューム(可変抵抗)が10kΩである理由は、手持ちの部品がたまたま10kΩだったからです。他のボリュームを使うとしたら、R5とVRでVCC(5V)を分圧したときVR側の電圧(AIN1に入力される電圧)の最大値が2V前後(感覚的に1.8〜2.2V)になるよう、R5を決めます。 仮に5kΩのボリュームを使うなら、5kΩ:R5=2V:3V → R5=7.5kΩです。R4も7.5kΩにします。 計算値と一致する抵抗が実際に存在するとは限らないので(E24系列)、存在する近い抵抗値を使うことにして、VRにかかる電圧が2V前後になるか再計算して確認するとよいでしょう。 なお、R4の値を変更するとコンデンサC2の充電時間が変わります。そうするとA/Dコンバータの分解能が変わり、ブロック崩しとしてはバーの動きに影響が出ます。 |
プログラムについて A/Dコンバータ用の16bitカウンタは割り込みを使っていません。先述の説明通り、走査線1本描画毎にアナログコンパレータの結果を読み、カウンタを止めています。 コンデンサの放電時間は1フィールド〜1/2フィールドくらいの時間でよさそうでした。それより短いと十分に放電できていない様子でした。 ボリュームの軸を回してバーがマスの変わり目ギリギリくらいにあるとき、バーがビクッと動くことがあります。 カウンタの値がたまに飛び抜けた値になるからです。この現象を抑えるため、カウンタの値は何回分かを平均して使います。 平均を取る回数が多いほど平滑化の効果は上がりますが、その分、軸の回転とバーの移動タイミングのズレが広がります。 ゲームの操作方法 ゲームはスイッチとボリュームのどちらでも操作できます。 スイッチでプレイするには、スイッチ左または右を押下してプレイ開始します。 ボリュームでプレイするには、バーを左端または右端まで移動してプレイ開始します。 ブロックを全部消したらクリア、ボールを落としたらゲームオーバー。どちらもすぐに次のプレイ待機状態になります。 通常プレイの弾道で斜めは45度方向のみでしたが、バリエーション型の弾道として「傾き2」の打ち返しができるようにしました。 左右どちらかのスイッチを押しながら電源を入れるとバリエーション型のプレイができます。通常プレイに戻すには電源を入れ直します(スイッチを押さずに電源を入れる)。 傾き2のボールの動きは微妙です。画面で見える1マスの大きさがそのまま移動単位ですから、かなりガタガタして見えます。 |
|
手順2:ボリューム最大 手順3:ボリューム最小 |
キャリブレーション アナログ入力の調整(キャリブレーション)の方法を説明します。 プログラムの先頭付近、#define群の最後の方にアナログ入力関連の定義があります。ここで調整します。 手順1: #define _ADC_DEBUG 1 //0:本番 1:デバッグ表示 ここで「1」を指定し、ビルドし、hexをATtiny2313に書き込み、電源を入れます。前出の動画と同じ画面が映ります。 手順2: ボリュームを一番右へ回します。バーが右へ動きます。 画面のブロック表示は2進数を表しています。灰色を1、黒を0として値を読み取り、それをACADC_MAX_PREに書きます。 表示が安定するより心持ち手前の値を指定するとよいです。 #define ACADC_MAX_PRE 0b01000000 手順3: ボリュームを一番左へ回します。バーが左へ動きます。 画面から値を読み取り、それをACADC_MIN_PREに書きます。 #define ACADC_MIN_PRE 0b00000100 手順4: ここでビルドし、hexをATtiny2313に書き込み、電源を入れます。 ボリュームを左右いっぱいまで回し、バーが左右端まで移動するか確認します。 端まで行かないときは手順2〜3の値を適当に変えながら調整を繰り返します。 手順5: 調整ができたら、手順1で指定した値を「0」に戻し、ビルドし、hexをATtiny2313に書き込みます。 これでキャリブレーション完了です。 ボリュームとバーの真ん中を合わせるのはなかなか難しいです。入力電圧が2V(ATMELの資料では「VCCの2/5」)を超えると、このA/Dコンバータの線形性が失われるためでしょう。 ※そういうことにして次へ行く。 【参考】 手順説明と動画の値ではACADC_MIN_PREが0b00000100となっています。これはブレッドボード上に組んだ回路での値なのですが、基板で製作したらこの値は0b00001000になりました。 これでも左右端を調整することは簡単ですが、真ん中合わせは、より難しくなっていました。 |
基板に実装する
部品について
電源コネクタやISP用のピンヘッダは部品一覧には書きませんが、必要に応じて用意してください。ICソケットはあった方がよいでしょう。 基板は25x15穴の片面基板を使いました。1枚80円程度です。完成品をケースに収めて使うかどうかも考慮し、好みのサイズの基板を使ってください。 抵抗は R2 470Ω [黄紫茶金] の値を確かめるときに注意することがあります。 抵抗に印刷された色で紫と茶の区別が付きません。光にあててよーく見ないと分かりません。 お店のケースの中に間違った値の物が混ざっていることは無いと思いますが、買うときに念のため確認してください。 クリスタル発振用のコンデンサの値はATtiny2313のデータシートを参考にしてください。 22pFでよいと思います。 ただのセラミックコンデンサと積層セラミックコンデンサのどちらでも構いません。 今回の製作物において、コンデンサ内蔵のセラロックで正常に動作しています。 コストの面からこちらをお勧めします。 回路図の点線囲みの部分、「クリスタル+コンデンサ2個」をセラロックに置き換えてください。 ボリューム(可変抵抗)はBカーブのものを使います。これは軸の回転量に比例して抵抗値が変化します。ちなみにオーディオの音量調節で使うタイプはAカーブです。これは抵抗値が対数的に変化します。 ボリュームを基板やケースに固定するナットが付属しているとは限りません。購入時に確認してください。付いてなければ必要に応じて別途購入してください。 RCAジャックはお馴染みの黄色いビデオケーブルを差し込むジャックです。 基板実装型とケース取り付け型の形状があります。 基板を剥き出しで使う場合は基板実装型にします。ケースに収めて使う場合、どちらの形状がよいかはケースの加工の仕方によります。 RCAジャックは端子の使い方で注意することがあります。下記参照。 |
RCAジャック 基板実装型やケース取り付け型がある。 端子が2つならSIGNALとGND. 端子が3つの場合、3つめはジャックの固定を兼ねるもう1つのGNDか、またはスイッチになっている。 写真は基板実装型でスイッチ端子が付いているもの。 1:GND 2:SIGNAL 3:SWITCH ケーブルを挿していない状態では端子2番と3番がつながっている。 ケーブルを挿すと2番と3番が離れ、ケーブルの信号線は2番とつながる。 このとき3番は1番とも2番ともつながっていない。 オーディオ製品で、普段はスピーカから音が出ていて、ヘッドホンをジャックに挿すとスピーカの音が途切れてヘッドホンから音が出るようになるものがある。それと同じ仕組みである(端子2番に回路からの音声信号、3番にスピーカをつなげば、そのようになる)。 今回の製作では端子1番、2番を使う。 3番は放置。またはジャックを固定する際の補強のため、基板にハンダ付けしておく。 |
部品名 | 部品番号 | 値 | 個数 | 参考価格/備考 |
AVR(マイコン) | ATTINY2313 | ATtiny2313 | 1 | 100円(秋月電子) |
抵抗 | R1 | 1.2kΩ [茶赤赤金] | 1 | 1個5円/100個100円 |
抵抗 | R2 | 470Ω [黄紫茶金] | 1 | 1個5円/100個100円 |
抵抗 | R3 | 75Ω [紫緑黒金] | 1 | 1個5円/100個100円 |
抵抗 | R4,R5 | 10kΩ [茶黒橙金] | 2 | 1個5円/100個100円 |
ボリューム(可変抵抗) | VR | Bカーブ10kΩ | 1 | 90円 |
積層セラミックコンデンサ | C1,C2 | 0.1uF [104] | 2 | 10個100円 |
タクトスイッチ | SW1,SW2 | 2 | 10個180円 (千石電商 店頭価格) |
|
RCAジャック | J | 黄色 | 1 | 30円 |
クリスタル | XTAL | 20MHz | 1 | 10個500円(秋月電子) |
(積層)セラミックコンデンサ | クリスタル発振用 | 22pF | 2 | 1個20円 |
セラロック | 点線囲み部分 | 20MHz | 1 | 40円 |
まとめ AVRでビデオ信号を生成し、TVに映像を出力するハードを製作しました。 AVRはATtiny2313を使いました。これにはA/Dコンバータが付いていません。 そこで、アナログコンパレータを応用したA/Dコンバータを作りました。 ソフトは、アナログ入力で操作するブロック崩しを作成しました。 自作のA/Dコンバータを使ってブロック崩しのバーを操作することができました。 |