/* Mini_3MCP9808_0.4depy.ino For the Pro Mini logger with RTC and SD card. Logs sensor data from 3 MCP9808 sensors, and BME280. The RTC and sensors are I2C devices on pins A4 (SDA) and A5 (SCL) deployed in compost pile 4th time, 6/30 C. Fastie, June 2017 */ #include // https://github.com/greiman/SdFat/ #include #include #include "LowPower.h" // from https://github.com/rocketscream/Low-Power #include // https://github.com/adafruit/RTClib/ RTC_DS3231 RTC; // RTC will be the RTC_DS3231 object #define DS3231_I2C_ADDRESS 0x68 // RTC address #include Adafruit_BME280 bme; // The BME280 will be an I2C device // The following two lines allow code in the BME280 library to compute altitude from pressure. // Before use, change the hgInches variable to the actual sealevel barometric pressure. // Consult a weather website for the current value. Then save and load the sketch onto the Pro Mini. float hgInches = 29.92; // Enter the sealevel barometric pressure here (xx.xx inches Hg) #define SEALEVELPRESSURE_HPA (hgInches/0.02952998751) // hPa=(inches Hg)/0.02952998751 #include "Adafruit_MCP9808.h" Adafruit_MCP9808 mcp1 = Adafruit_MCP9808(); Adafruit_MCP9808 mcp2 = Adafruit_MCP9808(); Adafruit_MCP9808 mcp3 = Adafruit_MCP9808(); SdFat SD; // SD will be the SdFat object const int chipSelect = 10; // for SD card #define MOSIpin 11 // for SD card #define MISOpin 12 // for SD card char TmeStrng[] = "0000/00/00,00:00:00"; // string template for RTC time stamp int RTC_INTERRUPT_PIN = 2; byte Alarmhour; byte Alarmminute; byte Alarmday; char CycleTimeStamp[ ] = "0000/00/00,00:00:00"; //19 ascii characters (with seconds) #define SampleIntervalMinutes 10 volatile boolean clockInterrupt = true; //this flag is set to true when the RTC interrupt handler is executed float temp3231; //variables for reading the DS3231 RTC temperature register float temp3231f; byte tMSB = 0; byte tLSB = 0; int RED_PIN = 4; //indicator LED pins: int GREEN_PIN = 5; int BLUE_PIN = 6; int LEDPin = 3; // Assign LEDPin to a pin number void setup() { // Setting the SPI pins high helps some sd cards go into sleep mode // the following pullup resistors only need to be enabled for the stand alone logger builds - not the UNO loggers pinMode(chipSelect, OUTPUT); digitalWrite(chipSelect, HIGH); //Always pullup the CS pin with the SD library //and you may need to pullup MOSI/MISO pinMode(MOSIpin, OUTPUT); digitalWrite(MOSIpin, HIGH); //pullup the MOSI pin pinMode(MISOpin, INPUT); digitalWrite(MISOpin, HIGH); //pullup the MISO pin delay(100); Serial.begin(9600); // Open serial communications Wire.begin(); // initialize the I2C interface RTC.begin(); // initialize the RTC bool status1; // initialize the BME280: status1 = bme.begin(0x76); // 0x76 is the default I2C address of the BME280 sensors if (!status1) { // Serial.println("No BME"); while (1); } if (!mcp1.begin(0x19)) { // initialize the three MCP sensors: // Serial.println("No MCP 1"); while (1); } if (!mcp2.begin(0x1A)) { // Serial.println("No MCP 2"); while (1); } if (!mcp3.begin()) { // Serial.println("No MCP 3"); while (1); } if (!SD.begin(10)) { // initialize the SD card // Serial.println("SD fail"); return; } else { // Serial.println("SD OK"); } // Set the RTC time to the time this sketch was last compiled. Uncomment the following line, load the // sketch on the logger. Must comment out the line and reload for subsequent boots or the RTC time will be wrong: // RTC.adjust(DateTime((__DATE__), (__TIME__))); // print a header to the data file: File dataFile = SD.open("datalog.txt", FILE_WRITE); if (dataFile) { // if the file is available, write a header to it: dataFile.println("Compost 4th, new SD card"); dataFile.print("Sealevel pressure used: "); dataFile.println(hgInches); dataFile.println("Date,Time,UTCtime,RTCtemp_C,mcp1,mcp2,mcp3,BMETemp_C,BMEhumid,Pressure_hPa,Altitude_M"); dataFile.close(); } else { Serial.println("file err 1"); // if the file isn’t open, display an error: } pinMode(RED_PIN, OUTPUT); //configure 3 RGB LED pins as outputs pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, HIGH); // startup with green led lit digitalWrite(BLUE_PIN, LOW); } // end of setup void loop() { DateTime now = RTC.now(); // read the time from the RTC, then construct two data strings: sprintf(TmeStrng, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); sprintf(CycleTimeStamp, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); // uncomment for debugging // Serial.print("RTC time: "); // Serial.println(TmeStrng); if (clockInterrupt) { if (RTC.checkIfAlarm(1)) { //Is the RTC alarm still on? RTC.turnOffAlarm(1); //then turn it off. } //print (optional) debugging message to the serial window if you wish // Serial.print("RTC Alarm on INT-0 triggered at "); // Serial.println(CycleTimeStamp); clockInterrupt = false; //reset the interrupt flag to false } // read the RTC temp register and print that out // Note: the DS3231 temp registers (11h-12h) are only updated every 64seconds Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x11); //the register where the temp data is stored Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 2); //ask for two bytes of data if (Wire.available()) { tMSB = Wire.read(); //2’s complement int portion tLSB = Wire.read(); //fraction portion temp3231 = ((((short)tMSB << 8) | (short)tLSB) >> 6) / 4.0; // Allows for readings below freezing: thanks to Coding Badly temp3231f = (temp3231 * 1.8) + 32.0; // To Convert Celcius to Fahrenheit } else { temp3231 = 0; //if temp3231 contains zero, then you know you had a problem reading the data from the RTC! }/* Serial.print("RTC temp: "); Serial.print(temp3231); Serial.println(" C");*/ float BMEt = (bme.readTemperature()); // Read the BME sensor: float BMEh = (bme.readHumidity()); float BMEp = (bme.readPressure() / 100.0F); float BMEa = (bme.readAltitude(SEALEVELPRESSURE_HPA)); // Serial.print("bme: "); Serial.print(BMEt); Serial.println(" *C"); // Read MCP sensor 1 mcp1.shutdown_wake(0); // required before reading temp delay(300); float c1 = mcp1.readTempC(); // Serial.print("MCP 1: "); Serial.print(c1); Serial.print(" *C"); // Serial.println(""); delay(300); mcp1.shutdown_wake(1); // Read MCP sensor 2 mcp2.shutdown_wake(0); // required before reading temp delay(300); float c2 = mcp2.readTempC(); // Serial.print("MCP 2: "); Serial.print(c2); Serial.print(" *C"); // Serial.println(""); delay(300); mcp2.shutdown_wake(1); // Read MCP sensor 3 mcp3.shutdown_wake(0); // required before reading temp delay(300); float c3 = mcp3.readTempC(); // Serial.print("MCP 3: "); Serial.print(c3); Serial.print(" *C"); // Serial.println(""); delay(300); mcp3.shutdown_wake(1); delay(300); float utc = (now.unixtime()); // write the data to the SD card: File dataFile = SD.open("datalog.txt", FILE_WRITE); // if the file is available, write to it: if (dataFile) { dataFile.print(TmeStrng);dataFile.print(",");dataFile.print(utc);dataFile.print(",");dataFile.print(temp3231);dataFile.print(",");dataFile.print(c1);dataFile.print(","); dataFile.print(c2);dataFile.print(",");dataFile.print(c3);dataFile.print(",");dataFile.print(BMEt);dataFile.print(",");dataFile.print(BMEh); dataFile.print(",");dataFile.print(BMEp);dataFile.print(",");dataFile.println(BMEa); dataFile.close(); delay(250); digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, LOW); digitalWrite(BLUE_PIN, HIGH); //Date written to SD card, turn on blue led delay(300); // send current for this long } else { // Serial.println("file err 2"); // if the file isn’t open, display an error } //——– Set the next alarm time ————– Alarmhour = now.hour(); Alarmminute = now.minute() + SampleIntervalMinutes; Alarmday = now.day(); // check for roll-overs if (Alarmminute > 59) { //error catching the 60 rollover! Alarmminute = 0; Alarmhour = Alarmhour + 1; if (Alarmhour > 23) { Alarmhour = 0; // put ONCE-PER-DAY code here -it will execute on the 24 hour rollover } } // then set the alarm RTC.setAlarm1Simple(Alarmhour, Alarmminute); RTC.turnOnAlarm(1); if (RTC.checkAlarmEnabled(1)) { //you would comment out most of this message printing //if your logger was actually being deployed in the field // delay(300); /* Serial.println(); // adds a carriage return Serial.print("Alarm OK"); Serial.print(" Will sleep for : "); Serial.print(SampleIntervalMinutes); Serial.println(" minutes"); Serial.println(); // adds a carriage return */ delay(300); //removing this delay causes the "Will sleep for..." line to not be printed. digitalWrite(GREEN_PIN, LOW); digitalWrite(BLUE_PIN, LOW); digitalWrite(RED_PIN, HIGH); // Turn on red led as our indicator that the Arduino is sleeping. // delay(500); //——– sleep and wait for next RTC alarm ————– // Enable interrupt on pin2 & attach it to rtcISR function: attachInterrupt(0, rtcISR, LOW); // Enter power down state with ADC module disabled to save power: LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON); //processor starts HERE AFTER THE RTC ALARM WAKES IT UP detachInterrupt(0); // immediately disable the interrupt on waking digitalWrite(RED_PIN, LOW); digitalWrite(GREEN_PIN, HIGH); //Interupt woke processor, turn on green led } } // end of the MAIN LOOP void rtcISR() { // This is the Interrupt subroutine that only executes when the rtc alarm goes off clockInterrupt = true; }