目次

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
;


目次

inserted by FC2 system