ESP32で回路を追加せずを使って電源電圧を計測する


電源電圧の計測方法について調べてみたところ、ESP8266であればESP.getAcc関数で電源の電圧を取得できることがわかりましたが、ESP32では使えないことがわかり代替の方法は無いか調べてみました。

結果としては、公式に公開されているAPIはないがrom_phy_get_vdd33関数をWIFIまたはBLEがオンのときに実行すると取得可能という情報を見つけて検証してみたところ、使えなくもなさそうだということがわかりました。

検証の目的としては電池駆動の際にしきい値より小さくなったら通知を送って電池交換を促す用途に使えないかを確認したかったというところです。

今回の検証には、開発ボードESPr Developer32を使用しました。

ESPr® Developer 32 – スイッチサイエンス
Wi-Fi + Bluetoothモジュール、ESP-WROOM-32とUSB-シリアル変換ICを搭載した開発ボードです。別売りのピンソケットを実装すれば、ESPr® Developer用に開発した拡張ボードをESPr Developer 32でもそのままお使いいただけます。

www.switch-science.com

No Image

以下、rom_phy_get_vdd33()の呼び出し方についてと計測した値をambientに送ってグラフ化してみた結果について解説しています。

rom_phy_get_vdd33()を使って計測

getVoltage関数はrom_phy_get_vdd33()を呼び出して電源電圧を取得します。

extern "C" int rom_phy_get_vdd33();
#define ADJUST 1.00f
float getVoltage() {
  int v = 0;
  btStart();
  for (int i = 0; i < 100; i++) { 
    int vdd = rom_phy_get_vdd33();
    if (vdd > 1000) {
      v = vdd;
      break;
    }
    delay(200);
  }
  btStop();
  const float vdd =  (0.0005045f * v + 0.3368f) * ADJUST;
  return vdd;
}

rom_phy_get_vdd33()はWIFIまたはBluetoothが起動していときのみ実行可能らしいです。
WIFIに接続する場合は、btStart()、btStop()は不要です。

また、rom_phy_get_vdd33の呼び出しは残念ながらかなりの確率で値の取得に失敗します。
そこで、ループして値が取得できたら抜けるようにしています。

取得した値を電圧に変換する計算式については、以下の記事を参考にさせていただきました。

電子ペーパーを使った情報表示装置

計測したデータをambientに送信してグラフ化

電池3本 (eneloop 1000mAh) をESPr Developer 32につないで起動します。
スケッチは以下のとおりです。

#include <WiFi.h>
#include <Ambient.h>

WiFiClient client;
const char *ssid="your ssid";          //  *** 書き換え必要 ***
const char *password="your password";  //  *** 書き換え必要(8文字以上)***

Ambient ambient;
unsigned int channelId = 11111;      //  *** ambient チャンネルID ***
const char* writeKey = "xxxxxxxxxx"; //  *** ambient チャンネルのライトキー ***

void setup() {
  Serial.begin(9600);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("connecting");
  }
  Serial.println(WiFi.localIP());
  ambient.begin(channelId, writeKey, &client);
}

extern "C" int rom_phy_get_vdd33();
#define ADJUST 1.00f
// WIFIを使用するのでBLEの起動は不要
float getVoltage() {
  int v = 0;
  for (int i = 0; i < 100; i++) { 
    int vdd = rom_phy_get_vdd33();
    if (vdd > 1000) {
      v = vdd;
      break;
    }
    delay(200);
  }
  const float vdd =  (0.0005045f * v + 0.3368f) * ADJUST;
  return vdd;
}

// 30秒おきに電圧を測ってambientに送信
void loop() {
  float vdd = getVoltage();
  ambient.set(1, vdd);
  ambient.send();
  delay(30 * 1000);
}

エネルーブ3本で3.7v強あり。
時間が立つと急に電圧が下がっていくのがわかります。

最終的に3.1vあたりまで落ちたところでWIFIでデータが送信できなくなっているようです。

まとめ

以上、回路無しでESP32でも電源電圧を計測することができました。

一応、この方法は使えそうではありますが、読み取りが不安定なので特に間欠駆動する場合は無駄に起動時間が長くなってしまう問題があります。
やはり、正攻法としては分圧してADCで読み取るのが良さそうです。

そもそも、GithubのStability of rom_phy_get_vdd33 ??? #2612のやりとりでも信頼性もないので、分圧してADCで計測するべきと書いてあります。

Sorry, misread your issue. Unfortunately, rom_phy_get_vdd33 is an unsupported command. This is probably because it is unreliable. Set up a voltage divider and read your battery level on an adc pin.

次は改めて分圧してACDで計測する方法も確認しておこうかと思っています。

,