参考
- https://wiki.seeedstudio.com/check_battery_voltage/
- https://qiita.com/umebosh/items/df3922add423d9482c41
環境
- 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というサービスを使い、値を確認する方法を示します。
#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)ため、単独のシステムで動かす際には役立ちそうです。