An arduino based low cost environmental data logger.
Components:
#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 ==== */
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€
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