測定する前に各要所の電流と電圧を測れる範囲で測定して見ました。
- LEDに流れる電流。
- 下記の回路でRs抵抗を3.3ΩとしLEDに流れる電流を60mAとしたのですが、実際には3.3Ωが無く1+2Ωの3Ωとしました
- その状態で測定したら67mAとなりました。
- Rs=0.2/Iの公式から、3=0.2/I I=0.0666 。
- 67mAは計算通りです。
- 全体に流れる電流
- LED ON / ESP32:DeepSleepの場合。→ 69mA
- LEDに流れている電流+2mAでした。
- 電源を入れると点灯するLEDが電源から2kΩの抵抗を通して配線されています。電源の電圧が3.3Vですのでこの部分に流れる電流は、3.3÷2000=0.00165。 1.65mAとなります。
- とするとESP32のDeepSleepの消費電流は2−1.65=0.35。 0.35mAとなります。
- LED OFF / ESP32:Idleの場合 → 88.6mA
- LED ON / ESP32:Idleの場合 → 154.3mA
- 計算上 88.6+67=155.6mAとなりそうですが若干小さい値になりました。
- LED ON / ESP32:DeepSleepの場合。→ 69mA
測定中は大半が、”LED ON / ESP32:DeepSleepの場合。→ 69mA”の状態なので、この値を元にバッテリーの寿命を計算します。
- SPECからこのバッテリーは、20hour rate ( 0.06A to10.50V )1.2Ah。
- 今回流れる電流が約69mA。SPECは60mAなのでほぼ同等の条件
- 1.2Ah=0.069xHour Hour≒17.39。17.39時間
この寿命はバッテリーの初期電圧に左右されますが、起動と同時に電圧を測定し、測定結果をSPECの寿命グラフと比べればバッテリーの性能を確認出来そうです。
回路とソフトの修正
ESP32からLEDのON/OFFを行いたくて前回の回路を書いたのですが、ソフトでLEDをOFFしてからESP32をDeepSleepにしており、この時点でせっかくOFFしたのにまたLEDをオンしてしまう事が分かりました。そこで、ESP32でにオンオフを止めてスイッチでオンオフする事ににました。新しい回路は、
それに対応してスケッチも変更しました。
#include "Arduino.h"
#include "SD.h"
#include <Wire.h>
#include <WebServer.h>
#include "esp_deep_sleep.h"
#include <ESPmDNS.h>
#include <DS3231.h>
// SD Card select PIN
#define sd_ss 5
/*
#define sd_sck 18
#define sd_mosi 23
#define sd_miso 19
*/
// AD Conversion R
#define ad_r1 100
#define ad_r2 22
// AD Conversion IO
#define ad_00 36
#define ad_01 39
#define ad_02 34
// AM2320 I2C Address
#define AM2320_ADR 0x5c // FIX
// LED Driver Ccontroll
#define LED_ctl 32
// External Interrupt
// Only use GPIO:0,2,4,12-15,25-27,32-39
#define RTC_INT GPIO_NUM_35
// Wakeup caused
#define by_ext_RTC_IO 2
#define by_ext_RTC_CNTL 3
#define by_timer 4
#define by_touchpad 5
#define by_ULP_program 6
// Pilot Lamp
#define Pilot_Lamp 13
// DS3231 Flg
#define every_s 0x0f //Alarm once per second
#define match_s 0x0e //Alarm when seconds match
#define match_ms 0x0c //Alarm when min, sec match
#define match_hms 0x08 //Alarm when hour, min, sec match
#define match_dhms 0x00 //Alarm when date, h, m, s match
#define match_whms 0x00 //Alarm when DoW, h, m, s match
#define alarm1 1
#define alarm2 2
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR int st_h = 0;
RTC_DATA_ATTR int st_m = 0;
int led_stat;
WebServer server(80);
const char *SSID = "xxxxxxxx";
const char *PASSWORD = "yyyyyyyy";
DS3231 Clock;
byte tm_data[10]; //Year,Month,Date,DoW,Hour,Minute,Secon
void setup()
{
File dataFile;
pinMode(LED_ctl, OUTPUT);
digitalWrite(LED_ctl, HIGH);
Wire.begin();
SPI.begin();
SD.begin(sd_ss);
if(esp_sleep_get_wakeup_cause() != 2)
{
Serial.begin(115200);
pinMode(RTC_INT, INPUT);
pinMode(Pilot_Lamp, OUTPUT);
digitalWrite(LED_ctl, LOW);
init_DS3231();
Serial.println("Connecting to WiFi");
WiFi.disconnect(true);
WiFi.softAPdisconnect(true);
delay(500);
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASSWORD);
delay(1000);
// Try forever
while (WiFi.status() != WL_CONNECTED) {
Serial.println("...Connecting to WiFi");
delay(1000);
}
Serial.println("Connected");
Serial.println(SSID);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp32solar")) {
Serial.println("MDNS responder started");
}
digitalWrite(Pilot_Lamp, HIGH);
server.on("/", handleRoot);
server.onNotFound(handleWebRequests);
server.begin();
Serial.println("HTTP server started");
led_stat=0;
}
else
{
Serial.begin(115200);
delay(500);
Serial.println("times:" + String(bootCount));
measure_data();
set_next(match_hms);
Clock.checkIfAlarm(alarm1);
Serial.println("Enter ReSleep");
esp_sleep_enable_ext0_wakeup(RTC_INT, LOW);
esp_deep_sleep_start();
delay(500);
}
}
void loop()
{
server.handleClient();
}
void handleRoot() {
String buf,cmd;
int a,b,fl,fl_sleep;
File dataFile;
float h_data[2];
uint8_t para[7];
fl=1; fl_sleep=0;
cmd=server.argName(0);
switch(cmd.toInt())
{
case 1: // Update Data
buf=server.arg("1");
get_h_m(buf);
break;
case 99: // Back or Cansel
break;
case 2: //Set TIME (send url data)
buf=server.arg("2");
get_h_m(buf);
dataFile = SD.open("/Set_Time.html", FILE_READ);
server.streamFile(dataFile,"text/html");
dataFile.close();
fl=0;
break;
case 3: // LED ON/OFF
buf=server.arg("3");
get_h_m(buf);
led_stat = ! led_stat;
digitalWrite(LED_ctl, led_stat);
break;
case 4: // Start Logger
buf=server.arg("4");
get_h_m(buf);
server.send(204, "text/plain", "");
Serial.println("Enter Start");
dataFile = SD.open("/data0.txt", FILE_WRITE);
dataFile.close();
dataFile = SD.open("/data1.txt", FILE_WRITE);
dataFile.close();
bootCount = 0;
measure_data();
set_next(match_hms);
Clock.checkIfAlarm(alarm1);
Clock.turnOnAlarm(alarm1);
esp_sleep_enable_ext0_wakeup(RTC_INT, LOW);
Serial.println("Enter Sleep");
digitalWrite(Pilot_Lamp, LOW);
esp_deep_sleep_start();
delay(500);
fl=0;
break;
case 80: // Send Solar parameter
buf=get_current_time() + ",";
AM2320(h_data);
buf += ("Temp:" + String(h_data[1]) + "'c / Humi:" + String(h_data[0]) +"%,");
buf += (String(get_volt(ad_00)) + "v / " + String(get_volt(ad_01)) + "v / " + String(get_volt(ad_02)) + "v,");
cmd = "LED ON,";
if(led_stat) cmd = "LED OFF,";
buf += cmd;
buf += (String(st_h) + "," + String(st_m) + ",");
server.send(200, "text/plain", buf);
fl=0;
break;
case 81: // Send RTC parameter
get_DS3231(tm_data);
buf = "";
for(a = 0; a < 7; a ++) buf += (String(tm_data[a]) + ",");
server.send(200, "text/plain", buf);
fl=0;
break;
case 100: // Set TIME
buf=server.arg("100");
b=0;
for(a=0; a<7; a++)
{
cmd="";
while( buf[b] != ',')
{
cmd += buf[b];
b ++;
}
tm_data[a]=cmd.toInt(); b ++;
}
set_DS3231(tm_data);
break;
}
if(fl)
{
dataFile = SD.open("/menu.html", FILE_READ);
server.streamFile(dataFile,"text/html");
dataFile.close();
}
}
void set_next(byte cntl)
{
int a,b;
get_DS3231(tm_data);
a = tm_data[5] + st_m;
b = tm_data[4] + st_h;
if(a > 59)
{
a -= 60;
b ++;
}
if(b > 23) b -= 24;
Clock.setA1Time(0, b, a, tm_data[6], cntl, 0, 0, 0);
}
void init_DS3231()
{
Clock.turnOffAlarm(alarm1); // Disables alarm 1 or 2 (default is 2 if Alarm != 1);
Clock.turnOffAlarm(alarm2); // Disables alarm 1 or 2 (default is 2 if Alarm != 1);
Clock.setClockMode(0);
}
void get_h_m(String str)
{
int a;
String cmd;
st_h = str.toInt();
a = 0;
while(str[a] != ',') a ++;
a ++;
cmd = str.substring(a);
st_m = cmd.toInt();
}
//#define CLOCK_ADDRESS 0x68
void set_DS3231(byte* tm_data)
{
Clock.setYear(tm_data[0]); //Set the year (Last two digits of the year)
Clock.setMonth(tm_data[1]);
Clock.setDate(tm_data[2]);
Clock.setDoW(tm_data[3]); //Set the day of the week SUN=1 / SAT=7
Clock.setHour(tm_data[4]);
Clock.setMinute(tm_data[5]);
Clock.setSecond(tm_data[6]);
}
void get_DS3231(byte* tm_data)
{
bool Century=false;
bool h12;
bool PM;
tm_data[0] = Clock.getYear();
tm_data[1] = Clock.getMonth(Century);
tm_data[2] = Clock.getDate();
tm_data[3] = Clock.getDoW();
tm_data[4] = Clock.getHour(h12,PM);
tm_data[5] = Clock.getMinute();
tm_data[6] = Clock.getSecond();
}
void measure_data()
{
String buf;
File dataFile;
float h_data[2];
buf= String(bootCount) + ",";
buf += get_current_time() + ",";
AM2320(h_data);
buf += ("T/H," + String(h_data[1]) + "," + String(h_data[0]) +",");
buf += ("/0/1/2," + String(get_volt(ad_00)) + "," + String(get_volt(ad_01)) + "," + String(get_volt(ad_02)));
dataFile = SD.open("/data0.txt", FILE_APPEND);
dataFile.println(buf);
dataFile.close();
dataFile = SD.open("/data1.txt", FILE_APPEND);
dataFile.println(buf);
dataFile.close();
bootCount ++;
}
String digit_2(byte num)
{
String str;
if(num < 10) str = ("0" + String(num));
else str = String(num);
return (str);
}
String get_current_time()
{
uint8_t a;
String buf;
String w_data[8]={"Sun","Mon","Tue","Wen","Thu","Fri","Sat"};
get_DS3231(tm_data);
buf=String(tm_data[0] + 2000);
buf += ("/" + digit_2(tm_data[1]));
buf += ("/" + digit_2(tm_data[2]));
buf += ("/" + w_data[tm_data[3] - 1] + "/");
for(a = 4; a < 7; a ++)
{
buf += digit_2(tm_data[a]);
if(a != 6) buf += ":";
}
return(buf);
}
void handleWebRequests()
{
String dataType = "text/plain";
String path;
File dataFile;
path = server.uri();
if(path.endsWith(".txt")) dataType = "text/plain";
else if(path.endsWith(".css")) dataType = "text/css";
else if(path.endsWith(".js")) dataType = "application/javascript";
else if(path.endsWith(".png")) dataType = "image/png";
else if(path.endsWith(".html")) dataType = "text/html";
else if(path.endsWith(".jpg")) dataType = "image/jpeg";
delay(5);
dataFile = SD.open(path.c_str(), "r");
server.streamFile(dataFile, dataType);
dataFile.close();
delay(5);
}
float get_volt(int no)
{
float d_vol;
d_vol = analogRead(no);
d_vol *= 3.6; d_vol /= 4095;
d_vol *= ((ad_r1 + ad_r2) / ad_r2);
d_vol *= 1.1;
return(d_vol);
}
void AM2320(float * h_t_data)
{
uint8_t data[8];
int flg;
Wire.beginTransmission(AM2320_ADR);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(AM2320_ADR);
Wire.write(0x03);
Wire.write(0x00);
Wire.write(0x04);
Wire.endTransmission();
delay(10);
Wire.requestFrom(AM2320_ADR,8);
if (Wire.available() >= 8)
{
for (uint8_t i=0; i<8; i++) data[i] = Wire.read();
h_t_data[0] = ((float)((data[2] << 8) | data[3]))/10;
flg = 1;
if(data[4] & 0x80) flg = -1;
data[4] &= 0x7f;
h_t_data[1] = ((float)((data[4] <<8 ) | data[5]))/10 * flg;
}
}
前回から124行から139行を変更したのみです。その他のファイルは変更有りません。
電圧測定結果
測定結果はこの様になりました。
- 時間0.0が最初の測定点です。
- 時間の単位は、”時”。測定間隔は10分です。
- 電圧の初期測定値は13.05Vが、次の10分で12.55V に下がりさらに次の10分で12.37Vまで下がる。
- 最初の20分での電圧の降下は大きいが、それ以降は比較的安定して下がっている。
- 測定は12時間30分行い、最終的に電圧は10.2Vまで下がった。
これをグラフにしてSPECに有ったグラフと比較すると
この様になります。SPECのグラフの横軸が対数なので比較しづらいですが、初期の電圧が約12.5VとするとSPECのグラフの矢印のあたりから測定がスタートした事に相当すると思われます。
そう仮定すると、SPECでは12.5Vから10.5Vになるまで 20➖6=14時間。今回の測定では約12時間10分ですから流れている電流がSPECが60mA、今回が69mAと言うことを考えてまずまずの結果と思われます。
でも最初の6時間分(電圧が13V弱から12.5Vになるまでの間)が有りません。今回最初の電圧測定では13.05V。10分後に12.55Vになっています。SPECでは6時間が実際には10分となった結果です。バッテリーの充電が不十分だったのでしょうか。確かにバッテリー購入後充電していませんし若干試しに使っています。それが原因でしょうか。