今から始める電子工作 ⑦ アナログ入力 その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のような問題はないように思えます。

前へ

今から始める電子工作 ⑥ ディジタル入力 その2 チャタリング対策

次へ

今から始める電子工作 ⑧ アナログ入力 その2 analogReference(AR_EXTERNAL)