XIAO ESP32C3でバッテリーの電圧を監視する

参考

環境

  • Seeed Studio XIAO ESP32C3
  • Arduino 1.8.16
  • 回路:バッテリーのGND,VDDをそれぞれ220kΩの抵抗でA0と接続

    この回路により、A0にはバッテリーの電圧の半分が分圧としてかかります。
    A0にはアナログ電圧を読み取ることができるADコンバータ機能が内蔵されており、読み取った電圧を2倍することでバッテリーの電圧を算出できます。

バッテリーの電圧を取得してシリアル出力

void setup() {
  Serial.begin(115200);
  pinMode(A0, INPUT);         // ADC
}

void loop() {
  float Vbattf = get_bat_level();
  Serial.println(Vbattf, 3);
  delay(1000);
}

float get_bat_level(){
  uint32_t Vbatt = 0;
  for(int i = 0; i < 16; i++) {
    Vbatt = Vbatt + analogReadMilliVolts(A0); // ADC with correction   
  }
  float Vbattf = 2 * Vbatt / 16 / 1000.0;     // attenuation ratio 1/2, mV --> V
  return Vbattf;
}

出力:4.154

USBが接続されている場合、バッテリーを充電する回路が動いてしまいます。そのため、充電電圧の4.2Vが出力されてしまいます。

正確にバッテリーの電圧のみを測定するには、USBを接続せずにバッテリ+ESP32C3の独立したセットでプログラムを動かす必要があります。

バッテリーの電圧をAmbient.ioに送信する

USBを接続せず単独で動作させたときに、電圧を出力する媒体(シリアルプロッタ等)がありません。
一つの方法として、インターネットに接続して値を送信する方法があります。
ここではAmbient.ioというサービスを使い、値を確認する方法を示します。

Ambientの使い方はこちら

#include "Ambient.h"
WiFiClient client;
Ambient ambient;
unsigned int channelId = XXXXX; // AmbientのチャネルID
const char* writeKey = "YOURWRITEKEY";
const char* readKey = "YOURREADKEY"; 
const char* ssid = "YOURSSID";
const char* password = "YOURPASSWD";

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);  //  Wi-Fi APに接続

  WiFi.begin(ssid, password);  //  Wi-Fi APに接続
    while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
        delay(100);
    }

  Serial.print("WiFi connected\r\nIP address: ");
  Serial.println(WiFi.localIP());
  
  ambient.begin(channelId, writeKey, &client, readKey=readKey); // チャネルIDとライトキーを指定してAmbientの初期化
  
  pinMode(A0, INPUT);         // ADC
}

void loop() {
  float Vbattf = get_bat_level();
  ambient.set(1,Vbattf);
  ambient.send();
//  Serial.println(Vbattf, 3);
  delay(5000);
}

float get_bat_level(){
  uint32_t Vbatt = 0;
  for(int i = 0; i < 16; i++) {
    Vbatt = Vbatt + analogReadMilliVolts(A0); // ADC with correction   
  }
  float Vbattf = 2 * Vbatt / 16 / 1000.0;     // attenuation ratio 1/2, mV --> V
  return Vbattf;
}

上記のコードを実行すると、Ambidata.io上では以下のようなグラフとして可視化できました。

20:17まではUSBに接続していましたが、それ以降はバッテリー+ESP32C3の単独システムで動作させています。
ブレがありますが、バッテリ電圧は3.8V程度のようです。

スリープして定期的にバッテリー電圧を監視する

上記の例では常にWi-Fiに接続し電池を食います。スリープして定期的に電力を送信するのであれば、消費電力を抑えられるはずです。

ここでは、タイマー機能を使って10分に一回バッテリー電圧を取得してAmbidata.ioに送信する例を紹介します。

#include "Ambient.h"
#include "esp_bt_main.h"
#include "esp_bt.h"
#include "esp_wifi.h"
WiFiClient client;
Ambient ambient;
unsigned int channelId = XXXXX; // AmbientのチャネルID
const char* writeKey = "YOURWRITEKEY";
const char* readKey = "YOURREADKEY"; 
const char* ssid = "YOURSSID";
const char* password = "YOURPASSWD";

void setup() {
  WiFi.begin(ssid, password);  //  Wi-Fi APに接続

  WiFi.begin(ssid, password);  //  Wi-Fi APに接続
    while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
        delay(100);
    }  
  ambient.begin(channelId, writeKey, &client, readKey=readKey); // チャネルIDとライトキーを指定してAmbientの初期化
  pinMode(A0, INPUT);         // ADC
  float Vbattf = get_bat_level();
  ambient.set(1,Vbattf);
  ambient.send();
  delay(10000);
  esp_bluedroid_disable();
  esp_bt_controller_disable();
  esp_wifi_stop();
  esp_deep_sleep(1000 * 1000 * 60 * 10);  //10 min sleep
}

void loop() {
}

float get_bat_level(){
  uint32_t Vbatt = 0;
  for(int i = 0; i < 16; i++) {
    Vbatt = Vbatt + analogReadMilliVolts(A0); // ADC with correction   
    delay(5);
  }
  float Vbattf = 2 * Vbatt / 16 / 1000.0;     // attenuation ratio 1/2, mV --> V
  return Vbattf;
}

DeepSleep後はsetup()の関数から実行されます。したがって、ここではWi-Fi接続とバッテリ電圧取得、バッテリ電圧のAmbidata.ioへの送信を全てsetup()内に入れています。

タイマー付きのdeepsleepに入るにはesp_deep_sleep(1000 * 1000 * 60 * min);を利用します。esp_deep_sleepはns単位での指定となるため、分(min)を指定したい場合は1000×1000×60をする必要があります。

暫く動かしてみましたが、きちんと10分おきに起動してバッテリ電圧を送信してくれています。

deep sleepを挟むことで大幅に省電力化できる(数十nA)ため、単独のシステムで動かす際には役立ちそうです。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です