【概要】
マイクロチップ社の最新チップである、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ビットの使い方がこれまで無かったものになり、下図の
ような指定になります。
アナログ入力ポートの使い方の設定は下表のようになります
Aはアナログ入力 Dはディジタル入出力 Vref+ Vref-は基準電圧入力
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
基準電圧入力の指定が無いときは、電源電圧が基準となる。
【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は誰でもダウンロードできます。