// Temperature logger based on DS18B20 waterproof one wire sensor // // Read Temperature // Read Vext battery voltage // Log to SD card // Display on lcd // Minimise power usage where possible // // // User setup variables String ver = "1.0.0"; // version number (5 char max) int scheduleFreq = 30; // logging freq in seconds int resolution = 12; // temperature sensor resolution (9-12 bits) /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// #include #include // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include #include "RTClib.h" // SD Card Functions #include #include // LCD Functions #include // Powersaving functions #include "LowPower.h" // LCD backlight workaround using pin 3 #define LCDBacklight() pinMode(3, INPUT) // turn on backlight #define LCDnoBacklight(){ pinMode(3, OUTPUT);digitalWrite(3, LOW);} // turn off backlight LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // select the pins used on the LCD panel // Data wire is plugged into pin 2 on the Arduino #define ONE_WIRE_BUS 2 // Setup a oneWire instance to communicate with any OneWire device OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress tempDeviceAddress; // Real Time Clock & SD Card RTC_DS1307 RTC; const int chipSelect = 10; // // Sketch global variables int dataPoints = 0; float temperature = 0; float voltage = 0; unsigned long future = 0; char buf[20]; char fname[13] = {'\0'}; //file length+1 (8.3 format) ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void setup(void) { // start serial port Serial.begin(9600); Wire.begin(); // Initialise lcd lcd.begin(16, 2); // start LCD lcd.setCursor(0, 0); // LCD cursor position lcd.print(F("Temp.logr v")); // print to LCD lcd.setCursor(11, 0); // LCD cursor position lcd.print(ver); // print to LCD Serial.print(F("Temp.logr 'v")); Serial.print(ver); Serial.println("'"); // Check RTC is running RTC.begin(); if (! RTC.isrunning())startupError(F(" RTC Error! ")); // Create dataFile name DateTime now = RTC.now(); sprintf(fname, "%02d%02d%02d%02d.csv", now.month(), now.day(), now.hour(), now.minute()); // see if the card is present and can be initialized: Serial.println(F("Initializing SD card...")); if (!SD.begin(chipSelect)) startupError(F(" SD Card Error! ")); Serial.println(F("Card initialized")); // Start up the temperature library sensors.begin(); // IC Default 9 bit resolution. // check resolution if required set resolution sensors.getAddress(tempDeviceAddress, 0); if (sensors.getResolution(tempDeviceAddress) != resolution) { sensors.setResolution(tempDeviceAddress, resolution); } // report parasite power requirements bool parasitePower = sensors.isParasitePowerMode(); Serial.print(F("Parasite power: ")); if (parasitePower)Serial.println(F("ON")); else Serial.println(F("OFF")); // get sensor chip type String chip = ""; switch (tempDeviceAddress[0]) { case 0x10: chip = (F("Temperature chip: 'DS18S20'")); // or old DS1820 break; case 0x28: chip = (F("Temperature chip: 'DS18B20'")); break; case 0x22: chip = (F("Temperature chip: 'DS1822'")); break; case 0x3B: chip = (F("Temperature chip: 'DS1825'")); break; default: chip = (F("Non 'DS18x2x' family device.'")); break; } Serial.println(chip); // get sensor serial String dataString = (F("Serial: '")); for (uint8_t i = 0; i < 8; i++) { if (tempDeviceAddress[i] < 16) dataString += ("0"); // zero pad the address if necessary dataString += String(tempDeviceAddress[i], HEX); } dataString += ("'"); Serial.println(dataString); // sensor resolution Serial.print(F("Sensor resolution (bits): '")); Serial.print(resolution); Serial.println("'"); Serial.print(F("Data logging frequency (seconds): '")); Serial.print(scheduleFreq); Serial.println("'"); Serial.println(); // open the file. If the file is available, write headers. File dataFile = SD.open(fname, FILE_WRITE); if (dataFile) { dataFile.print(F("Temp.logr v")); dataFile.println(ver); dataFile.print("File name: "); dataFile.println(fname); dataFile.println(chip); dataFile.println(dataString); dataFile.print(F("Parasite power: ")); if (parasitePower)dataFile.println(F("ON")); else dataFile.println(F("OFF")); dataFile.print(F("Sensor resolution (bits): ")); dataFile.println(resolution); dataFile.print(F("Data logging frequency (seconds): ")); dataFile.println(scheduleFreq); dataFile.println(); dataFile.println(F("AEST Date Time (dd/mm/yyyy hh:mm:ss),Temperature (deg C),Ext Battery Voltage (V)")); dataFile.close(); } // pause so user can read program name & version Serial.flush(); // get ready for sleep LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); // set schedule frequency and determine the time for first data point now = RTC.now(); future = (now.unixtime() - (now.unixtime() % scheduleFreq) + scheduleFreq); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void loop(void) { DateTime now = RTC.now(); // turn backlight off if more than 4 secs from last log point if (now.unixtime() > (future - scheduleFreq + 4)) LCDnoBacklight(); if (now.unixtime() >= future) // waited long enough?? { LCDBacklight(); // Turn on backlight lcdRefresh(now); // Sample time, temperature and vext sensors.requestTemperatures(); String dataString = ""; temperature = sensors.getTempCByIndex(0); // 0 refers to the first IC on the wire sprintf(buf, "%02d/%02d/%04d %02d:%02d:%02d,", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second()); dataString += (buf); dtostrf(temperature, 2, resolution - 8, buf); dataString += (buf); Serial.println(buf); // print temperature on its own line for serial plotter int sensorValue = analogRead(A0); //read the Analog pin value voltage = sensorValue * (5.00 / 1023.00) * 2; //convert the value to a true voltage i.e. v divider dtostrf(voltage, 2, 2, buf); dataString += (","); dataString += (buf); // open the file. If the file is available, write to it. File dataFile = SD.open(fname, FILE_WRITE); if (dataFile) { dataFile.println(dataString); dataFile.close(); dataPoints ++; // Serial.println(dataString); } // find next time needed to log future = (now.unixtime() - (now.unixtime() % scheduleFreq) + scheduleFreq); } lcdRefresh(now); Serial.flush(); // get ready for sleep LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// void lcdRefresh(DateTime now) { // refresh lcd, calc line 1 first, then line 0 // minimise time when lcd is cleared to avoid flashing appearance String lcdString0 = (""); sprintf(buf, "%02d:%02d:%02d ", now.hour(), now.minute(), now.second()); lcdString0 += buf; if (voltage > 2) { lcdString0 += dtostrf(voltage, 2, 2, buf); lcdString0 += ("V"); } else lcdString0 += (" USB"); String lcdString1 = ("Pt:"); sprintf(buf, "%05d ", dataPoints); lcdString1 += buf; lcdString1 += dtostrf(temperature, 2, 2, buf); lcdString1 += ((char)223); lcdString1 += ("C"); lcd.clear(); // clear lcd lcd.setCursor(0, 0); // display temp lcd.print(lcdString0); lcd.setCursor(0, 1); // display time lcd.print(lcdString1); } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// void startupError(String str) { Serial.println(str); Serial.flush(); // get ready for sleep lcd.setCursor(0, 1); // LCD cursor position lcd.print(str); // print to LCD LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); } ////////////////////////////////////////////////////////////