picture of Bill


Building A
Weather Station

In this project we combine the Arduino micro-controller with sensors to detect barometric pressure, temperature, and relative humidity.

This is the completed project.

Components are pictured below.

One of the nice features of the Arduino design is its ability to accomadate plug-in boards, called shields. The shield in use above is a data logger. It has the ability to store data on an SD card, and has a built in real time clock with a battery backup.


The Arduino fitted with a data shield

The BMP 180 pressure sensor is quite small. The breakout board measures 3/8 of an inch. The sensor, the small metal box on the board is around 1/8 in on a side. Wile the sensor is designed for 3.3 Volts, chips on the board allow it to be safely connected to a 5 volts source. This sensor reads the pressure in Pascals and then transmits the number of Pascals over a serial line using I2C technology.


The BMP 180 pressure sensor

The humidity sensor measures 1/2 by 5/8 inches. This sensor reads the %RH and transmits that value serially using SPI technology.


The ASAIR humidity sensor.

The backpack, circled in the image, plugs into the rear of the LCD display. It reduces the number of connections need from 12 to only 4.


The four line LCD plus I2C backpack.

The wiring Diagram

A wiring diagram follows, but for those who might want to recreate this project the following table of connections might be more helpful.

Arduino Pins 5 4 3 Gnd 5V
Arduino Function SCL SDA Data Gnd 5V
BMP 180 SCL SDA NC Gnd 5V
LCD I2C Backpack SCL SDA NC Gnd 5V
Humidity Sensor NC NC Data Gnd 5V


Some parts on the wiring diagram look different from the ones I used in my project. Sensors usually come on breakout boards, and breakout boards vary in layout. Also, not every device is available for use with the Fritzing software used to create the wiring diagram. As long as you make the connections outlined in the above table to the appropriate pins on your device you should be fine.

Initial Results

The following is a sample output from the SD card.



Here is what the comma / and () separated data looks
like when ported to a spreadsheet.



The following is an example of plotting barometric
pressure over a relatively short time.



Barometric pressure changes slowly with time. The
following shows a trend over a much longer time interval.



The Code

//****************Libraries and variables********************

#include "RTClib.h"
RTC_PCF8523 rtc;

char daysOfTheWeek[7][12] = {"Su", "Mo", "Tu", "Wed", "Th", "Fr", 
"Sa"};

#include  //load sd library
#include //load SPI comminication library
int chipSelect = 10; //set chipSelect.
File mySensorData; //variable for working with our file object

#include 
Adafruit_LiquidCrystal lcd(0);
#include "DHT.h"
#define DHTPIN 2 //the pin we are connected to
#define DHTTYPE DHT22 //(AM2302)
#include "Wire.h"
#include "Adafruit_BMP085.h"

Adafruit_BMP085 bmp;//create an instance

DHT dht(DHTPIN, DHTTYPE); //create an instance

long b1=0;//variable to hold first reading
long b2=0;
long b3;//variable to hold the second reading
long delta=0;//variable to hold the change.
int i=0;
void setup() {
Serial.begin(9600);
dht.begin(); //begin is a function in dht
bmp.begin();
lcd.begin(16, 4);
SD.begin(chipSelect); //initialize the SD card with chipselect 
connected to pin 4

//***********************clock***********************
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for 
native USB
#endif

if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}

if (! rtc.initialized() || rtc.lostPower()) {
Serial.println("RTC is NOT initialized, let's set the time!");
// When time needs to be set on a new device, or after a power 
loss, the
// following line sets the RTC to the date & time this sketch was 
compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for 
example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
//
// Note: allow 2 seconds after inserting battery or applying 
external power
// without battery before calling adjust(). This gives the 
PCF8523's
// crystal oscillator time to stabilize. If you call adjust() 
very quickly
// after the RTC is powered, lostPower() may still return true.
}

// When time needs to be re-set on a previously configured 
device, the
// following line sets the RTC to the date & time this sketch was 
compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for 
example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

// When the RTC was stopped and stays connected to the battery, 
it has
// to be restarted by clearing the STOP bit. Let's do this to 
ensure
// the RTC is running.
rtc.start();

// The PCF8523 can be calibrated for:
//        - Aging adjustment
//        - Temperature compensation
//        - Accuracy tuning
// The offset mode to use, once every two hours or once every 
minute.
// The offset Offset value from -64 to +63. See the Application 
Note for calculation of offset values.
// https://www.nxp.com/docs/en/application-note/AN11247.pdf
// The deviation in parts per million can be calculated over a 
period of observation. Both the drift (which can be negative)
// and the observation period must be in seconds. For accuracy 
the variation should be observed over about 1 week.
// Note: any previous calibration should canceled prior to any 
new observation period.
// Example - RTC gaining 43 seconds in 1 week
float drift = 43; // seconds plus or minus over observation 
period - set to 0 to cancel previous calibration.
float period_sec = (7 * 86400);  // total observation period 
in seconds (86400 = seconds in 1 day:  7 days = (7 * 86400) 
seconds )
float deviation_ppm = (drift / period_sec * 1000000); //  
deviation in parts per million (μs)
float drift_unit = 4.34; // use with offset mode PCF8523_TwoHours
// float drift_unit = 4.069; //For corrections every min the 
drift_unit is 4.069 ppm (use with offset mode PCF8523_OneMinute)
int offset = round(deviation_ppm / drift_unit);
// rtc.calibrate(PCF8523_TwoHours, offset); // Un-comment to 
perform calibration once drift (seconds) and observation period 
(seconds) are correct
// rtc.calibrate(PCF8523_TwoHours, 0); // Un-comment to cancel 
previous calibration

Serial.print("Offset is "); 
Serial.println(offset); // Print to control offset
//*****************************clock****************************
}

void loop() {

float h = dht.readHumidity();
float t = dht.readTemperature(); //Celsius

delay(10000);
lcd.clear();

if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from FHT sensor!");
return;
}
if (!bmp.begin()) {
Serial.println("Could not find a valid BMP085 sensor, check 
wiring!");
while (1) {}
}



Serial.print("Pressure= ");
Serial.print(bmp.readPressure());

Serial.print( " Pa");
//Serial.print(" Start ");
Serial.print(" ");
Serial.print(b1);
Serial.print(" ");
Serial.print(b3);
Serial.print(" D ");
Serial.println(delta);

Serial.print("Baro Temp= ");
Serial.print(bmp.readTemperature() * 9 / 5 + 32);
Serial.println(" F ");

Serial.print("Humidity: ");
Serial.print(h);
Serial.println("%\t");

Serial.println();

//*******************Print to monitor************************
DateTime now = rtc.now();

Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();


//************************Write to the LCD display*************
lcd.setCursor(0, 0);
lcd.print(now.year(), DEC);
lcd.print('/');
lcd.print(now.month(), DEC);
lcd.print('/');
lcd.print(now.day(), DEC);
lcd.print("(");
lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
lcd.print(")");
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);

lcd.setCursor(0, 1);
lcd.print(bmp.readTemperature() * 9 / 5 + 32);
lcd.print(" F");

lcd.setCursor(0, 2);
lcd.print(bmp.readPressure());
lcd.print(" Pa");
lcd.print(" Del ");
lcd.print(delta);

lcd.setCursor(0, 3);
lcd.print(h);
lcd.print(" %RH");

//this code is used to check the change in barometric pressure 
for a given time interval

Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
i=i+1;
Serial.println(i);
//readings are refreshed every 10 seconds. 
//this will happen 360 times in one hour. 
//when the count is greater than 359, or 360, the second reading 
is compared to the one
//taken at the beginning of the time interval. Change the value 
of the test count-1 to 
//use a different time interval.
if(i>359){  //creates a time between readings of one hour. 
Serial.println("now writing to disk");

//********************Write to the SD card*******************
mySensorData = SD.open("PTData.txt", FILE_WRITE); //open 
FTData.txt on the SD card as a file to write to
if (mySensorData) { //if file opens

DateTime now = rtc.now();

mySensorData.print(now.year(), DEC);
mySensorData.print('/');
mySensorData.print(now.month(), DEC);
mySensorData.print('/');
mySensorData.print(now.day(), DEC);
mySensorData.print(" (");
mySensorData.print(daysOfTheWeek[now.dayOfTheWeek()]);
mySensorData.print(") ");
mySensorData.print(now.hour(), DEC);
mySensorData.print(',');
mySensorData.print(now.minute(), DEC);
mySensorData.print(",");
mySensorData.print(bmp.readTemperature() * 9 / 5 + 32); //write 
temperature to SD card.
mySensorData.print(",");
mySensorData.print(bmp.readPressure());//write pressure
mySensorData.print(",");
mySensorData.println(h);//write humidity
mySensorData.close(); //close the file

}
i=0;
b2=bmp.readPressure();
delta=b1-b2;//display change relative to one hour prior

b1=b2;

}

}

Copyright 2021, William Johnson