// Copy code and paste into Arduino IDE
// Dew Heater Controller
// v4.0 using 0.96" 128x64 display, using I2C
// global constants
const int numHeaters = 2; // max number of heaters
const float tempCutOff = 25; // heater cut-off if too hot
const float dewPointThreshold = 5; // threshold above dew point to start heater
// these are the pins being used for sensors and heaters
// DHT22 = digital 2. Ambient temperature & humidity
// DS18B20 = digital 10, 11, 12. Sensor 1-3 temperature
// Heater Outputs = digital 3, 5, 6. To MOSFET heater drivers for DS18B20 sensors 1-3.
// the display = 128*64 I2C
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
// DHT22 for ambient temperature & humidity sensing
// on pin 2
#include <DHT.h>
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
#define DHTPIN 2 // the DHT22 pin
DHT dht(DHTPIN, DHTTYPE);
float dewPointAmbient;
float temperatureAmbient;
float humidityAmbient;
boolean errorDHT22;
// MOSFET Driver modules = Heater Outputs 1-3 on PWM pins
int heaterDutyCycle[] = {0, 0, 0}; // drive to heater
int heaterPin[] = {3, 5, 6}; // heater pins
// DS18B20 for sensing temperature on heated elements, using Onewire library
// Have separate pin for each DS18B20. Easier to wire up and distinguish
#include <OneWire.h>
#include <DallasTemperature.h>
int DS18B20Pin[] = {10, 11, 12}; // only pin12 at this stage
OneWire oneWire1(DS18B20Pin[0]);
OneWire oneWire2(DS18B20Pin[1]);
OneWire oneWire3(DS18B20Pin[2]);
DallasTemperature sensor1(&oneWire1);
DallasTemperature sensor2(&oneWire2);
DallasTemperature sensor3(&oneWire3);
boolean errorDS18B20[3];
float tempHeater[3]; // 3x heaters
// general - delay for sensor and "i" for counting
int theDelay = 1000; // need ~1sec delay after DS18B20 read in parasitic mode
int i;
void setup() {
Serial.begin(9600);
Serial.println("Dew Heater Controller");
Serial.println("DS18B20 test - serial output to computer");
Serial.println("Heater number \tDigital Pin \tStatus \t\tTemp (C)");
delay(theDelay*2);
// initialize display
// with the 128*64 SSD1306 display - I2C addr 0x3C (not 3D)
dht.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextColor(WHITE);
display.setTextSize(1);
// Display intro and heating parameters
display.setTextSize(1);
display.clearDisplay();
display.setCursor(16,0);
display.print("DEW HEATER v4.0");
display.drawRect(0, display.height()*0.35, display.width(), display.height()*0.05, WHITE);
display.setCursor(16,16);
display.print("Threshold: ");
display.print(dewPointThreshold,0);
display.write(9);
display.print("C");
display.setCursor(16,24);
display.print(" Cutoff: ");
display.print(tempCutOff,0);
display.write(9);
display.print("C");
display.display();
delay(theDelay*2);
// setup heater settings and set to zero
for (i = 0; i < numHeaters; i++) {
pinMode(heaterPin[i], OUTPUT); // sets the pin as output
heaterDutyCycle[i] = 0;
analogWrite(heaterPin[i] , heaterDutyCycle[i]);
}
}
void loop() {
// Read ambient temperature & humidity from DHT22
// & calculate dew point if no error reading
errorDHT22 = getDHT22data();
// display ambient data
displayAmbientData();
//displayHeaterData( theHeater);
// Read temperatures from DS18B20s and set duty cycle. NB-need long delay after read
for (i = 0; i < numHeaters; i++) {
displayHeaterData( i);
// read the heater, return if an error and value to global variable tempHeater
errorDS18B20[i] = getDS18B20data(i);
// send duty cycle to heater output, set to 0 if any read errors
heaterDutyCycle[i] = setDutyCycle(i);
analogWrite(heaterPin[i] , heaterDutyCycle[i]);
if ( !errorDS18B20[i] ) {
// display heater data if its connected (no errors)
displayHeaterData(i);
}
}
}
boolean getDHT22data() {
float logEx,dewPoint;
boolean anError;
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
humidityAmbient = dht.readHumidity();
// Read temperature as Celsius (the default)
temperatureAmbient = dht.readTemperature();
delay(theDelay);
if (isnan(temperatureAmbient) || isnan(humidityAmbient)) {
// if error reading DHT22 set all to 0
temperatureAmbient = 0;
humidityAmbient = 0;
dewPointAmbient = 0 ;
anError = true;
}
else {
// if no error reading DHT22 calc dew point
// more complex dew point calculation
logEx=0.66077 + 7.5*temperatureAmbient/(237.3+temperatureAmbient) + (log10(humidityAmbient) - 2);
dewPointAmbient = (logEx - 0.66077)*237.3/(0.66077+7.5-logEx);
// simpler dew point calculation
// dewPointAmbient = temperatureAmbient - ((100 - humidityAmbient)/5.0);
anError = false;
}
return anError;
}
boolean getDS18B20data(int theHeater) {
boolean anError = false;
// for each heater
// Start the sensor, read temperatures & save to global array tempHeater
if (theHeater == 0) {
// Start up the DallasTemperature library for lens temp sensors 1-3
sensor1.begin();
// delay(theDelay);
sensor1.requestTemperatures();
tempHeater[theHeater] = sensor1.getTempCByIndex(0);
}
if (theHeater == 1) {
sensor2.begin();
// delay(theDelay);
sensor2.requestTemperatures();
tempHeater[theHeater] = sensor2.getTempCByIndex(0);
}
if (theHeater == 2) {
sensor3.begin();
// delay(theDelay);
sensor3.requestTemperatures();
tempHeater[theHeater] = sensor3.getTempCByIndex(0);
}
if (tempHeater[theHeater] == -127) {
anError = true;
}
return anError;
}
int setDutyCycle(int theHeater) {
// set output duty cycle on temp diff between heater and ambient dew point
float aboveDewPoint;
float theDutyCycle = 0;
if (errorDHT22 || errorDS18B20[ theHeater ]) {
// Heater OFF if error reading DHT22 or DS18B20 (for this heater)
theDutyCycle = 0;
}
else {
if ( tempHeater[ theHeater ] > tempCutOff ) {
// Heater OFF if above cut-off
theDutyCycle = 0;
}
else {
// Heater ON if Temp < Threshold(C) above dew point(C)
aboveDewPoint = tempHeater[ theHeater ] - dewPointAmbient;
// restrict between 0 & threshold
Serial.print("aboveDewPoint1= "); Serial.println(aboveDewPoint);
aboveDewPoint = constrain( aboveDewPoint , 0 , dewPointThreshold );
// PWM 0 - 100% duty cycle EQUIV TO analog 0 - 255
theDutyCycle = 255 * (( dewPointThreshold - aboveDewPoint ) / dewPointThreshold );
Serial.print("tempHeater[ theHeater ]= "); Serial.println(tempHeater[ theHeater ]);
Serial.print("dewPointAmbient= "); Serial.println(dewPointAmbient);
Serial.print("aboveDewPoint= "); Serial.println(aboveDewPoint);
Serial.print("dewPointThreshold= "); Serial.println(dewPointThreshold);
Serial.print("theDutyCycle= "); Serial.println(theDutyCycle);
Serial.println("= ");
}
}
//theDutyCycle=200;
return theDutyCycle;
}
void displayAmbientData() {
display.clearDisplay();
display.setCursor(16,0);
display.print("AMBIENT");
display.setCursor(20,8);
display.print("Temp:");
display.setCursor(20,16);
display.print("Humidity:");
if (errorDHT22) {
// error reading DHT22
display.setCursor(80,8);
display.print("error");
display.setCursor(80,16);
display.print("error");
}
else {
// if ambient read okay display DHT22 data
display.setCursor(80,8);
display.print(temperatureAmbient, 0);
display.write(9);
display.print("C");
display.setCursor(80,16);
display.print(humidityAmbient, 0);
display.print("%");
display.setCursor(20,24);
display.print("DewPoint: ");
display.setCursor(80,24);
display.print(dewPointAmbient, 0);
display.write(9);
display.print("C");
}
display.display();
delay(theDelay);
}
void displayHeaterData( int theHeater ) {
float thePerCentDutyCycle;
thePerCentDutyCycle = 100 * heaterDutyCycle[ theHeater ] / 255;
display.clearDisplay();
display.setCursor(0,0);
display.print("T");
display.print(theHeater+1);
display.print(": ");
Serial.print("theHeater= "); Serial.println(theHeater);
//tempHeater[theHeater] = sensor2.getTempCByIndex(0);//
tempHeater[ theHeater]=getDS18B20data(theHeater);
display.print(tempHeater[ theHeater] , 0);
//display.write(9);
display.print("C ");
if (tempHeater[ theHeater] > tempCutOff) {
// if above cut-off
display.print(" cutOFF");
}
else {
if ((tempHeater[ theHeater] - dewPointAmbient) > 0) {
display.print(">DP: H-D= ");
}
else {
display.print("<DP: H-D= ");
}
display.print(tempHeater[ theHeater] - dewPointAmbient , 0);
display.print("C");
}
display.setCursor(4*12,8);
// display.print("Power %");
uint8_t color = WHITE;
display.drawRect(0, display.height()*0.3, display.width(), display.height()*0.4, WHITE);
display.fillRect(0, display.height()*0.3, display.width()*thePerCentDutyCycle/100, display.height()*0.4, WHITE);
display.setCursor(0,24);
display.print("0");
display.setCursor(4.5*12,24);
display.print(thePerCentDutyCycle , 0);
display.print("%");
display.setCursor(9*12,24);
display.print("100");
display.display();
delay(theDelay);
}