ここまでRTCとして主にDS1307を使っていたが、DS1307のRQWピンでは1Hzのインターバルしか作れないので、1時間とかのインターバルでスリープさせるとかはできない。そこでDS3231に切り替えようと思う。
そしてスリープ復帰のプログラムを書こうと思ったが、どうも世の中の先人たちはRTClibではなくRtcDS3231だとかDS3231RTCだとか別のライブラリを使っているらしい。
素直に先人の言うとおりにすればいいのだけれど、ライブラリを変えると他の部分もいろいろ書き換えなくてはならなくなるわけで、それはそれで面倒だな、ということでRTClibのままでスリープ復帰のプログラムを模索してみたところ、とりあえず想定通りの動作にたどり着いた。
ここまでのプログラム全部のせでESP32+DS3231で書いてみる。
/* TSL2591 Digital Light Sensor Dynamic Range: 600M:1 Maximum Lux: 88K SHT4x Humidity & Temp Sensor I2C | ESP32 SCL 22 SDA 21 Vin 3.3V GND GND Connect the SD card to the following pins: SD Card | ESP32 D2 - D3 SS (5) CMD MOSI (23) VSS GND (GND) VDD 3.3V (5V) CLK SCK (18) VSS GND (GND) D0 MISO (19) D1 - */ #include <Adafruit_SHT4x.h> #include <Adafruit_Sensor.h> #include <Adafruit_TSL2591.h> #include <Wire.h> #include <RTClib.h> #include <SPI.h> #include <SD.h> #include <EEPROM.h> #define buttonPin 16 // calibration mode select #define DEFAULT_DRY0 4095 // EEPROM default value #define DEFAULT_WET0 0 // EEPROM default value #define DATA_VERSION "v1.0" // EEPROM #define INTERRUPT_PIN GPIO_NUM_33 // the pin that is connected to SQW //#define uS_TO_S_FACTOR 1000000 //sleep Timer //#define TIME_TO_SLEEP 24 //sleep Timer #define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex Adafruit_SHT4x sht4 = Adafruit_SHT4x(); Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); RTC_DS3231 RTC; //use DS3231 char daysOfTheWeek[7][12] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // int sensorPin0 = A6; // select the input pin for the potentiometer int sensorValue0 = 0; // variable to store the value coming from the sensor //int sensvPin0 = 35; // int serialStat = 0; // To skip serial const int chipSelect = 5; //SPI (SD) int buttonStat = 1; // calibration/measure mode status int wetValue0 = 0; // calibrated value 100% moisture int dryValue0 = 4095; // calibrated value complete dry float humValue0 = 0; // Humidity RTC_DATA_ATTR int bootCount = 0; /**************************************************************************/ // EEPROM struct DATA_SET { int dValue0; int wValue0; char check[10]; }; DATA_SET data; void load_data() { EEPROM.get<DATA_SET>(0, data); if (strcmp(data.check, DATA_VERSION)) // Check for version { // If there is no data data.dValue0 = DEFAULT_DRY0; data.wValue0 = DEFAULT_WET0; } } void save_data() { strcpy(data.check, DATA_VERSION); EEPROM.put<DATA_SET>(0, data); } /**************************************************************************/ void setup() { pinMode(buttonPin, INPUT_PULLUP); // pinMode(sensvPin, OUTPUT); buttonStat = digitalRead(buttonPin); pinMode(INTERRUPT_PIN, INPUT_PULLUP); Serial.begin(9600); delay(1000); if (Serial) { serialStat = 1; } else { serialStat = 0; } // RTC Wire.begin(); RTC.begin(); delay(1000); if (serialStat == 1) { if (!RTC.begin()) { Serial.println("RTC failed"); Serial.flush(); while (1) delay(10); } if(RTC.lostPower()) { // this will adjust to the date and time at compilation RTC.adjust(DateTime(F(__DATE__), F(__TIME__))); } } //we don't need the 32K Pin, so disable it RTC.disable32K(); RTC.clearAlarm(1); RTC.clearAlarm(2); RTC.writeSqwPinMode(DS3231_OFF); // turn off alarm 2 (in case it isn't off already) // again, this isn't done at reboot, so a previously set alarm could easily go overlooked RTC.disableAlarm(2); //Set RTC alerm // RTC.setAlarm1(RTC.now() + TimeSpan(0,0,4,58), DS3231_A1_Minute); // In case of returning from sleep every 4'58" from the present time RTC.setAlarm1(DateTime(0, 0, 0, 0, 0, 0), DS3231_A1_Minute); // Return from sleep every hour 0'0" // RTC.adjust(DateTime(__DATE__, __TIME__)); // RTC.adjust(DateTime(2022, 10, 29, 0, 13, 30)); /* Set RTC with PC initially */ /* Configure the TSL2591 sensor */ configureSensorTsl(); /* Configure the SHT4x sensor */ configureSensorSht(); SD.begin(); tsl.begin(); sht4.begin(); load_data(); dryValue0 = data.dValue0; wetValue0 = data.wValue0; // for serial debug if (serialStat == 1) { // SD card // Serial.print("Initializing SD card..."); // see if the card is present and can be initialized: if (!SD.begin()) { Serial.println("Card failed, or not present"); } // Serial.println("card initialized."); // TSL2591 & SHT40 // Serial.println("Adafruit SHT4x & TSL2591 sensors"); // TSL2591 if (! tsl.begin()) { Serial.println(F("Couldn't find TSL2591")); while (1) delay(1); } // Serial.println(F("Found a TSL2591 sensor")); /* Display some basic information on this sensor */ // displaySensorDetailsTsl(); // SHT40 if (! sht4.begin()) { Serial.println("Couldn't find SHT4x"); while (1) delay(1); } // Serial.println("Found SHT4x sensor"); // Serial.print("Serial number 0x"); // Serial.println(sht4.readSerial(), HEX); if (buttonStat == LOW) { calibSens(); data.dValue0 = dryValue0; data.wValue0 = wetValue0; save_data(); } } //Increment boot number and print it every reboot ++bootCount; //sensing timeRead(); delay(10); advancedReadTsl(); delay(10); sensorReadSht(); delay(10); sensorReadSw(); esp_sleep_enable_ext0_wakeup(INTERRUPT_PIN,0); //1 = High, 0 = Low //Go to sleep now esp_deep_sleep_start(); } /**************************************************************************/ void configureSensorTsl(void) { /* You can change the gain on the fly, to adapt to brighter/dimmer light situations */ //tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light) tsl.setGain(TSL2591_GAIN_MED); // 25x gain //tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain /* Changing the integration time gives you a longer time over which to sense light longer timelines are slower, but are good in very low light situtations! */ //tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light) // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS); tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS); // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light) } /**************************************************************************/ void configureSensorSht(void) { /* You can have 3 different precisions, higher precision takes longer*/ sht4.setPrecision(SHT4X_HIGH_PRECISION); //sht4.setPrecision(SHT4X_MED_PRECISION); //sht4.setPrecision(SHT4X_LOW_PRECISION); /* You can have 6 different heater settings higher heat and longer times uses more power and reads will take longer too!*/ sht4.setHeater(SHT4X_NO_HEATER); //sht4.setHeater(SHT4X_HIGH_HEATER_1S); //sht4.setHeater(SHT4X_HIGH_HEATER_100MS); //sht4.setHeater(SHT4X_MED_HEATER_1S); //sht4.setHeater(SHT4X_MED_HEATER_100MS); //sht4.setHeater(SHT4X_LOW_HEATER_1S); //sht4.setHeater(SHT4X_LOW_HEATER_100MS); } /**************************************************************************/ void calibSens(void) { // digitalWrite(sensvPin, HIGH); dryValue0 = analogRead(sensorPin0); while (dryValue0 < 4000) { if (serialStat == 1) { Serial.println("Calibrate Dry"); } delay(1000); dryValue0 = analogRead(sensorPin0); } // digitalWrite(sensvPin0, HIGH); sensorValue0 = analogRead(sensorPin0); while ((dryValue0 - sensorValue0) < 100) { if (serialStat == 1) { Serial.print("DryValue0 = "); Serial.println(dryValue0); Serial.println("Calibrate Wet0"); delay(1000); } delay(1000); sensorValue0 = analogRead(sensorPin0); } sensorValue0 = analogRead(sensorPin0); delay(5000); wetValue0 = analogRead(sensorPin0); while (!(wetValue0 == sensorValue0)) { if (serialStat == 1) { Serial.print("Value is not stable; "); Serial.println(wetValue0); } sensorValue0 = analogRead(sensorPin0); delay(5000); wetValue0 = analogRead(sensorPin0); } if (serialStat == 1) { Serial.print("WetValue0: "); Serial.println(wetValue0); } delay(5000); // digitalWrite(sensvPin, LOW); } /**************************************************************************/ void timeRead(void) { DateTime now = RTC.now(); String timeStamp = String(now.year()) + '/' + String(now.month()) + '/' + String(now.day()) + " (" + daysOfTheWeek[now.dayOfTheWeek()] + ") " + String(now.hour()) + ':' + String(now.minute()) + ':' + String(now.second()); File dataFile = SD.open("/datalog.txt", FILE_APPEND); dataFile.print(timeStamp); dataFile.close(); if (serialStat == 1) { Serial.println(timeStamp); } } /**************************************************************************/ void advancedReadTsl(void) { // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum // That way you can do whatever math and comparisons you want! uint32_t lum = tsl.getFullLuminosity(); uint16_t ir, full; ir = lum >> 16; full = lum & 0xFFFF; File dataFile = SD.open("/datalog.txt", FILE_APPEND); dataFile.print(", "); dataFile.print(ir); dataFile.print(", "); dataFile.print(full); dataFile.print(", "); dataFile.print(full - ir); dataFile.print(", "); dataFile.print(tsl.calculateLux(full, ir), 6); dataFile.close(); if (serialStat == 1) { //Serial.print(F("[ ")); Serial.print(millis()); Serial.println(F(" ms ] ")); Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F(" ")); Serial.print(F("Full: ")); Serial.print(full); Serial.print(F(" ")); Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F(" ")); Serial.print(F("Lux: ")); Serial.println(tsl.calculateLux(full, ir), 6); } } /**************************************************************************/ void sensorReadSht(void) { sensors_event_t humidity, temp; // uint32_t timestamp = millis(); sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data // timestamp = millis() - timestamp; File dataFile = SD.open("/datalog.txt", FILE_APPEND); dataFile.print(", "); dataFile.print(temp.temperature); dataFile.print(", "); dataFile.print(humidity.relative_humidity); dataFile.close(); if (serialStat == 1) { Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C"); Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH"); //Serial.print("Read duration (ms): "); //Serial.println(timestamp); } } /**************************************************************************/ void sensorReadSw(void) { // digitalWrite(sensvPin, HIGH); sensorValue0 = analogRead(sensorPin0); // digitalWrite(sensvPin, LOW); humValue0 = ((float)(dryValue0 - sensorValue0)) / ((float)(dryValue0 - wetValue0)) * 100; File dataFile = SD.open("/datalog.txt", FILE_APPEND); dataFile.print(", "); dataFile.print(sensorValue0); dataFile.print(", "); dataFile.print(humValue0); dataFile.println(""); dataFile.close(); if (serialStat == 1) { Serial.print("Soil sensor value0: "); Serial.println(sensorValue0); Serial.print("Soil Humidity0: "); Serial.print(humValue0); Serial.println("%"); } } /**************************************************************************/ void loop() { }
とりあえずこの状態で毎時00分にスリープから起きてデータを計測できる様になった。
00分、15分、30分、45分とかで起きるようなセッティングはTimeSpanを使うしかないんだろうかね。
センサーの電源をIOピンをoutputにしてとればもっと省エネになりそうだけど、そこまでしなくてもいいかな。
マイコンをモバイルバッテリーで駆動するのは案外難しい。流れる電流が小さいと、充電完了、ということで止まってしまうようだ。
このバッテリーなら微弱なマイコンの電流でも停止せずにバッテリーが切れるまで運転できる。