PIC16F87xのA/D変換の使い方


【概要】

マイクロチップ社の最新チップである、PIC16F87xシリーズには、待ちかねて
いた10ビットのA/D変換モジュールが内蔵されました。
ここでは、この10ビットA/D変換モジュールの使い方を主にCコンパイラを
ベースにして説明しています。

【10ビットA/D変換の概要】

PIC16F87xシリーズの10ビットA/D変換は、逐次変換方式で、分解能が
1024段階になったことになります。
これまでが8ビットで256段階しかなかったので、測定には分解能不足で
使えませんでしたが、今回はかなり応用範囲を広げることが出来ます。
1024の分解能があるということは、1Vの電圧を測るときには1mV単位
で計測できるということになるからです。


【10ビット保証の条件】 2003/7/24

ここで、このA/D変換モジュールが10ビットの精度を出すためには、条件が
あります。下記を守らないと10ビットの精度は保証されませんので要注意。

(1) 条件1  Vref+ − Vref- > 2V 
      つまりリファレンス電圧差が2V以上必要ということです。
(2) 条件2  Vdd+0.3V > Vref+ > 2.5V 
      つまりVref+は必ず2.5V以上でないとだめということです。

この2つが守れていないと10ビットの動作はしますが、完全な精度は出ません。
従って、Vref+側だけ使い、Vref-は0Vとするときには、Vrerf+は2.5V以上に
しないと精度が出ないことになります。

【A/D変換に必要な変換時間】

PICでは、A/D変換をするために、まずアナログ信号を一旦内部のコンデンサ
に蓄えます。その後、参照となる一定の電圧を加算して比較しながら計測する
という原理であるため、A/D変換を正確に行うためには、蓄積するまでの時間
と計測する時間の両方を確保することが必要になります。
従来のPICの場合と比較して、この時間がどれぐらいかというと

蓄積時間+計測時間=
 (従来8ビット)
    12μsec+1.6μsec×9.5 =最小28μsec
 (今回10ビット)
    20μsec+1.6μsec×12 =最小39μsec
となります。(クロック20MHzの時)

【レジスタの詳細内容】

A/D変換制御用には3種類のレジスタがありますが、詳細内容と設定内容
は下図の様になっています。
PIC16F87xの種類によってチャンネル数が異なりますが、下図はPIC16F877
の例です。




A/D変換クロック(Tad)の設定方法は下表とします。

設定

ADCS1,0

PICのクロック周波数

20MHz

10MHz

4MHZ

1MHz

Fosc/2

00

 

 

 

2.0

Fosc/8

01

 

 

2.0

8.0

Fosc/32

10

1.6 

3.2

8.0

 

Frc

11

2〜 6 

 上表のようにクロック周波数により可能な設定は黄色の設定
 のみとなります。他の設定にした場合には、精度が保証されません。
 なぜならA/D用クロックとしては1.6μsec以上必要な為です。




ここでは特にADFMビットの使い方がこれまで無かったものになり、下図の
ような指定になります。



アナログ入力ポートの使い方の設定は下表のようになります

PCFG3−0

RE2

RE1

RE0

RA5

RA3

RA2

RA1

RA0

0000

A

A

A

A

A

A

A

A

0001

A

A

A

A

Vref+

A

A

A

0010

D

D

D

A

A

A

A

A

0011

D

D

D

A

Vref+

A

A

A

0100

D

D

D

D

A

D

A

A

0101

D

D

D

D

Vref+

D

A

A

011x

D

D

D

D

D

D

D

D

1000

A

A

A

A

Vref+

Vref-

A

A

1001

D

D

A

A

A

A

A

A

1010

D

D

A

A

Vref+

A

A

A

1011

D

D

A

A

Vref+

Vref-

A

A

1100

D

D

D

A

Vref+

Vref-

A

A

1101

D

D

D

D

Vref+

Vref-

A

A

1110

D

D

D

D

D

D

D

A

1111

D

D

D

D

Vref+

Vref-

D

A

 Aはアナログ入力 Dはディジタル入出力 Vref+ Vref-は基準電圧入力
 基準電圧入力の指定が無いときは、電源電圧が基準となる。



【Cコンパイラでの使い方】

CCS社Cコンパイラで、10ビットA/D変換を正常に動作させるには、読込む変数
をlong型かfloat型にするだけで10ビットのデータとして読込むことが出来ます。


 8ビットと10ビットさらに、右詰と左詰これらの全部が扱えるようにするため
 Ver2.732で擬似命令が追加されました。
 追加された擬似命令は下記となっていて、これを #include   <16F877>の
 すぐ次にどれかひとつを指定追加するようになりました。

   《追加擬似命令》
     #DEVICE  ADC=8   //従来同様に8ビットとして読み込まれる
     #DEVICE  ADC=10  //10ビットで右詰で読み込まれる
     #DEVICE  ADC=16  //10ビットだが、左詰めで読み込まれる。


(2003/7/24)
 実際の例で説明すると、まず下図の回路図を元にしてアナログ信号である
Analog0とAnalog1の入力をディジタルデータに変換する例を考えて見ます。
Vref+に加えるリファレンス電圧をちょうど2.047Vにすれば、フルスケールが
0V〜2.047Vの範囲となり、10ビットのA/D変換後で考えると、1ビット当たり2mV
の分解能となります。
また、リファレンス電圧を1.024の倍数とすれば、1ビット当たりちょうど1mVxn倍
の分解能とすることが出来ますので、非常に扱いやすくなります。
ただし、完全な10ビット精度にするためには、リファレンス電圧差 Vref+ − Vref-
の差が2V以上で、かつ、Vref+が2.5V以上にしないと出ませんので要注意です。
従って下記回路も、本来の10ビット精度は出ていません。さらに工夫が必要です。





≪例1≫ long型でバイナリデータとして扱う場合
   この例では液晶表示器への表示内容は下記となります。

      CH=2 03EF

   液晶表示器への表示出力にも”printf文"が使えるので簡単に
   希望するフォーマットで表示出力をすることが出来ます。


///////////////////////////////////////////
// A/D Converter test program for PIC16F877
// This A/D is 10bit mode
// LCD is SC1602BSLB or SC1602BS*B
//////////////////////////////////////////
#include <16f877.h>
#device ADC=10
#use delay(CLOCK=10000000)
#use fast_io(D)
#byte porta = 5
#byte portb = 6
#byte portc = 7
//////// Port define and link LCD library
#byte port = 8      //define port D
#define rs PIN_D0    //chip select
#define rw PIN_D1    //read/write
#define stb PIN_D2    //strobe
#include <lcd_lib3.c>

///////////////////////////////////////////////
// LCD test program main routine
// Display several message on LCD
// with some interval.
// Constant Message is send by lcd_data()
///////////////////////////////////////////////

main(){
  int  ch;      //cahnnel number
  long data;      //analog data

  lcd_init();      //initialize LCD

  setup_adc_ports(ANALOG_RA3_REF); //RA3 is Ref+ others A/D
  setup_adc(ADC_CLOCK_DIV_32);   //Fosc/32 full speed

  do {               //endless loop
   for (ch=0;ch<7;ch++){
   lcd_clear();          //clear display
   set_adc_channel(ch);      //set channel
   delay_us(50);
   data=read_adc();        //get data 10 bits
   printf(lcd_data,"CH=%1U %4LX",ch,data);
   delay_ms(1000);
  }
 }while(1);
}



≪例2≫ float型で10進小数として扱う場合
  この例でいうと液晶表示器の表示は下記となり、直接入力電圧値を
  表示させることが出来ます。

      CH=0 1.002 Volt

   液晶表示器への表示出力にも”printf文"が使えるので簡単に
   希望するフォーマットで表示出力をすることが出来ます。


///////////////////////////////////////////
// A/D Converter test program for PIC16F877
// This A/D is 10bit mode
// LCD is SC1602BSLB or SC1602BS*B
//////////////////////////////////////////
#include <16f877.h>
#device ADC=10
#use delay(CLOCK=10000000)
#use fast_io(D)
#byte porta = 5
#byte portb = 6
#byte portc = 7
//////// Port define and link LCD library
#byte port = 8      //define port D
#define rs PIN_D0    //chip select
#define rw PIN_D1     //read/write
#define stb PIN_D2     //strobe
#include <lcd_lib3.c>

///////////////////////////////////////////////
// LCD test program main routine
// Display several message on LCD
// with some interval.
// Constant Message is send by lcd_data()
///////////////////////////////////////////////

main(){
  int  ch;       //cahnnel number
  float data;      //analog data

  lcd_init();       //initialize LCD

  setup_adc_ports(ANALOG_RA3_REF); //RA3 is Ref+ others A/D
  setup_adc(ADC_CLOCK_DIV_32);   //Fosc/32 full speed

  do {               //endless loop
   for (ch=0;ch<7;ch++){
    lcd_clear();         //clear display
    set_adc_channel(ch);     //set channel
    delay_us(50);
    data=read_adc();       //get data 10 bits
    printf(lcd_data,"CH=%1U %1.3f Volt",ch,data/500);
    delay_ms(1000);
   }
  }while(1);
}




(旧版保存)

【Cコンパイラの不備修正】

CCS社のCコンパイラでは、Ver2.660以降のバージョンについてはPIC16F87x
シリーズをサポートしています。
しかし、オリジナルのヘッダーファイルには一部不備があるようで、A/D変換の
設定が一部できません。

そこでまずヘッダーファイルの修正を行います。修正といっても簡単で、MPLAB
のディレクトリ下にあるPIC16C74のヘッダーファイル(16c74.h)の最後の数行の
下記部分をコピーして、PIC16F877のヘッダーファイル(16f877.h)の最後に張り
つけたあと、上書き保存します。
これでSETUP_ADC( )関数も正常にコンパイルされるようになります。


////////////////////////// Constants used for SETUP_ADC()
#define ADC_OFF        0
#define ADC_CLOCK_DIV_2    1
#define ADC_CLOCK_DIV_8   0x41
#define ADC_CLOCK_DIV_32  0x81
#define ADC_CLOCK_INTERNAL 0xc1

#define ADC_DONE 0x8C40 // Used for ENABLE/DISABLE INTERRUPTS
#define INT_ADC  0x8C40 // Used for ENABLE/DISABLE INTERRUPTS



(2001/1/12)
この不具合もVer2.7以降は修正されていますので、最新のExampleをダウロード
して展開すれば全てのヘッダーファイルが最新のものに出来ます。
このExampleは誰でもダウンロードできます。



  目次ページに戻る