目次
前
次
A/D処理
ATmegaチップの内蔵A/D変換器を動かしてみます。
Arduinoが動作する基板を利用。
A/D変換器は、ポートCの6ビットのピンのいずれかに
接続されるので、コネクタをつけている基板を使うと
電圧測定に都合がよいため、Arduino基板を利用。
ATmega328のSFRを確認。
A/D変換器を制御するには、データと制御ステータスの
2レジスタに関する仕様を理解しなければなりません。
制御ステータスレジスタは、ADCSRA、ADCSRBという
ラベルがつけられ、データレジスタを合わせてワード
「constant」を利用して、文字列で扱えるようにして
おきましょう。
$7f constant DIDR1
$7e constant DIDR0
$7c constant ADMUX
$7b constant ADCSRB
$7a constant ADCSRA
$79 constant ADCH
$78 constant ADCL
各レジスタの内容を見ていきます。
ADCL ADCH
ATmegaのA/D変換器は、10ビットのデジタル値を
生成するので、16ビット分のレジスタが必要。
16ビット中に10ビットを展開するので、ADMUXのADLARビット
により、左詰めをするか否かを指定できます。
ADLARの論理値で、10ビットは次のように配置されます。
ADCSRA
A/Dコンバータの制御とスタータスを
知るために、このレジスタを使います。
アナログ→デジタルの変換では、比較が必要。
比較には、カウンタを使うのでクロックを与えます。
下位ビットにある、ADSPの組合わせで
システムクロックを分周したクロック
のいずれかを選びます。
MSBにあるADENビットで、A/D変換器を使うか
否かを指定。A/D変換器を使わないときは
内部回路の電源をカットしています。
ADSCビットを1にすると、A/D変換を開始。
変換が終了すると、自動的に0になります。
システムクロックを分周したクロックをもとに
変換するので、A/D変換器モジュールに与える
クロックで、おおよその変換時間を見積もること
ができます。
ADATEビットを1にすると、A/D変換を開始し
終了する動作を繰り返します。
8ビットレジスタのADCSRBに設定する値で、自動処理
の詳細を指定します。
ADIE、ADIFは、A/D変換終了時の割込みに
関係するビットです。今回は、使いません。
DIDR0 DIDR1
A/D変換器を使うとき、チップのアナログ入力と
デジタル入出力を兼用するピンの動作モードを
指定するために利用。
DID = Digital Input Disableを見れば、デジタル
入力禁止とわかります。
アナログ入力が多いチップでは、DIDR1をもつ
デバイスもあります。
Forthインタプリタが起動したときは、ともに$00。
調べるのは簡単で、次の操作で確認できました。
DIDR0 c@ .{enter}
DIDR1 c@ .{enter}
A/D変換器を使うときには、使いたいビットに1を書き込み。
ポートCの0ビット目をA/D変換で使うときは
次のように入力。
DIDR0 c@ $01 or DIDR0 c!{enter}
ポートCの6ビット中の任意のビットを、A/D変換で
使うようにしたいときには、ワードを用意しておく
と、ミスが少なくなるでしょう。
A/D変換器の入力に設定と解除には、次のワード定義。
: adc.sele 1 swap lshift DIDR0 c@ or DIDR0 c! ;
: adc.seld 1 swap lshift $ff xor DIDR0 c@ and DIDR0 c! ;
使いたいピンが、ポートCの4ビット目だとすると
次のようにタイプ。
4 adc.sele{enter}
大まかな仕様を理解したとして、初期化ワード
を定義していきます。
PC0を利用し、クロックを最低周波数に。
: adc.init ( -- )
0 adc.sele
1 5 lshift ADMUX c@ xor ADMUX c!
1 7 lshift 7 or ADCSRA c!
;
シフトを利用して、ADMUXのADLARビットの値を指定。
ADCLの8ビット全体を使い、ADCHの下位2ビットに
10ビットを展開するようにしてみました。
A/D変換の開始と終了を制御するワードを定義します。
: adc.start ( -- )
1 6 lshift ADCSRA c@ or ADCSRA c!
begin
ADCSRA c@ 6 rshift 1 and =0
until
;
変数advを用意して、A/D変換の結果を格納します。
variable adv
: adc.do
adc.init
adc.start
ADCH c@ 3 and 8 lshift
ADCL c@ or
adv c!
;
ポートCの0ビット目に、電池を接続して電圧測定します。
デジタル値から電圧値への換算は、次式を利用。
V = 50 * adv / 1024
Forthは、整数計算しかできないので1.5Vや2.3Vを表現できません。
予め10倍した値を求め、10で割った商と余りを計算するのが定石。
ワードを定義します。
: show.adc
50 * 1024 /
10 /mod swap ( quotient residue -- residue quotient )
$30 + emit \ quotient
$2e emit \ .
10 / $30 + emit \ residue
cr
;
ワード「emit」は、ASCIIコードを端末に出力するので
数値から数字への変換。
商と余りをワード「/mod」で求めたら、スタック内での
位置関係を交換。
余りは、1桁にするため10で割った商を求めています。
小数点を入れたいので、「.」($2e)をスタックに置いて
からワードを呼び出し。
使い方は、以下。
256 show.adc{enter}
A/D変換を一気にするためのシーケンサは、次のワードで。
: adv.show
adc.do adv c@ show.adc
;
目次
前
次