40MHzモードでコンパイル すれば、完全に電池×2 仕様に変貌する ESP32。
とはいえ単体で動かす分にはいいとしても、2.2V とかいう電圧だとキャラクタ液晶どころか LED すら難しいっす。。
センサーとか色々と付けるんなら、いっそ 3.3V のほうが楽なんですね。
せっかく 電池×2 で動くキャパがありながら、実運用では ストリナさん あたりで昇圧DCDC を探す羽目に陥ったり。
900円も出せば かなりいい感じのが手に入りますから、普通はそういうのを選ばれるのが賢明ですが、ESP32 には PWM も付いていることだし、なんか、そーいう便利モジュールに逃げたら負けた気分になるじゃないですか。
ってことで、あまり実益はないものの、DCDCモジュールを使わず、手持ち部品で貧乏昇圧してみることにします。
自分自身へは電池×2直結のまま外部機器に向けてだけ 3.3V を作ると、信号線のレベルコンバートという作業が待ち受けるため、効率は脇に置いといて自身と外部と共通の 3.3V を作ることにします。
前回の「自己測定して過放電防止」の回路 に対して、MOSFETとインダクタとショットキーダイオードと、コンデンサと抵抗が数個増えただけです。
ごくありふれたチョッパ昇圧回路なわけですが、2V前後という電圧域でスイッチングしないといけない Nch MOSFET には、(たぶん)秋月で入手できる中で最も低電圧駆動な IRLML6344(10個で180円) を投入します。
インダクタは、とりあえず部品箱にあった 47μH(30円) を選択。
動作ですが、電池×2 から 1S3(20円) の VF 分だけ低い電圧で ESP32 に給電され、これをもって起動。
起動できたら IO23 を PWM して昇圧開始、という段取りです。
本当はゲート抵抗をいれたほうがいいかもしれませんが、ゲート容量が 650pF と小さく、かつ電圧も低いので ESP32 の気合いを引き出すべく省略しましたが・・・(試作機では今のところ直結でも大丈夫ぽい)
昇圧前と昇圧後の電圧を測定し、デューティ比をコントロールする仕組みはプログラム側で行います。
プログラムで自身の電圧をコントロールする格好でして、そのデューティ比の次第では 5V とかいう昇圧も出来てしまい、いわゆる「自爆」ができてしまうため、念のため 3.6Vのツェナー(10円) で絶対定格は超えないよう保護しておきます。
この保護ツェナーは省電力と諸刃の剣でして、常に 60μA(@2V)〜500μA(@3V)ほどお漏らししてしまいます。
これは過放電防止作動中も一緒で、ツェナーを取り外すと、1μA未満を達成できるのですが、重負荷→軽負荷 に急激遷移した時、プログラムによる追随が間に合わず思いがけない電圧が出てしまうことがあるため、非常に悩めるところ。
探すとモバイル用途に 10〜20分の1 に漏れ電流を改善したツェナーがあるみたいですが、素人が入手できるようなもんじゃない気がします。
今回はストリナさんの900円が勿体ないという時の貧乏昇圧回路なのでツェナーのお漏らしには目をつむることにしましょう。
さて、プログラムで昇圧させますので、そのソースも御披露目します。
#include "driver/adc.h" #include "esp32-hal-ledc.h" const int RA = 10000; // 10k ohm const int RB = 30000; // 30k ohm const float VF = 0.35; // 0.35V@200mA with 1S3 const float VCC = 3.30; const float maxDuty = 0.50; // 念のためリミッター volatile float duty; volatile float espVoltage; volatile float batVoltage; volatile float efficiency; void checkVoltage() { espVoltage = (float)adc1_get_voltage(ADC1_CHANNEL_6) / 4096 * 3.6 * (RA + RB) / RB; batVoltage = (float)adc1_get_voltage(ADC1_CHANNEL_7) / 4096 * 3.6; efficiency = espVoltage / VCC; duty = 1 - ((batVoltage < espVoltage ? batVoltage : espVoltage) - VF) * efficiency / VCC; if(duty > maxDuty) duty = maxDuty; else if(duty < 0) duty = 0; ledcWrite(1, duty * 255); } void setup() { // put your setup code here, to run once: Serial.begin(115200, SERIAL_8N1); pinMode(21, OUTPUT); digitalWrite(21, HIGH); ledcAttachPin(23, 1); // for PWM ledcSetup(1, 100000, 8); // 100kHz, 8bit // ADC 関係の ardino-esp32 が出来てないぽい気がするので core を利用 adc1_config_width(ADC_WIDTH_12Bit); adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_11db); // IO34 adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_11db); // IO35 } void loop() { // put your main code here, to run repeatedly: static unsigned long last_time = 0; unsigned long now_time = millis(); checkVoltage(); if((now_time - last_time) > 1000) { static int seq = 0; last_time = now_time; Serial.print("SEQ:"); Serial.print((String)seq++); Serial.print(" ESP:"); Serial.print((String)espVoltage); Serial.print(" BAT:"); Serial.print((String)batVoltage); Serial.print(" EFFICIENCY:"); Serial.print((String)efficiency); Serial.print(" DUTY:"); Serial.print((String)duty); Serial.println(""); static int low_bat = 0; if(batVoltage < 2.00) // 40MHz でコンパイルを前提 { low_bat ++; if(low_bat > 2) { Serial.println("good bye!"); delay(500); // なくてもいいが good bye がPCに届かなくなる digitalWrite(21, LOW); // 自殺 } } else low_bat = 0; } }
詳しくはソース読んでもらうとして、当初は Ticker で割り込みかけて電圧監視しようと思ったんですが、どうも現バージョンでは Ticker が実装されていないらしく・・・
仕方ないので、普通の loop() の中から呼ぶようにしてあります。
(volatile 〜 は Ticker を使いたかった未練で残してある)
仕組みとしては、実測値とのズレを「効率」として求めて、理論デューティ比から微調整する、という風になってます。
ADC の精度がたいしたことないので、効率>1.00 と求まることもありますが、まぁ大きな実害はありません。
昇圧前の電圧が 2.00 を割ったら過放電防止作動という風なのですが、コンデンサの選定が悪いせいだと思いますが、2.5→1.9→2.5 みたいな挙動を示すことがあったので、3連続で 2.00 を下回ったら・・・という風にしました。
3.3V を指定していながら実測 3.12V っていう風ですが、これは ADC の精度の問題でして、ESP32 としては 3.3V のつもりでいるみたい。
いずれ arduino-esp 側で改善されることを期待しつつ上がりすぎるよりはマシなので目を瞑ることにします。
900円のモジュールほどには効率よくないですが、100円くらいで昇圧できるので、ちゃんとした昇圧モジュール使うほどでもない・・・って場合にご検討くださいませ。