/* Mini_spring.ino For the Mini Pearl Data Logger with RTC and SD card. Logs sensor data from BME280, DS18B20, and MMA8451 to microSD card. A TPL5110 timer controls the logger and turns it on at intervals set by the hardware. When the logging is completed, the sketch signals the TPL5110 to cut power to the logger. All sections of this sketch are run only once every time the timer turns on the logger. The RTC and sensors are I2C devices on pins A4 (SDA) and A5 (SCL). DS18B20 is a one-wire sensor on pin D2. RTC can be set by editing the code, see below. To check operation, uncomment serial print lines, connect a UART adapter, and open the serial monitor. C. Fastie, March 2018 */ #include #include #include // https://github.com/greiman/SdFat/ #include // https://github.com/adafruit/RTClib/ #include // https://github.com/adafruit/Adafruit_BME280_Library/ #include // https://github.com/PaulStoffregen/OneWire #include // https://github.com/milesburton/Arduino-Temperature-Control-Library #include // https://github.com/adafruit/Adafruit_MMA8451_Library #define ONE_WIRE_BUS 2 // Data wire is plugged into pin D2 on the Arduino OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature. Adafruit_MMA8451 mma = Adafruit_MMA8451(); // establish the object for the MMA8451 sensor RTC_DS3231 RTC; // RTC will be the RTC_DS3231 object #define DS3231_I2C_ADDRESS 0x68 // RTC address #define donePin A3 // This pin signals to the TPL5110 to cut power Adafruit_BME280 bme; // The BME280 object is bme SdFat SD; // SD will be the SdFat object #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 float BMEt; // variables for the sensor: float BMEh; float BMEp; long utc; // variables for the RTC: float rtcTemp; float rtcTempC; float DS18; byte tMSB = 0; byte tLSB = 0; int N_reads = 60; // _____ Enter _____ the number of duplicate sensor readings float armLength = 127; // _____ Enter _____ the length of the tilting arm (cm) float pivotHeight = 175; // _____ Enter _____ the height of the pivot above the floor (cm) float aboveH2O = 3; // _____ Enter _____ height of float pivot above water (cm) int mmaY; // raw sensor output long mmaYsum = 0; // rolling sum float mmaYavg; // calculated mean of N_reads sensor readings float armEndHeight; // the height of the lower end of the tilting arm above the floor float heightH2O; float thetaDegree; // the angle of the tilting arm in degrees float thetaRadian; // the angle of the tilting arm in radians int LEDPin = 9; // Assign LEDPin to a pin number void setup() { pinMode(donePin, OUTPUT); // This pin sends output to the TPL5110 timer to cut power digitalWrite(donePin, LOW); // LOW until its time to cut power // Serial.begin(9600); // Open serial communications Wire.begin(); // initialize the I2C interface sensors.begin(); // initialize the DallasTemperature sensors sensors.setResolution(12); 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"); } // else { Serial.println("BME OK"); } if (!SD.begin(10)) { // initialize the SD card, chip select (CS) is pin 10 // Serial.println("SD fail"); } // else { Serial.println("SD OK"); } if (! mma.begin()) // initialize MMA8451 sensor { // Serial.println("MMA Couldnt start"); while (1); } // Serial.println("MMA8451 OK"); mma.setRange(MMA8451_RANGE_2_G); // this sensor has three ranges // Serial.print("Range = "); Serial.print(2 << mma.getRange()); // Serial.println("G"); // 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__))); delay(50); // } // end of setup void loop() { DateTime now = RTC.now(); // read the time from the RTC, then construct a data string: sprintf(TmeStrng, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); utc = (now.unixtime()); // time code (good for graphing) rtcTemp = RTC.getTemperature(); // Read temperature from the RTC BMEt = (bme.readTemperature()); // Read the BME sensor BMEh = (bme.readHumidity()); BMEp = (bme.readPressure() / 100.0F); rtcTemp = rtcMinus(); // custom function (see below) to read RTC temperatures below freezing sensors.requestTemperatures(); // read the onewire temperature sensor DS18 = (sensors.getTempCByIndex(0)); // mmaYsum = 0; // reset the rolling variable for(int a = 1; a <= N_reads; a++) // run through N_reads sensor reads { mma.read(); // Read the 'raw' MMA8451 data in 12-bit counts mmaY = mma.y; // Use the Y-axis result mmaYsum = mmaYsum + mmaY; // Sum the N_reads sensor reads delay (40); } mmaYavg = mmaYsum/N_reads; // mean of N_reads sensor reading thetaRadian = asin((mmaYavg + 12)/4096); // convert the raw 12 bit voltage readings into a tilt angle (radians) armEndHeight = pivotHeight - (cos(thetaRadian) * armLength); // convert the tilt angle into the height of the end of the arm heightH2O = armEndHeight - aboveH2O; // correct for lower pivot being above the water level thetaDegree = 57.2958 * thetaRadian; // convert radians to degrees // write the data to the SD card: File dataFile = SD.open("datalog.txt", FILE_WRITE); dataFile.print(TmeStrng);dataFile.print(","); dataFile.print(utc);dataFile.print(","); dataFile.print(rtcTemp);dataFile.print(","); dataFile.print(BMEt);dataFile.print(","); dataFile.print(BMEh);dataFile.print(","); dataFile.print(BMEp);dataFile.print(","); dataFile.print(DS18);dataFile.print(","); dataFile.print(heightH2O);dataFile.print(","); dataFile.print(thetaDegree); dataFile.println(); dataFile.flush(); dataFile.close(); /* Serial.println(TmeStrng); // for checking operation using UART adapter // print to serial monitor Serial.print("DS18: ");Serial.println(DS18); Serial.print("bme: ");Serial.println(BMEt); Serial.print("Mean: ");Serial.println(mmaYavg); Serial.print("Arm angle (degree): ");Serial.println(thetaDegree); Serial.print("ArmHeight (cm): ");Serial.println(armEndHeight); Serial.print("HeightH2O (cm): ");Serial.println(heightH2O); Serial.println(); */ delay(200); // Make sure the SD card finishes unpredictable housecleaning while (1) // The toggling might not be required, but... { // toggle donePin HIGH so TPL5110 will cut power and turn off logger digitalWrite(donePin, HIGH); delay(1); digitalWrite(donePin, LOW); delay(1); } } // end of the MAIN LOOP float rtcMinus() { // allows for RTC temperatures below 0C 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(); // 2s complement int portion tLSB = Wire.read(); // fraction portion rtcTempC = ((((short)tMSB << 8) | (short)tLSB) >> 6) / 4.0; } return rtcTempC; }