アナログ-デジタル変換(ADC)について

〔PICの動かせ方入門に戻る〕


24EP256MC202のA/D変換モジュールが今までの8ビット版PICとは異なり、
かなり高機能で複雑っぽいので忘れない様に書いて置きますが、高機能な部分にはふれません。
MPLAB X V2.15MPLAB(R) XC16 C Compiler Version 1.24コンパイラ を使用しての記事です。
ADCのPIC24E用日本語リファレンスマニュアルはこちらを参照下さい。

ADC(アナログ/デジタルコンバータ)の主な特徴は
 ・逐次比較型(SAR)変換、複数のチャンネルを逐次サンプリング/変換します。
 ・独立した4つのモジュールが有り、最大4本のアナログ入力ピンによる同時サンプリング可能。
 ・アナログモジュールは、10ビット/4 チャンネル又は12ビット/1 チャンネルADCとして設定出来ます
 ・サンプリング/変換は手動と自動が可能で、自動チャンネルスキャンモードの動作も可能。
 ・変換のタイミング指示をPWM/Timer/INT0からトリガー出来る。
 ・DMA機能が利用出来る
  (DMAは、CPUに負荷をかけずに、CPU(メモリー)とADC 間でデータを転送する機能です。)

ピンの構成図
24EPxxxMC202のアナログピン構成図です。
AN0-AN5までがアナログ使用可能で、VREF-/VREF+がリファレンス電圧用ピンです。
又、AVDD/AVSSとアナログ専用電圧入力ピンが有ります。
VREF+ = AVDD = VDD = 3.3V(MAX3.6V)

ADCモジュールは4チャンネル有り、チャンネルによって入力可能なアナログピンが決まっています
チャンネル0の選択はAD1CHS0レジスタチャンネル1-3の選択はAD1CHS123レジスタで行います。
(アナログピンをダブって割り付けても動作しますが、同じ値を得るだけです)
尚、チャンネル1のCH-AをAN0とした場合は、CH2=AN1・CH3=AN2と割り当てられます。

チャンネル0 チャンネル1 チャンネル2 チャンネル3
CH-A AN0-AN5 AN0(AN3) AN1(AN4) AN2(AN5)
CH-B AN0-AN5 AN3(AN0) AN4(AN1) AN5(AN2)
10ビット
12ビット - - -

AD1CON2レジスタの"ALTS"ビットで、CH-A/CH-Bの何れかでサンプリングするのかを選択します。
ALTS=0 :常にサンプルA 用チャンネル入力選択を使う
ALTS=1 :最初のサンプリングでCH-A入力を使い、次のサンプリングでCH-B入力を使う
      (全チャンネルのCH-Aをサンプリングした後にCH-Bがサンプリングされます)

自動チャンネルスキャンモードと12ビットモードはチャンネル0のみ可能です、
12ビットモードにした場合は、チャンネル1−3は使用できません。
自動チャンネルスキャンモード時のチャンネル選択(AN0-AN5)は、AD1CSSLレジスタで行います。

使用するアナログピンは、ANSELA/ANSELBレジスタでアナログ/デジタルを切り替えます、
又、TRISA/TRISBレジスタで入力に切り替えます。

AD1CON2レジスタの"CHPS"ビットで、使用するチャンネルを選択します、
下記表の3パターンの組み合わせのみです、個別には選択できません。

CHPS チャンネル0 チャンネル1 チャンネル2 チャンネル3
00 - - -
01 - -
11(10)

複数チャンネル(CHPS=01/1x)を選択した場合は、AD1CON1レジスタの"SIMSAM"ビットで、
「同時にサンプリングする」「逐次サンプリングする」を選択します。

サンプリングし変換が終了すると、
16ワードのADCバッファレジスタ([ADC1BUF0]〜[ADC1BUFF])に格納されます。
例えば、下の様に割り付けて、チャンネル0と1を使用するとした場合のバッファは、

チャンネル0 チャンネル1 チャンネル2 チャンネル3
CH-A AN1(RA1) AN0(RA0) AN1 AN2
CH-B AN2(RB0) AN3(RB1) AN4 AN5

ADCバッファの構成図
  ANSELA = 0b0000000000000011 ;// AN0/1はアナログ、他はデジタルI/Oに割当
  ANSELB = 0b0000000000000011 ;// AN2/3はアナログ、AN4/5アナログは使用しない
  TRISA  = 0b0000000000000011 ;// RA0/1は入力、RA2-4は出力に設定、1で入力 0で出力
  TRISB  = 0b0000000000000011 ;// RB0/1は入力、その他は出力に設定
  AD1CHS0   = 0b0000001000000001 ; // CH0=A(AN1)B(AN2)
  AD1CHS123 = 0b0000000100000000 ; // CH1=A(AN0)B(AN3)
  AD1CON1bits.SIMSAM = 1 ;         // 同時にサンプリングする
  AD1CON2bits.CHPS   = 1 ;         // チャンネル0と1を使う
                      AD1CON2bits.ALTS   = 1 ;         // サンプルABチャンネルを使う
上記の様にバッファリングされますが、もし、"ANSELB"で"AN2"をデジタルとした場合、
ADC1BUF2は使用されなく開いたままで内容は不定な値です。

(ADC関連レジスタ)

ADC関連レジスタの詳しい内容は、日本語のリファレンスマニュアルを見て下さい。
少々書くのがメンドイのでここでは簡単に説明します。

AD1CHS123
 チャンネル1−3モジュール用で、アナログ入力を行うピンの設定を行います。
 正極性側と負極性側の両方設定、サンプルA(CH-A)/B(CH-B)チャンネルの両方設定が有ります。

AD1CHS0
 チャンネル0モジュール用で、アナログ入力を行うピンの設定を行います。
 正極性側と負極性側の両方設定、サンプルA/Bチャンネルの両方設定が有ります。

AD1CSSL
 チャンネル0で入力スキャンモードを行う場合のアナログ入力ピンを選択します。

AD1CON1
 ADCの制御を行うレジスタです。
 // 10bit,符号なし整数変換,手動モード、チャンネルは同時にサンプリングでの例
 AD1CON1 = 0b0000000000001000 ;
 FORM :データ変換の出力フォーマットを選ぶビット
      00 = 符号なし整数 01 = 符号付き整数 10 = 符号なし小数 11 = 符号付き小数
 ADON :ADCモジュールの有効/無効を設定するビット
      0 = ADCモジュールを無効  1 = ADCモジュールを有効
      全ての設定が完了した後に"有効"と設定します

AD1CON2
 ADCの制御を行うレジスタです。
 // リファレンスはAVDD/AVSS、CH0/1のA用チャンネルのみ使う、1回サンプリングでの例
 AD1CON2 = 0b0000000100000000 ;
 // AVDD/AVSS、CH0のABチャンネル交互に読む、2回サンプリングでの例
 AD1CON2 = 0b0000000000000101 ;

AD1CON3
 変換を行うクロックの選択とサンプリング時間の設定を行います。
 // 変換クロックはFCY、0TAD(手動時)、変換クロック分周=8での例
 AD1CON3 = 0x0007 ;
 // 変換クロックはFCY、3TAD(自動時)、変換クロック分周=8での例
 AD1CON3 = 0x0307 ;
 SAMC :自動時のサンプリング時間を設定するビット
      0TAD〜31TAD
      手動時はソフト側で待つ(リファレンスマニュアルでは10us程待っている?)
      最少サンプリング時間は、"10bit=2TAD 12bit=3TAD"掛かる
 SADCS:ADC変換を行うクロック(周期)を設定するビット
      ADCのクロック周期は"10bit=76ns 12bit=118ns"でFCY=60MHzなら
      TAD=(1000000000/60000000)*8=133ns(12bit時)なので、SADCS=8-1の7で設定する
      1つのサンプリングの変換に"10bit=12TAD 12bit=14TAD"掛かる。

AD1CON4
 DMA機能を使用する場合に設定を行うレジスタです。

AD1BUFx
 サンプリング/変換が行われた結果のデータを格納するレジスタです。
 AD1BUF0〜ADBUFFの16ワード分有ります。

(参考回路)

回路図  半固定抵抗(20KΩ)使った実態配線図
 です、電源は3.3V。

 アナログ専用電圧AVDD(28番)/
 AVSS(27番)はVDD(13番)/VSS(8・19番)と
 同じ電源に接続しています。

 内蔵のレギュレータ用にVCAP端子(20番)
 に、10uFのコンデンサーを取付けVSSに
 落とす必要が有ります。

1番ピンはMCLR専用なのでリセット回路を取付けないのなら1K-10KΩ抵抗でVDDに接続します。
アナログピンはAN0(RA0)とAN1(RA1)を使い、リファレンス電圧はAVDD/AVSSとなっています。

(サンプルプログラム)

I2C接続でLCDに表示を行う為の記事やソースファイルはこちらのページを参照下さい。

参考回路のサンプルソースファイルは↓ここからダウンロードして下さい。
ADC.lzh
 AD_No10.c・・・・・・・・・・・CH0/CH-AにAN0を割付け、10bitの手動で読込むサンプル
 AD_No11.c・・・・・・・・・・・CH0/CH-AにAN0を割付け、12bitの手動で読込むサンプル
 AD_No20.c・・・・・・・・・・・CH0/CH-AにAN1・CH1/CH-AにAN0を割付け、10bitの手動で読込むサンプル
 AD_No22.c・・・・・・・・・・・CH0/CH-AにAN1・CH1/CH-AにAN0を割付け、10bitの自動で読込むサンプル
 AD_No30.c・・・・・・・・・・・CH0/CH-AにAN0・CH-BにAN1を割付け、12bitの自動で読込むサンプル
 AD_No40.c・・・・・・・・・・・CH0スキャン入力にAN0/AN1を割付け、12bitの自動で読込むサンプル

"AD_No30/40.c"のみチャンネルは逐次サンプリング、他は同時にサンプリングに設定
自動は、サンプリングもデータ変換も全て自動にて行われます。

// AD_No10.cの設定内容です、手動でサンプリングと変換の指示を出す
void analogRead(int *value)
{
     AD1CON1bits.SAMP = 1;         // サンプリングの開始
     __delay_us(10) ;              // サンプリングの終了まで待つ(10usも待たなくて良い様な気が....)
     AD1CON1bits.SAMP = 0 ;        // 変換の開始
     while (!AD1CON1bits.DONE) ;   // 変換の終了まで待つ
     *value = ADC1BUF0 ;           // アナログ値(AN0)を読み出す
}
int main(void)
{
     // A/D変換情報の設定(CH0:10bit:DMA無:手動サンプリング:手動変換)
     AD1CHS0   = 0b0000000000000000 ; // CH0=A(AN0)B( )
     AD1CHS123 = 0b0000000100000000 ; // CH1/2/3使用しない
     AD1CON1   = 0b0000000000000000 ; // 10bit,符号なし整数変換,手動モード、チャンネルは逐次サンプリング
     AD1CON2   = 0b0000000000000000 ; // AVDD/AVSS,CH0のA用チャンネルのみ使う,1回サンプリングのみ
     AD1CON3   = 0x0007 ;             // 変換クロックはFCY,0TAD,変換クロック分周=8
     AD1CON4   = 0b0000000000000000 ; // DMAは使用しない
     AD1CON1bits.ADON = 1 ;           // A/D変換モジュールを有効にする
     __delay_us(20) ;                 // アナログ段が安定するまで待機する

     while(1) {
          analogRead(ad_dt) ;
          // LCDに値を表示する
          sprintf(buf,"AN0=%d   ",ad_dt[0]) ;
          LCD_SetCursor(0,1) ;
          LCD_Puts(buf) ;
          __delay_ms(500) ;
     }
}
 サンプリングの終了を待つのに10usでなく1us待てば十分と思われるがぁ....
  同時サンプリングは1回で読むとして、逐次サンプリングの場合はアナログピンの分のサンプリング時間を
  確保しないとダメなのかが今一解らない。
  ここはリファレンスマニュアルのサンプルプログラム通りにして置きます。

// AD_No30.cの設定内容です、サンプリングと変換は自動で行う。
void analogRead(int *value)
{
     while (!_AD1IF) ;             // 変換完了まで待つ
     _AD1IF = 0 ;                  // フラグクリア
     *value = ADC1BUF0 ;           // アナログ値(AN0)を読み出す
     value++ ;
     *value = ADC1BUF1 ;           // アナログ値(AN1)を読み出す
}
int main(void)
{
     // A/D変換情報の設定(CH0:12bit:DMA無:自動サンプリング:自動変換)
     AD1CHS0   = 0b0000000100000000 ; // CH0=A(AN0)B(AN1)
     AD1CHS123 = 0b0000000100000000 ; // CH1/2/3使用しない
     AD1CON1   = 0b0000010011100100 ; // 12bit,符号なし整数変換,自動モード、チャンネルは逐次サンプリング
     AD1CON2   = 0b0000000000000101 ; // AVDD/AVSS,CH0のABチャンネル交互に読む,2回サンプリングする
     AD1CON3   = 0x0307 ;             // 変換クロックはFCY,3TAD,変換クロック分周=8
     AD1CON4   = 0b0000000000000000 ; // DMAは使用しない
     AD1CON1bits.ADON = 1 ;           // A/D変換モジュールを有効にする
     __delay_us(20) ;                 // アナログ段が安定するまで待機する

     while(1) {
          analogRead(ad_dt) ;
          // LCDに値を表示する
          sprintf(buf,"AN0=%d   ",ad_dt[0]) ;
          LCD_SetCursor(0,0) ;
          LCD_Puts(buf) ;
          sprintf(buf,"AN1=%d   ",ad_dt[1]) ;
          LCD_SetCursor(0,1) ;
          LCD_Puts(buf) ;
          __delay_ms(500) ;
     }
}

※ PIC18F以下ではアナログ入力が複数ある場合は、アナログピンを切り替えながら行っていたが、
   PIC24EPは必要なアナログは全て割り付けて置き、1回の動作で全アナログを読み込む感じぃ。

※ サンプリングも変換も自動であれば必要な時に変換されたデータを読み出せばよいので便利だが
   常に動作しているから消費電力を考えれば手動ですね。

※ アナログ入力を行う場合は、ピンをAN0,AN1,AN2...と順番に使い、チャンネルも0,1,2-3と
   これも順番に使っていた方が操作しやすい様に思われる。




【きむ茶工房ガレージハウス】
Copyright (C) 2006-2015 Shigehiro Kimura All Rights Reserved.