M5StickC PLUSの内蔵ADコンバータで電圧測定

この記事では、M5StickC PLUSの内蔵ADコンバータを使って、電圧測定する方法を解説します。 M5StickC PLUSは、Arduino互換機であるESP32 PICOをベースに、バッテリーやボタンをパッケージしたM5Stackシリーズ製品のひとつです。本記事の内容はESP32の資料を参考にしました。また、M5StickC PLUSの使い方は をご覧ください。
はじめに
M5StickC PLUSでアナログ入力をサクッと終えるつもりでしたが、ESP32の意外な一面を知って時間がかかってしまいました。記事の中で説明しますが、M5StickC PLUSの内蔵ADコンバータを使うときは、あまり精度は期待しないほうが良さそうです。精度が必要なときは、素直にADコンバータのモジュールを使用することをおすすめします。
G36/G25を使ってアナログ電圧を読み取る
それではStickC PLUSのG36/G25を使って、アナログ電圧を読み取ってみましょう。ただし、G36/G25を使うときには注意しなければならないことがあります。
G36/G25を使うときの注意事項
G36/G25は同じポートを利用してます。そのため、片方のピンを利用しているとき、もう片方のピンはフローティング入力(プルアップもプルダウンもしない状態)にする必要があります。
()
setup{
.begin();
M5(36, INPUT);
pinMode(GPIO_NUM_25); // Disable pull-down on GPIO.
gpio_pulldown_dis(GPIO_NUM_25); // Disable pull-up on GPIO.
gpio_pullup_dis}
▲このような感じで、GPIO36番をADコンバータの入力として使う場合、GPIO25番をフローティング状態に設定します。
https://docs.m5stack.com/en/core/m5stickc_plus
また、M5StickC PLUSのGPIOのアナログ入力電圧は3.3Vまでなので注意してください。
配線
入力電圧は、ふたつの1kΩの抵抗で3.3Vを分圧し、真ん中の端子をG36/G25へ入力しました。なので、理想でいけば1.65Vが入力されるはずです。
プログラム
次のようなプログラムを書いて、ADコンバータによるアナログ電圧を測定してみました。
#include <M5StickCPlus.h>
const float Vref = 3.3;
const int ADC_PIN = GPIO_NUM_36;
void setup() {
.begin();
M5.Axp.ScreenBreath(9);
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.setTextSize(6);
M5
(ADC_PIN, INPUT);
pinMode(GPIO_NUM_25); // Disable pull-down on GPIO.
gpio_pulldown_dis(GPIO_NUM_25); // Disable pull-up on GPIO.
gpio_pullup_dis
.begin(115200);
Serial
}
void loop() {
.Lcd.fillScreen(WHITE);
M5
int val = analogRead(ADC_PIN); // read the input pin
float volt = Vref * float(val) / 4095.0; // 12bit
.println(volt);
Serial.Lcd.setCursor(20, 40);
M5.Lcd.printf("%.2fV", volt);
M5(500);
delay}
写真は1kΩの抵抗で分圧したときの値です。なぜか理論値の1.65Vよりだいぶズレてしまいました。
抵抗の値をもっと高くして10kΩで分圧してみました。すると、さらに電圧値がズレた結果になってしまいました。さらに100kΩでは、0Vが表示され測定不可能になってしまいました。
ADコンバータの入力インピーダンスは高いものとばかり思っていましたが、随分と低いみたいです。つまり、アナログ入力にはある程度の電流を流す必要があるのかなと。
逆に抵抗をもっと小さくして、220Ωでやってみました。しかし結果はそれほど変わらず。アナログ入力のピンを変えてG26でも試してみました。少しはマシになったものの理論値とはかなりズレてます。謎です。
その後いろいろ調べてみるとESP32の内蔵ADコンバータは精度が悪いようで、皆さん同じ悩みを抱えているみたいです。 https://qiita.com/klme_u6/items/e29e4b57fd149488d1c3
▼こちらのスイッチサインセンスさんの記事の「ADC(アナログ入力)」の項目が非常に参考になりました。 https://trac.switch-science.com/wiki/esp32_tips
ESP32には逐次比較型(SAR)ADCモジュールが使われているようです。分解能は9~12bitで、デフォルトは12bit。また、ADCの入力には減衰器を設定可能とのこと。
ここまでは良かったのですが、次の一文を読んで驚きました。
**デフォルトでは11dBの減衰が設定され、12bitでの__最大値は3.6V__を示してます。**
えっ!3.6V!?
これではどうやって測定しても理論通りの電圧にならない訳です。
実はESP32のADCは、もともと0〜1Vしか測れないようです。そこで減衰器を設定して、もっと幅広い電圧を測定できるようになりました。デフォルトでは、-11dBに減衰(-11dBは約1/3.6倍)させられているため、0〜3.6Vの値が測定されるというわけです。
▼ 精度に関する問題はこちらのスレッドで議論されてました。 https://esp32.com/viewtopic.php?f=12&t=1045
この中から、減衰量による測定結果の違いに関するグラフがありましたので、ちょっとお借りします。
ご覧の通り、-11dBでは比例関係になっていません。だいぶ精度は悪そうです。
一方で、0dBや、-6dBでは測定できる最大電圧は低くなるものの、キレイな比例になっていてデフォルトよりは精度が良さそうです。
たとえば、-6dBで設定した場合は、先ほどのプログラムを次のように修正すれば良いでしょう(計算あってますかね?)。
void setup() {
...
(ADC_6db); // ←追記
analogSetAttenuation...
}
void loop() {
...
float volt = Vref * float(val) / log(5) / 4095.0; // ←修正
...
}
ただし、これ以上精度を突き詰めてもむだ骨を折るだけですので、今回はこの辺で終わります。
関連記事
- ADコンバータADS1115の使い方【ESP32・Arduino】
- ESP32でジョイスティックを使ってみよう【Arduino】
- Raspberry PiでSPI通信できるようにする設定【ADコンバータMAX1118】
- 静電容量型の土壌湿度センサを使ってArduinoで土の水分量測定
- 昇圧型DC-DCコンバータでESP32の5Vから12V電源をつくる(MT3608)