[戻る]

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コンバータとは
ブロック崩しのバーをボリューム(可変抵抗)で操作しようと思います。軸のねじり具合を電圧の変化としてマイコンに伝えれば、そういうことができます。ただ、電圧の値は小数なので、そのままではプログラムで扱いにくいです。
ここでマイコンには、入力された電圧を一定範囲の整数に変換してプログラムに渡す機能があります。
例えば電圧測定用のピンに0〜5Vを入力すると、マイコンはこれを0〜255の値に変換します。「3.5V」を入力するとプログラム上では「178」として値が取得できます。(3.5 / 5) * 255 = 178

この、アナログ(電圧)→デジタル(一定範囲の整数)に値を変換する機能をA/Dコンバータ(Analog/Digital Converter)と言います。ボリューム(可変抵抗)を通した入力や、温度センサからの入力、音声入力などを扱うにはお馴染みの機能です。

A/Dコンバータはマイコン組み込みの機能としてだけでなく、単品のICとしても様々な性能(分解能や変換速度)のものが販売されています。先の例では分解能が256段階(8ビット)ですが、10ビットのA/Dコンバータを使えば分解能は1024段階なので、入力した電圧は0〜1023に変換されます。
入力できる電圧の上限はA/Dコンバータの仕様によります。マイコン内蔵のA/Dコンバータの場合は基本的にマイコンの電源電圧までです。
2011/01最後3行の説明を修正。



ATtiny2313のA/Dコンバータ?
残念なことにATtiny2313にはA/Dコンバータ機能がありません。ですが、2つの電圧を入力し、どちらが高いか判定するアナログコンパレータ(アナログ比較器)という機能が付いています。このアナログコンパレータを応用してA/Dコンバータを作ることができます。

アナログコンパレータ専用の入力ピンAIN0,AIN1(I/OピンのPB0,PB1と兼用)を使います。回路はAIN0にコンデンサがつながっていて、PB2から充電できるようになっています。
【1】AIN1に計測したい電圧を入力します。このときコンデンサは放電しておきます。
【2】コンデンサの充電を開始します。それと同時にカウンタをスタートします。充電時間をストップウォッチで計測するということです。
【3】充電中のコンデンサの電圧がAIN0に入力されます。AIN0とAIN1の電圧が随時比較されます。

充電を開始すると(AIN0 < AIN1)からAIN0が徐々に大きくなり、(AIN0 < AIN1)→(AIN0 = AIN1)→(AIN0 > AIN1)と変化します。
アナログコンパレータで電圧が(AIN0 = AIN1)になった瞬間(厳密には(AIN0<AIN1)から(AIN0>AIN1)に変わる瞬間)を検知して、このときのカウンタの値をA/Dコンバータの変換値として使おうというわけです。

アナログコンパレータ応用のA/Dコンバータ



実験
前回の製作でPB0,PB1につなげていたスイッチをPB3,PB4に移し、AIN0(PB0),AIN1(PB1)にそれぞれコンデンサとボリューム、抵抗をつなげました。
左の写真で、中央手前の小さい水色の部品が主役となるコンデンサです。
右下の4つの抵抗は直列につながっていて、黒い線を挿す位置によって10k,20k,30k,40kΩになります。実験しながら値を検討しているところです。

(動画)
ATtiny2313 ビデオ出力 A/Dコンバータ
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になりました。
これでも左右端を調整することは簡単ですが、真ん中合わせは、より難しくなっていました。

基板に実装する




基板を加工する
ここまでブレッドボード上に回路を組んで動作確認してきました。各部品の値も決まったし、基板に実装して完成させます。

ボリュームをどう乗せるかが工夫のしどころでしょうか。軸の太さで穴を空け、基板の裏側から軸を通し、表側からナットで止めるのが普通のやり方だと思います。ボリュームには部品の回転ズレ防止のツメも付いています。
しかし実はこれに合うナットを持っていないので(そういった付属品なしの安い部品を買ったので)、表側から固定することにしました。基板に部品サイズの穴を空けて表側からはめ込みます。

ビデオケーブルを挿すRCAジャックは基板実装用のものを使います。取り付ける穴は現物合わせで空けます。


初期案


決定した配置

部品配置を検討する
ブレッドボード上の部品を外し、回路図を見ながら部品配置を検討しているところです。まだハンダ付けはしていません。
部品が2セットあれば、ブレッドボード上の配線を見ながら基板に部品を置いていく、という方法もあります。

今後の拡張のことを考えて(するかは分かりませんが)、未使用のI/Oピン付近はなるべく空けておくようにします。
初期案ではまだPD0(RxD),PD1(TxD)を空けることは考えていませんでした。また、実はボリュームにつなぐ抵抗の配置を間違えています。

部品配置が決定したらデジカメで撮影して、印刷するかモニタに映して、それを見ながらハンダ付けすると作業しやすいです。
部品の切りカスなどでモニタ画面を傷付けないよう注意!

後から分かったことですが…
最終的に完成したものとブレッドボード上で動作していたものでは、A/Dコンバータの性能が若干違いました。完成品ではコンデンサの充電時間がわずかに長くなりました。配線の引き回しやハンダ付けの具合が影響したのかもしれません。
一応、そういった影響が出にくい配置を意識したつもりだったのですが、全く同じにはなりませんでした。




ハンダ付けする
ビデオ出力のRCAジャックは端子(兼・固定用のツメ)をハンダ付けしただけなので、強い力を加え続けるとハンダが割れて接触不良を起こす可能性があります。接着剤で固めるか、紐類で縛るとベターです。
それほど強くビデオケーブルを引っ張り回すことはないと思いますが。

ボリューム操作中には、軸を押し込む力と端子が浮き上がる力が加わります。
端子付近が基板に接しているので、ここを支点にして縛ります。
さらに補強するには、スズメッキ線などをかぎ爪状にして、ボリュームを底面から支えるようにハンダ付けする方法が考えられます。

しかし今回、敢えてそれをしませんでした。ゲーム中、ボリュームの底面に手が触れる度に、何かが手に引っかかる感触があるのはイヤだなと思いまして。
それでボリュームの頭付近をスズメッキ線で引っかけるようにしてハンダ付けしています。しかしすぐに外れてしまうと思います。気休めです。




完成
ボリュームにツマミを付けました。緑の基板、黄色のジャック、青いツマミ、見た目にも楽しいです。

手に持って操作するものなので、裏面はゴムシートなどで覆った方がよいかもしれません。汗で基板がショートする可能性があります。

部品について

電源コネクタや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番は放置。またはジャックを固定する際の補強のため、基板にハンダ付けしておく。


ATtiny2313 ビデオ出力 ブロック崩し「アナログコンパレータ応用A/Dコンバータ版」
部品一覧
 (回路図はここをクリック
部品名 部品番号 個数 参考価格/備考
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コンバータを使ってブロック崩しのバーを操作することができました。


[戻る]
inserted by FC2 system