ESP32 電源電圧を自己測定して過放電防止 (後編)
Keynee さんのお陰をもちまして、自己電圧を計測して低電圧になったらフリーズする前に自発的に Hibernation mode を発動させ、4μA という NiMH の自然放電と同じ次元の超低電力モードに移行し電池の過放電の進行を防止する、という目的は実現しました。
Hibernation mode でも RTC は生きているため、あらかじめオッキする時間をセットしておいてから Hibernation mode に移行すれば指定時間に再起動がかかるため、過放電防止じゃなくても用途は広いです。
(20μA 程度の消費を許容できるなら、ピン割り込みでオッキという手もあります)
ただ人の欲望は限りなく、「RTC 生かしつつ 4μA は凄いと思うけど、RTC が要らないときは無駄だよねー」って言い出すじゃないですか。
NiMH 運用で過放電防止の目的で使うとき普通は
- 電池が切れて止まる
- 取り外して充電(もしくは充電済みと交換する)
- 起動
という流れになります。
これじゃ RTC の出る幕がありません。
ということで、こーいう用途に特化した究極の過放電防止案を。
前回の回路 に抵抗1本とタクトスイッチが増えただけですが、EN の付近の配線が違うことに気が付かれますでしょうか。
(ちなみに、この増えた抵抗は保護用で、決して IO34 を OUTPUT/LOW にしないと誓うならば省略可)
普通は EN をプルアップさせつつ、片方を GND に落としたタクトスイッチをリセットボタンとして使うことが多いと思いますが、逆の使い方をしてみました。
電池を繋いだだけでは EN ピンは LOW のままですが、START スイッチを ON にすると EN が HIGH になり起動します。
スイッチを離すと EN ピンが 30kΩ に引っ張られて LOW に戻ってしまいますが、それまでの間に IO21 を HIGH にしてやればスイッチを離しても大丈夫でしょ?
プログラムが動き出して IO21 を HIGH にする処理が走るまではスイッチを押し続けないといけませんが、そんなの1秒もかかりません。
#include "driver/adc.h" const int RA = 10000; // 10k ohm const int RB = 30000; // 30k ohm void setup() { // put your setup code here, to run once: Serial.begin(115200, SERIAL_8N1); pinMode(21, OUTPUT); digitalWrite(21, HIGH); // ADC 関係の ardino-esp32 が出来てないぽい気がするので core を利用 adc1_config_width(ADC_WIDTH_12Bit); adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_11db); // IO34 } void loop() { // put your main code here, to run repeatedly: static int seq = 0; float value = adc1_get_voltage(ADC1_CHANNEL_6); float voltage = value / 4095 * 3.6 * (RA + RB) / RB; Serial.print("SEQ:"); Serial.print((String)seq++); Serial.print(" VALUE:"); Serial.print((String)value); Serial.print(" VOLTAGE:"); Serial.print((String)voltage); Serial.println(""); if(voltage < 2.30) // 40MHz 時は 2.00 にして良い { Serial.println("good bye!"); delay(500); // なくてもいいが good bye がPCに届かなくなる digitalWrite(21, LOW); // 自殺 // 不要 esp_deep_sleep_start(); } delay(1000); }
あれ、esp_deep_sleep.h をインクルードしてないぞ?って思われるかもしれませんが
Deep Sleep も Hibernation mode も使いません。
setup にあった esp_deep_sleep_pd_config の付近もバッサリ削除してます。
- 起動したら直ちに IO21 を HIGH に
- 電圧測定
までは前回の電測プログラムと一緒ですね。
実は前回のプログラムにヒントが・・・
if(voltage < 2.30) // 40MHz 時は 2.00 にして良い { Serial.println("good night!"); digitalWrite(21, LOW); // なくていい esp_deep_sleep_start(); }
本来は不要な行を // なくていい とコメントで入れてありましたが、僅かに回路に手を加えることで、これが // 自殺 に変わり、究極の過放電防止となるのでした。
電測時に 1/2 分圧とかにしないで、わざわざ 3/4 にしたのは今回の伏線でもあったのですが、EN ピンは電源電圧に対して 75% 以上で HIGH と認識しますので、そのまま EN ピンにも流用するようにしました。
過放電検知に伴って IO21 を LOW に落とすことで分圧抵抗の消費電力を抑制する、という目的で、電源を直接測るのでなく IO21 を測ることにしたのは以前にも説明しました。
IO34(電測ピン) と EN とが直結されているので、EN ピンも LOW に引っ張ります。
EN ピンが LOW と認定するのは 25% を下回ったところで、RTC を含めて全ての動作が止まります。
ESP32 が停止した後は IO21 はオープンとなりますが、30kΩ でプルダウン状態を維持
という風に遷移します。
消費電流は @2.5V 時で 0.2〜0.3AμA をフラフラしてましたが、これで限界。
高尚な仕組みを期待されていた方には肩すかしな内容だったと思いますが、単純な自殺回路に勝るものはないですね。。