Monday, March 28, 2016

Data Loger

An arduino based low cost environmental data logger.

Components:
Arduino pro mini 3.3v  ~ 2€
SD card module ~ 1.25€
RTC Real Time Clock Module ~ 1.25€
18650 battery* ~ 2€

You can also find 18650 batteries from an old laptop.

Sensors
BME280 ~ 5.5€
or
HTU21 ~ 4.5€

Other sensors
AM2320 Digital Temperature Humidity ~ 3€
MQ-135 Air Quality Sensor ~ 2.5€
TEMT6000 Light Sensor ~ 2€


Schematics





The Code


#include <DS3232RTC.h>    //Time http://github.com/JChristensen/DS3232RTC
#include <Time.h>         //Time http://www.arduino.cc/playground/Code/Time
#include <Wire.h>         //Time http://arduino.cc/en/Reference/Wire (included with Arduino IDE)
#include <SPI.h>          //SD
#include <SD.h>           //SD
#include <BME280.h>       //BME280

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 10; //SD
File dataFile;            //SD

/*
Connecting the BME280 Sensor:
Sensor              ->  Board
-----------------------------
Vin (Voltage In)    ->  3.3V
Gnd (Ground)        ->  Gnd
SDA (Serial Data)   ->  A4 on Uno/Pro-Mini, 20 on Mega2560/Due, 2 Leonardo/Pro-Micro
SCK (Serial Clock)  ->  A5 on Uno/Pro-Mini, 21 on Mega2560/Due, 3 Leonardo/Pro-Micro
*/
/* ==== Global Variables ==== */
BME280 bme;                   // Default : forced mode, standby time = 1000 ms
                              // Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
bool metric = true;
/* ==== END Global Variables ==== */

/* ==== Prototypes ==== */
/* === Print a message to stream with the temp, humidity and pressure. === */
void printBME280Data(Stream * client);
/* === Print a message to stream with the altitude, and dew point. === */
void printBME280CalculatedData(Stream* client);
/* ==== END Prototypes ==== */


void setup(void)
{
  Serial.begin(9600);
  while (!Serial) {}// wait for serial port to connect. Needed for Leonardo only
  while(!bme.begin()){
    Serial.println("Could not find BME280 sensor!");
//    delay(1000);
  }
 
//Time
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus() != timeSet)
      Serial.println("Unable to sync with the RTC");
  else
      Serial.println("RTC has set the system time");    

//SD
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(SS, OUTPUT);
 
  // see if the card is present and can be initialized:
//  if (!SD.begin(10, 11, 12, 13)) {  //Only for Leonardo an Mega for ather Boards: if (!SD.begin(chipSelect))
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1) ;
  }
  Serial.println("card initialized.");
 
  // Open up the file we're going to log to!
  dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
  }

    Serial.println("Time     Date       TempC RH%   atm  Alt(m) Dew p");
    dataFile.println("Time     Date       TempC RH%   atm  Alt(m) Dew p");
 
}


void loop(void) {

    printDigits(hour());
    Serial.print(':');
    printDigits(minute());
    Serial.print(':');
    printDigits(second());
    Serial.print(' ');
    printDigits(day());
    Serial.print('/');
    printDigits(month());
    Serial.print('/');
    Serial.print(year());
    Serial.print(' ');
   
    printBME280Data(&Serial);
    printBME280CalculatedData(&Serial);
    Serial.println();

    dataFile.print(hour());
    dataFile.print(':');
    dataFile.print(minute());
    dataFile.print(':');
    dataFile.print(second());
    dataFile.print(' ');
    dataFile.print(day());
    dataFile.print('/');
    dataFile.print(month());
    dataFile.print('/');
    dataFile.print(year());
    dataFile.print(' ');

    printBME280Data(&dataFile);
    printBME280CalculatedData(&dataFile);
    dataFile.println();
  // The following line will 'save' the file to the SD card after every
  // line of data - this will use more power and slow down how much data
  // you can read but it's safer!
  // If you want to speed up the system, remove the call to flush() and it
  // will save the file only every 512 bytes - every time a sector on the
  // SD card is filled with data.
    dataFile.flush();
 
  // Take 1 measurement every 500 milliseconds
  delay(1000);
}

void printDigits(int digits)
{
    // utility function for digital clock display: prints preceding colon and leading 0
    if(digits < 10)
        Serial.print('0');
    Serial.print(digits);
}

/* ==== BME280 Functions ==== */
void printBME280Data(Stream* client){
  float temp(NAN), hum(NAN), pres(NAN);
   uint8_t pressureUnit(3);   // unit: B000 = Pa, B001 = hPa, B010 = Hg, B011 = atm, B100 = bar, B101 = torr, B110 = N/m^2, B111 = psi
  bme.ReadData(pres, temp, hum, metric, pressureUnit);                // Parameters: (float& pressure, float& temp, float& humidity, bool hPa = true, bool celsius = false)
  /* Alternatives to ReadData():
    float ReadTemperature(bool celsius = false);
    float ReadPressure(uint8_t unit = 0);
    float ReadHumidity();

    Keep in mind the temperature is used for humidity and
    pressure calculations. So it is more effcient to read
    temperature, humidity and pressure all together.
   */
//  client->print("Temp: ");
  client->print(temp);
  client->print(' ');
//  client->print("°"+ String(metric ? 'C' :'F'));
//  client->print("\t\tHumidity: ");
  client->print(hum);
  client->print(' ');
//  client->print("% RH");
//  client->print("\t\tPressure: ");
  client->print(pres);
  client->print(' ');
//  client->print(" atm");
}
void printBME280CalculatedData(Stream* client){
  float altitude = bme.CalculateAltitude(metric);
  float dewPoint = bme.CalculateDewPoint(metric);
//  client->print("\t\tAltitude: ");
  client->print(altitude);
  client->print(' ');
//  client->print((metric ? "m" : "ft"));
//  client->print("\t\tDew point: ");
  client->print(dewPoint);
//  client->print("°"+ String(metric ? 'C' :'F'));

}
/* ==== END BME280 Functions ==== */

No comments:

Post a Comment