#include <LCD.h>
#include <LiquidCrystal_I2C.h>
//#include <Wire.h>
#include <dht.h>
#include "i2c.h"
#include "i2c_BMP280.h"
dht DHT;
BMP280 bmp280;
//specify the temp sensor
#define DHTTYPE DHT22;
#define DHT22_PIN 6
#define I2C_ADDR 0x27 // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
//total delay = (lcdDelayScreen1 + lcdDelayScreen2 + lcdDelayScreen3) * loopCount (in seconds)
int lcdDelayScreen1 = 44; //seconds displaying primary info
int lcdDelayScreen2 = 8; //seconds displaying secondary info
int lcdDelayScreen3 = 8; //seconds displaying secondary info
//these all have to match
int loopCount = 60; //total loops
float dataPointT[60]; //temperature data points
float dataPointB[60]; //pressure data points
int mainLoop; //primary loop
int loopBaroGraph; //secondary loop
int loopTempGraph; //secondary loop
float currentTemp;
float currentHumid;
float baroPressure;
float currentPressure;
float tempDifference = 0;
float tempValueComparative;
int offset;
int mt;
int mp;
float pressDifference = 0;
float pressValueComparative;
//engineeringtoolbox.com/barometers-elevation-compensation-d_1812.html
float altitudeAdjustment = 1;
float minTemp;
float maxTemp;
float minPressure;
float maxPressure;
int rangeLowGraph;
int rangeHighGraph;
float percentOfCol;
float pixelHeightPercent;
int pixelHeight;
bool firstLoopComplete = false;
//define characters for temperature indicators
byte arrowUp[8] = {
B00100,
B01110,
B10101,
B00100,
B00100,
B00100,
B00100,
B00100,
};
byte arrowDown[8] = {
B00100,
B00100,
B00100,
B00100,
B00100,
B10101,
B01110,
B00100,
};
byte equalSign[8] = {
B00100,
B01110,
B10101,
B00100,
B00100,
B10101,
B01110,
B00100,
};
byte row1[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
};
byte row2[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
};
byte row3[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
};
byte row4[8] = {
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
B11111,
};
byte row5[8] = {
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
};
byte row6[8] = {
B00000,
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
byte row7[8] = {
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
byte row8[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
};
void setup() {
int setupLoop;
bool dotPosition = true;
Serial.begin(9600);
lcd.begin (20,4);
//Switch on the backlight
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(HIGH);
lcd.home ();
//delay a few seconds so the sensors are ready
for (setupLoop = 1; setupLoop < 8; setupLoop++)
{
lcd.clear();
if (dotPosition)
{
lcd.print("Initializing .");
lcd.setCursor(0, 1);
lcd.print("WeatherStation v.1");
}
else
{
lcd.print("Initializing .");
lcd.setCursor(0, 1);
lcd.print("WeatherStation v.1");
}
dotPosition = !dotPosition;
delay(500);
}
//Check if BMP 280 is ready
if (bmp280.initialize())
{
lcd.setCursor(0, 2);
lcd.print("Barometer ready");
}
else
{
lcd.print("Barometer error");
}
lcd.setCursor(0, 3);
//check if DHT22 is ready
int chk = DHT.read22(DHT22_PIN);
switch (chk)
{
case DHTLIB_OK:
lcd.print("Temp sensor ready");
break;
case DHTLIB_ERROR_CHECKSUM:
lcd.print("Temp checksum error");
break;
case DHTLIB_ERROR_TIMEOUT:
lcd.print("Temp timeout");
break;
default:
lcd.print("Temp sensor error");
break;
}
//leave info on screen long enough
delay(2000);
bmp280.setEnabled(0);
bmp280.triggerMeasurement();
bmp280.awaitMeasurement();
bmp280.getPressure(baroPressure);
DHT.read22(DHT22_PIN);
//populate baseline datapoints with startup values
int p;
for (p = 0; p <= loopCount - 1; p++)
{
dataPointT[p] = DHT.temperature;
dataPointB[p] = (baroPressure / 1000) + altitudeAdjustment;
}
//wait for sensors to be ready again
delay(500);
}
void loop() {
for (mainLoop = 0; mainLoop <= loopCount - 1; mainLoop++)
{
bmp280.awaitMeasurement();
DHT.read22(DHT22_PIN);
currentTemp = DHT.temperature;
currentHumid = DHT.humidity;
bmp280.getPressure(baroPressure);
bmp280.triggerMeasurement();
currentPressure = (baroPressure / 1000) + altitudeAdjustment;
//read and store the array value before overwriting it
tempValueComparative = dataPointT[mainLoop];
dataPointT[mainLoop] = currentTemp;
tempDifference = currentTemp - tempValueComparative;
pressValueComparative = dataPointB[mainLoop];
dataPointB[mainLoop] = currentPressure;
pressDifference = currentPressure - pressValueComparative;
//create lcd chars defined above
lcd.createChar(0, arrowUp);
lcd.createChar(1, arrowDown);
lcd.createChar(2, equalSign);
//LCD Output begin
lcd.clear();
lcd.print(currentTemp, 1);
lcd.print((char)223);
lcd.print("C ");
//determine which trend indicator to display
showTrendIndicator(tempDifference);
lcd.print(" ");
//then display the temperature diff
lcd.print(tempDifference);
//move to the next line and display humidity
lcd.setCursor(0, 1);
lcd.print(currentPressure, 1);
lcd.print(" kPa ");
showTrendIndicator(pressDifference);
lcd.print(" ");
lcd.print(pressDifference);
lcd.setCursor(0, 2);
lcd.print(currentHumid, 1);
lcd.print(" % Rel Hum");
lcd.setCursor(0, 3);
lcd.print("Data age: ");
//this ensures the 'data age' value displays the max after the first loop completes
if (!firstLoopComplete)
{
if (mainLoop < (loopCount - 1))
{
lcd.print(mainLoop);
}
else
{
lcd.print(loopCount);
firstLoopComplete = true;
}
}
else
{
lcd.print(loopCount);
}
lcd.print(" m");
//countdown until next screen
screenWaitRight(lcdDelayScreen1);
//+++++++++++++++Screen 1 End+++++++++++++++
//+++++++++++++++Screen 2 Start+++++++++++++++
//bar chart characters
lcd.createChar(0, row1);
lcd.createChar(1, row2);
lcd.createChar(2, row3);
lcd.createChar(3, row4);
lcd.createChar(4, row5);
lcd.createChar(5, row6);
lcd.createChar(6, row7);
lcd.createChar(7, row8);
//initialize to something these will never be
minTemp = 50;
maxTemp = -50;
//find min and max temps
for (mt = 0; mt <= loopCount - 1; mt++)
{
//offset value translates a negative result for 'mainLoop - mt' into the appropriate
//value in the array sequence
offset = getOffsetValue(mainLoop - mt);
if (minTemp > dataPointT[offset])
{
minTemp = dataPointT[offset];
}
}
for (mt = 0; mt <= loopCount - 1; mt++)
{
offset = getOffsetValue(mainLoop - mt);
if (maxTemp < dataPointT[offset])
{
maxTemp = dataPointT[offset];
}
}
//this sets the min/max range that the graph will show
rangeLowGraph = minTemp - 1.5;
rangeHighGraph = maxTemp + 1.5;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print((char)223);
lcd.print("C ");
lcd.setCursor(0, 1);
lcd.print("H");
lcd.print(maxTemp, 1);
lcd.setCursor(0, 2);
lcd.print("L");
lcd.print(minTemp, 1);
for (loopTempGraph = 0; loopTempGraph <= loopCount - 1; loopTempGraph += 4)
{
offset = getOffsetValue(mainLoop - loopTempGraph);
currentTemp = dataPointT[offset];
//i add 50 so the values never go below zero
currentTemp = (currentTemp + 50) - (rangeLowGraph + 50);
percentOfCol = currentTemp / ((rangeHighGraph + 50) - (rangeLowGraph + 50));
//32 = total pixels vertical
pixelHeightPercent = 32 * percentOfCol;
pixelHeight = pixelHeightPercent;
showGraphColumn(pixelHeight, loopTempGraph / 4);
}
screenWaitLeft(lcdDelayScreen2);
//+++++++++++++++Screen 2 End+++++++++++++++
//+++++++++++++++Screen 3 Start+++++++++++++++
//initialize to something these will never be
minPressure = 250;
maxPressure = 75;
//find min and max pressure
for (mp = 0; mp <= loopCount - 1; mp++)
{
offset = getOffsetValue(mainLoop - mp);
if (minPressure > dataPointB[offset])
{
minPressure = dataPointB[offset];
}
}
for (mp = 0; mp <= loopCount - 1; mp++)
{
offset = getOffsetValue(mainLoop - mp);
if (maxPressure < dataPointB[offset])
{
maxPressure = dataPointB[offset];
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("kPa");
lcd.setCursor(0, 1);
//lcd.print("H"); //doesn't fit on screen :(
lcd.print(maxPressure, 1);
lcd.setCursor(0, 2);
//lcd.print("L"); //doesn't fit on screen :(
lcd.print(minPressure, 1);
for (loopBaroGraph = 0; loopBaroGraph <= loopCount - 1; loopBaroGraph += 4)
{
offset = getOffsetValue(mainLoop - loopBaroGraph);
currentPressure = dataPointB[offset];
currentPressure = currentPressure - (minPressure - 1.5);
percentOfCol = currentPressure / ((maxPressure + 1.5) - (minPressure - 1.5));
pixelHeightPercent = 32 * percentOfCol;
pixelHeight = pixelHeightPercent;
showGraphColumn(pixelHeight, loopBaroGraph / 4);
}
screenWaitLeft(lcdDelayScreen3);
} //main for loop end
}
int getOffsetValue(int z)
{
if (z < 0)
{
return z + 60;
}
else
{
return z;
}
}
void screenWaitRight(int secondsR)
{
int a;
for (a = secondsR; a >= 0; a--)
{
lcd.setCursor(18, 3);
if(a >= 10)
{
lcd.print(a);
}
else
{
lcd.print(" ");
lcd.print(a);
}
delay(1000);
}
}
void screenWaitLeft(int secondsL)
{
int b;
for (b = secondsL; b >= 0; b--)
{
lcd.setCursor(0, 3);
if(b >= 10)
{
lcd.print(b);
}
else
{
lcd.print(b);
lcd.print(" ");
}
delay(1000);
}
}
void showTrendIndicator(float val)
{
if (val > 0)
{
lcd.write(byte(0));
}
else if (val < 0)
{
lcd.write(byte(1));
}
else
{
lcd.write(byte(2));
}
}
void showGraphColumn(int pixelHeight, int c)
{
switch (pixelHeight)
{
case 1:
lcd.setCursor(c + 5, 3);
lcd.write(byte(0));
break;
case 2:
lcd.setCursor(c + 5, 3);
lcd.write(byte(1));
break;
case 3:
lcd.setCursor(c + 5, 3);
lcd.write(byte(2));
break;
case 4:
lcd.setCursor(c + 5, 3);
lcd.write(byte(3));
break;
case 5:
lcd.setCursor(c + 5, 3);
lcd.write(byte(4));
break;
case 6:
lcd.setCursor(c + 5, 3);
lcd.write(byte(5));
break;
case 7:
lcd.setCursor(c + 5, 3);
lcd.write(byte(6));
break;
case 8:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
break;
case 9:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(0));
break;
case 10:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(1));
break;
case 11:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(2));
break;
case 12:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(3));
break;
case 13:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(4));
break;
case 14:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(5));
break;
case 15:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(6));
break;
case 16:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
break;
case 17:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(0));
break;
case 18:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(1));
break;
case 19:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(2));
break;
case 20:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(3));
break;
case 21:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(4));
break;
case 22:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(5));
break;
case 23:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(6));
break;
case 24:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
break;
case 25:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(0));
break;
case 26:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(1));
break;
case 27:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(2));
break;
case 28:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(3));
break;
case 29:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(4));
break;
case 30:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(5));
break;
case 31:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(6));
break;
case 32:
lcd.setCursor(c + 5, 3);
lcd.write(byte(7));
lcd.setCursor(c + 5, 2);
lcd.write(byte(7));
lcd.setCursor(c + 5, 1);
lcd.write(byte(7));
lcd.setCursor(c + 5, 0);
lcd.write(byte(7));
break;
}
}
Comments