Dew Heater Code

// 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);
}