今から始める電子工作 ⑦ アナログ入力 その1 analogReadResolution(14)とanalogReference(AR_INTERNAL)
マイコンのアナログ入力用に、A-Dコンバータが内蔵されています。A-Dコンバータの変換方式には何種類もあります。Arduino UNO 3はSAR(逐次比較)方式が採用されています。
多くのマイコンでは、A-Dコンバータ回路は一つだけ実装されています。入力は複数あり、それをマルチプレクサ回路につなげています。ソフトウェアで、そのマルチプレクサのチャネルを切り替えて、アナログ入力を読み込みます。比較的高速に切り替えられるので、複数のアナログ入力を同時に利用できます。
UNO 4には、14 ビットA-D コンバータが内蔵されています。UNO 3と同じ逐次比較方式です。UNO 3で使われているマイコンATMega328のA-Dコンバータは10ビットなので、UNO 4のほうが分解能が向上しています。デフォルトでは10ビットです。
●アナログ入力
マイコン・ボードの左側にA0~A5のアナログ入力があります。それぞれのピンは、別の用途でも使われます。
いずれのピンもディジタル入力/出力に使えます。さらに、下記のように別の機能にも使えます。A1、A2、A3ピンのOPAMPはUNO 3にはなかった機能です。
- A1 Analog Analog input 1 / OPAMP +
- A2 Analog Analog input 2 / OPAMP -
- A3 Analog Analog input 3 / OPAMP Out
- A4 Analog Analog input 4 / I²C Serial Data (SDA)
- A5 Analog Analog input 5 / I²C Serial Clock (SCL)
これ以外に、アナログ入力に関連する端子にAREFがあります。A-D変換をするときの基準電圧源です。
このマイコン・ボードで使われているCPU R7FA4M1AB3CFMには、14ビットA-Dコンバータの入力は18本ありますが全部は使われていません。
ピン名自体は、従来のA0~A5以外に、AN009、AN000、AN001、AN002、AN021、AN022がありますが、どういうときに使われるかは不明です。
AN009 DAC OUT
AN000 OPAMP+
AN001 OPAMP-
AN002 OPAMP OUT
AN021 不明
AN022 不明
●解像度を更新するには、 analogReadResolution()コマンドを使用
アナログ入力の解像度は10ビットです。2^10=1024です。基準電圧VREFは通常電源電圧が用いられるので5Vで、したがって、0~5Vを0~1024で表現するので、最小の電圧は5/1024=0.00488V=4.88mV単位になります。
ディジタル・マルチメータを用いて、マイコン・ボードの実際の基準電圧を測定します。
- +5V端子:4.503V
- AREF端子:4.503V
Arduino UNO 4は通常、PCとUSBケーブルで接続していて、USBの5Vを電源電圧に使います。PCの5Vは個体差はありますし、常に変動しています。また、マイコン・ボードのUSB 5V端子から、保護用のショットキーバリア・ダイオードが入っているので、約0.3V電圧が低下します。したがって、多くの解説では、4.7Vという表現が出てきます。
analogReadResolution()を用いて、解像度を変更できます。指定できる数値は最大16です。ここでは、14を指定します。
2^14は16384です。最小の電圧は4.503 / 16384 =0.2748mVです。
次のスケッチで、アナログ電圧を測定します。20回の移動平均の結果を表示しています。
1.0000Vの電圧を測定しています。シリアルモニタに表示している電圧はmV単位です。
float Vref = 4.503; float LSB = 1000.0 * Vref / 16384; // mV int cnt; float average=0; float sum=0; #define loopCount 20 float data[loopCount]; void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReadResolution(14); } void loop() { if (cnt == loopCount) cnt = 0; sum -= data[cnt]; data[cnt] = analogRead(0) * LSB; sum += data[cnt]; cnt++; average = sum / loopCount; delay(100); Serial.println(average,4); if (cnt == loopCount) Serial.print("\n");; }
ディジタル・マルチメータは、岩通のVOAC7602、電圧発生の1V以下はタケダ理研(アドバンテスト)のTR6142を使っています。1V以上は、一般的な定電圧電源を使い、ディジタル・マルチメータで電圧を読み取っています。
0~4.4Vの範囲で正しく変換できているようです。
●内部基準電圧源を利用する
電源電圧を基準電圧源に利用するということは、測定のたびに、電源電圧を測ってってスケッチに記入しないといけません。とても面倒です。
安定な基準電圧源は内部に用意されていますが、ルネサスのデータシートによると、1.36(min)、1.43(type)、 1.50(max)Vなので、1.43Vでは、入力の扱える電圧は0~1.43Vと低めになります。その分14ビットであれば、最小の電圧は1000*1.43 / 16384 = 0.08728mVととても細かい分解能を得られます。
内部基準電圧を利用するには、setup()内で、analogReference(AR_INTERNAL)を実行します。
https://docs.arduino.cc/language-reference/en/functions/analog-io/analogReference/
には、1.5Vと書かれています。
AREF端子は4.502Vでした。
次のスケッチを動かして、A0端子に1.0000Vを入力して、測定結果を見ます。built-in referenceは1.5Vと書かれているので、その電圧で実行していますが、高めの電圧が観測されました。
ルネサスのマニュアルに書かれている「内部基準電圧入力チャネル1.43V(typ)」を利用します。まだ少し高めの電圧が観測されました。
できるだけ、測定結果が1.0000Vに近くなるように、基準電圧を修正したところ、1.41Vが内部基準電圧に近いことがわかりました。、これはマイコンに固有の電圧なので、このマイコン・ボードではこの電圧をずっと利用できます。
普通の家庭で精密に電圧を測ろうとすると、AC100Vの誘導などの影響で、1mVの電圧付近はいつも変動しています。ですから、14ビットの分解能を十分に生かすのはとても大変です。
●隣のアナログ端子の影響
Arduino UNO 3/4では逐次比較方式のA-Dコンバータを内蔵しています。
この方式は、入力にサンプリング・コンデンサがあって、マルチプレクサの中で目的の入力がつながったときに充電し、サンプル&ホールド回路によって、電圧が維持されます。その電圧はコンパレータの入力につながれ、もう一つの入力端子は逐次比較レジスタ(SAR)からつながっているD-Aコンバータのアナログ出力がつながっています。
コンパレータは二つの電圧を比較し、'1'もしくは'0'を出力します。SARはMSBからLSBに向かって値を変えていきます。
しかし、このモデルで使われているAtmega328PのA-Dコンバータの入力にバッファが入っていないので、A0に5Vなどの高めの電圧を入力して、すぐにA1で低めの電圧を測定しようとしたら、充電したコンデンサの放電経路がなくて、電圧が残ってしまい、変な変換電圧になってしまうことがありました。
ここで、ボードが1.2.2から1.3.1へのアップデートがかかりました。Arduino IDEも2.3.3から2.3.4へアップデートしました。
次のスケッチで、二つのアナログ入力の値を表示します。A0は5Vへ、A1はGNDへ接続しました。
void setup() { Serial.begin(9600); while (!Serial) delay(10); analogReadResolution(14); } void loop() { delay(1000); Serial.print(analogRead(0)); Serial.print("\t"); Serial.println(analogRead(1)); }
実行します。GNDの値が0~4になっています。ほぼ'0'ですね。Arduino UNO 4では、UNO 3のような問題はないように思えます。