今から始める電子工作 ⑧ アナログ入力 その2 analogReference(AR_EXTERNAL)
前回、A-D変換を行う上で基準となる電圧源は、不安定だが簡便な電源、マイコン内部にある安定だが電圧が低い基準電源の二通りを取り上げました。
AREF端子には任意の電圧の基準電圧源をつなげられます。I/O端子は、規格上5V以下にします。
●ポピュラなTL431を基準電圧源に使う
安定な電圧を得る素子にツェナー・ダイオードがあり、それを使った回路を使ってた事例がたくさんあります。安定化電源をICにした製品もたくさんあり、いろいろな電圧が用意されています。たとえば4V出力用を使うと、測定できる入力電圧は0~4Vとなり、使い勝手はいいかもしれません。
そのなかでも、低価格なTL431を利用します。普通のトランジスタのような3端子の形状をしている製品が昔は多かったです。今は、チップ部品になって利用されているかもしれません。
主なスペックです。TL431のデータシート
基準電圧IC TL431; 基準電圧:約2.5V、可変時~36V シンク電流:1~100mA 出力インピーダンス:0.2Ω(標準値) 動作温度範囲: 0~70℃ 動作温度範囲でのドリフト:6mV |
温度のドリフトとは、温度が変化したとき、出力電圧がどのくらい変化するかという数値です。
2.5Vを基準電圧としたとき、14ビットのA-DコンバータのLSBは、
1000 * 2.5 / 2 ^14 = 0.152mV
6 / 0.152 = 39LSB <-変化量の最大
と無視できない変化量になります。けれども0~70℃の範囲で温度が変わる環境で利用することはほとんどないと思うので、TL431の室温25℃付近で一度出力電圧を測定してスケッチに記入しておけば、通常の利用時に温度変化の影響はあまりないと考えます。
回路図です。
実装しました。ディジタル・マルチメータで測ったTL431の出力電圧は2.49598Vでした。
スケッチです。外部の基準電圧源は、analogReference(AR_EXTERNAL);で指定します。
2^14 は pow(2,14) と記述します。
const float TL431 = 2.49598; float LSB = 1000 * TL431 / pow(2,14); void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReference(AR_EXTERNAL); analogReadResolution(14); } void loop() { delay(1000); Serial.print(analogRead(0)); Serial.print("\t"); Serial.println(analogRead(0) * LSB); }
実行結果です。アナログ入力A0には1.0000Vをつないでいます。
回路の中で、1kΩは適当な数値を選んでしまったのですが、検証します。
抵抗の左側は4.7V、右側は約2.5Vなので、電位差は4.7-2.5=2.2Vです。オームの法則から、
電流 I = 2.2 / 1000 = 0.0022A = 2.2mA
データシートから、レギュレーションのための最小カソード電流は1mAほしいので、適切な電流になっているようです。
●入力電圧を0~5VにするためにOPAMPを利用
上記の事例では、入力電圧範囲は0~2.49598Vでした。
2.49598Vを5Vまで増幅してみようと思います。
利用するピンです。
A1/AN000 OPAMP+
A2/AN001 OPAMP-
A3/AN002 OPAMP OUT
OPAMPは、裸のまま入っています。したがって、利用するときは、回路を外部に組まないといけません。
A0/AN000 OPAMP+とA1/AN001 OPAMP-をショートして入力に使うときは、増幅率1のバッファになります。A-Dコンバータのアナログ入力抵抗は2.5kΩと低いので、測定する場合、被測定物に影響が出る場合がありますが、バッファを入れることで、数MΩにできるので、健全な測定が可能になるかもしれません。
話を戻して、増幅回路(非反転増幅回路)は、次のように二つの抵抗を用意します。
回路図です。
2.49598Vを5Vまで増幅、正確にいうと4.7Vまで増幅するには、
4.7/2.49598=1.883倍
すればいいことになります。
増幅率 1.883 = 1 + (R1 /R2)
R2=10kΩとすると、
R1= (1.883 -1) * 10k =8830Ω
8.2kΩと680Ωを直列にすると8.88kΩです。手持ちの抵抗で実測したら8.93kΩでした。
10kΩを実測したら10.02kΩでした。この組み合わせで行きます。
増幅率 1 + (8.93 / 10.02) = 1.891倍
スケッチです。A1にアナログ入力をつなぎます。出力はA3なので、A3を読みます。
OPAMPを利用するのには、最初で、#include <OPAMP.h> しておきます。
setup()内で、OPAMP.begin(OPAMP_SPEED_LOWSPEED); を記述し、利用を始めます。引数は、OPAMP_SPEED_HIGHSPEEDも利用できますが、通常の測定で高速にする必要はないと思います。
#include <OPAMP.h> const float TL431 = 2.49598; float Av = 1.891; const float Aref = TL431 / Av; float LSB = 1000 * Aref / 16384; float analogData; void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReference(AR_EXTERNAL); analogReadResolution(14); OPAMP.begin(OPAMP_SPEED_LOWSPEED); } void loop() { delay(1000); analogData = analogRead(3); Serial.println(analogData * LSB); }
実行結果です。アナログ入力A1には1.0000Vをつないでいます。正しく測定できています。
●増幅するなら、内部基準電圧を使ってもいいじゃないか
前回、推測した内部基準電圧は1.41Vでした。4.7Vまで増幅するには、
4.7/1.41=3.333倍
すればいいことになります。
増幅率 3.333= 1 + (R1 /R2)
R2=10kΩとすると、
R1= (3.333 -1) * 10k =23.33kΩ
手持ちの22kΩ抵抗で実測したら21.88kΩです。
10kΩを実測したら10.02kΩでした。これで行きます。
増幅率 1 + (21.88 / 10.02) = 3.183倍
スケッチです。
#include <OPAMP.h> const float INTERNAL_vref = 1.41; float Av = 3.183; const float Aref = INTERNAL_vref / Av; float LSB = 1000 * Aref / 16384; float analogData; void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReference(AR_INTERNAL); analogReadResolution(14); OPAMP.begin(OPAMP_SPEED_LOWSPEED); } void loop() { delay(1000); analogData = analogRead(3); Serial.println(analogData * LSB); }
実行します。アナログ入力には0.4000Vをつないでいます。それ以上の、たとえば0.5Vでは、OPAMPの出力が0.5*3.183=1.5915Vと、内部基準電圧1.41Vを超えてしまっていて出力が飽和してしまうからです。
入力電圧範囲が0~1.41Vでは、細かく電圧を測定ができるメリットはあるのですが、ちょっと狭くて使いずらいですね。
●TL431は4.7Vの電圧を作れる
入力電圧範囲を0~4.7Vとしたい場合、基準電圧源も4.7Vにしなければなりません。この電圧をTL431を用いて作ります。
回路図です。動きません。なぜなら、入力電圧が低いというか、入力と出力の電圧が同じなら、レギュレータとして動作しません。レギュレータは、出力電圧より入力電圧は、数V高くないといけません。
なので、DCジャックに9~12Vをつなぎ、この回路の入力はVin端子につなぎます。
DCジャックに12V出力のAC-DCアダプタをつなぎ、Vinの電圧を測ります。12.65Vでした。電流容量は任意です。
VR1を回して、Arefの電圧を4.70Vに設定しました。
スケッチです。
const float Aref = 4.70; float LSB = 1000 * Aref / pow(2,14); void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReference(AR_EXTERNAL); analogReadResolution(14); } void loop() { delay(1000); Serial.print(analogRead(0)); Serial.print("\t"); Serial.println(analogRead(0) * LSB); }
実行しました。A0入力には1.0000Vを入れました。
DCジャックとUSBの2か所から電源を供給していますが、同時に使っても問題ないように回路が組まれています。
PCとのUSB接続を切っても、DCジャックからの電源で動き続けます。でも、このままでは、測定値を表示できないですが。
●入力電圧範囲を広げるには
入力電圧範囲が0~4.7Vでは最大の電圧が低くて、いろいろ測定するのに不便なら、アッテネータ(減衰器)を入れましょう。
たとえば、1/5に減衰するなら、入力電圧範囲が0~4.7Vは0~入力電圧が0~23.5V対応になり、電子工作ではほとんどなんでも測れそうです。
実例は、いつか。