//----------------------------------------------------------------//
//For DHT22 Sensor
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
//For Sampling Rate Millis
unsigned long currentMillis;
unsigned long previousMillis;
unsigned long samplingRate = 2000; //This will be change to 2sec
//----------------------------------------------------------------//
//----------------------------------------------------------------//
//For Button Pin Assignment and States
#define left_btn A0
#define ok_btn A1
#define right_btn A2
//For Button States
int left_State;
int ok_State;
int right_State;
//For Buttons Flags
int LeftClick;
int RightClick;
//----------------------------------------------------------------//
//----------------------------------------------------------------//
//For Switching Menu
int EnterMode = 0;
int MainMenu = 0;
int SubMenu_2 = 0;
int SubMenu_3 = 0;
int SubMenu_4 = 0;
//For LCD Pins
#include <LiquidCrystal.h>
#define RS 13
#define EN 12
#define D4 11
#define D5 10
#define D6 9
#define D7 8
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
//----------------------------------------------------------------//
//----------------------------------------------------------------//
//For PID Control
#include <PID_v1.h>
#define PIN_INPUT 2
#define LightBulb 3
#define DCFan 5
//For Storing Precious Variables
//float SV_h = 20.0; //incase Humidity PID is used
float PV_h; //For Storing Humidity Input
//For Offset Values
float offset_t;
float offset_h;
//Define Variables we'll be connecting to
double SV_t = 35.0, PV_t, Output;
//Specify the links and initial tuning parameters
double kP_T = 2, kI_T = 5, kD_T = 1;
PID tempPID(&PV_t, &Output, &SV_t, kP_T, kI_T, kD_T, DIRECT);
int OnTimeInterval = 250;
unsigned long OnStartTime;
//----------------------------------------------------------------//
void setup() {
//For Serial Communication
Serial.begin(9600);
//For DHT Sensor to Begin
dht.begin();
sensor_t sensor;
//For PID Library
tempPID.SetOutputLimits(0, OnTimeInterval); //tell the PID to range between 0 and the full window size
tempPID.SetMode(AUTOMATIC); //turn the PID on
OnStartTime = millis();
//For Input Buttons
pinMode(left_btn, INPUT_PULLUP);
pinMode(ok_btn, INPUT_PULLUP);
pinMode(right_btn, INPUT_PULLUP);
//For Outputs
pinMode(LightBulb,OUTPUT);
pinMode(DCFan,OUTPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
ButtonStates();
Display();
switch (EnterMode) {
case 1:
switch (MainMenu) {
case 1:
//Starts the Loop
sensorData(); //Runs the sensor Data gathering
PID(); //Runs the PID Controlling
Fan(255); //Runs the Inside Fan
break;
}
break;
}
}
void sensorData() {
//Will read DHT sensor every 2 seconds
currentMillis = millis();
if (currentMillis - previousMillis >= samplingRate) {
previousMillis = currentMillis;
//PV = dht.readTemperature();
PV_t = dht.readTemperature() + offset_t;
PV_h = dht.readHumidity() + offset_h;
}
}
void PID() {
Serial.print("OnStartTime: ");
Serial.println(OnStartTime);
Serial.print("OUTPUT: ");
Serial.println(Output);
tempPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if (millis() - OnStartTime > OnTimeInterval)
{ //time to shift the Relay Window
OnStartTime += OnTimeInterval;
}
//Output Control
if (Output < millis() - OnStartTime) digitalWrite(LightBulb, LOW);
else if (Output > millis() - OnStartTime) digitalWrite(LightBulb, HIGH);
}
void Fan(int fanSpeed) {
analogWrite(DCFan, fanSpeed);
}
void Display() {
//For Ok BTN Selection
switch (EnterMode) {
case 0: //No Menu is selected yet; scanning all the menus
switch (MainMenu) {
case 0: //WELCOME SCREEN
//Prints at the LCD
lcd.setCursor(0,0);
lcd.print(" Arduino - PID ");
lcd.setCursor(0,1);
lcd.print(" Egg Incubator ");
break;
case 1: //DISPLAY INFO
//Turns off the Relay if Display info is exited
digitalWrite(LightBulb, LOW);
//Prints at the LCD
lcd.setCursor(0,0);
lcd.print(" DISPLAY INFO ");
lcd.setCursor(0,1);
lcd.print("<< ENT. >>");
break;
case 2: //SET TARGET VALUES
lcd.setCursor(0,0);
lcd.print("SET TARGET VALUE");
lcd.setCursor(0,1);
lcd.print("<< ENT. >>");
break;
case 3: //CHANGE PID VALUES
lcd.setCursor(0,0);
lcd.print("CHANGE PID VALUE");
lcd.setCursor(0,1);
lcd.print("<< ENT. >>");
break;
case 4: //CHANGE OFFSET VALUES
lcd.setCursor(0,0);
lcd.print("EDIT OFFSET VAL.");
lcd.setCursor(0,1);
lcd.print("<< ENT. >>");
break;
case 5: //IF SURPASSED THE TOTAL MENUS, GO BACK TO START
MainMenu = 0;
break;
case -1: //IF SURPASSED THE LOWEST VALUE, GOES BACK TO LAST
MainMenu = 4;
break;
}
break;
//When on of the Menu is selected
case 1:
switch (MainMenu) {
case 0: //WELCOME SCREEN
EnterMode = 0; //disabling enter mode in welcome screen
break;
case 1: //DISPLAY INFO
//Prints the data at LCD
//Shows the set Values
//Temperature
lcd.setCursor(0,0);
lcd.print("sT:");
lcd.setCursor(3,0);
lcd.print(SV_t, 1); //This will print the data in one decimal value instead of 2
lcd.setCursor(7,0);
lcd.print("C ");
//Humidity
lcd.setCursor(10,0);
lcd.print("O:");
//For Showing Output Value from 0~100%
double showData;
showData = map(Output, 0, OnTimeInterval, 0, 100); //maps out the value to 0~100%
lcd.setCursor(12,0);
lcd.print(showData, 0); //This will print the data with no decimal value
if (showData != 100 && showData >= 1) {
lcd.setCursor(14,0);
lcd.print(" %");
}
else if (showData == 0) {
lcd.setCursor(13,0);
lcd.print(" %");
}
else {
lcd.setCursor(15,0);
lcd.print("%");
}
//Shows the processed values
//Temperature
lcd.setCursor(0,1);
lcd.print("pT:");
lcd.setCursor(3,1);
lcd.print(PV_t, 1); //This will print the data in once decimal value instead of 2
lcd.setCursor(7,1);
lcd.print("C ");
//Humidity
lcd.setCursor(10,1);
lcd.print("pH:");
lcd.setCursor(13,1);
lcd.print(PV_h, 0); //This will print the data with no decimal value
lcd.setCursor(15,1);
lcd.print("%");
break;
case 2: //SET VALUES
//For SETTING TEMPERATURE
switch (SubMenu_2) {
//Set Temp Option
case 0:
lcd.setCursor(0,1);
lcd.print("Set Temperature");
break;
//Set Humid Option
case 1:
SubMenu_2 = 2; //skips the Set Humid Option
//lcd.setCursor(0,1);
//lcd.print(" Set Humidity ");
break;
//For Exiting
case 2:
lcd.setCursor(0,1);
lcd.print(" Exit ");
break;
//LOOPING THE SCREEN
//For Going back to first option
case 3:
SubMenu_2 = 0;
break;
//For Going back to last option
case -1:
SubMenu_2 = 2;
}
break;
case 3: //SET PID VALUES
//For SETTING PID Values
switch (SubMenu_3) {
//Set Proportional Gain
case 0:
lcd.setCursor(0,1);
lcd.print(" Set kP_T ");
break;
//Set Integral Gain
case 1:
lcd.setCursor(0,1);
lcd.print(" Set kI_T ");
break;
//Set Derivative Gain
case 2:
lcd.setCursor(0,1);
lcd.print(" Set kD_T ");
break;
//For Exiting
case 3:
lcd.setCursor(0,1);
lcd.print(" Exit ");
break;
//LOOPING THE SCREEN
//For Going back to first option
case 4:
SubMenu_3 = 0;
break;
//For Going back to last option
case -1:
SubMenu_3 = 3;
break;
}
break;
case 4: //SET OFFSET VALUES
//For OFFSET Values
switch (SubMenu_4) {
//Temperature Offset
case 0:
lcd.setCursor(0,1);
lcd.print("Set Temp. Offset");
break;
//Humidity Offset
case 1:
lcd.setCursor(0,1);
lcd.print("Set Humid Offset");
break;
//For Exiting
case 2:
lcd.setCursor(0,1);
lcd.print(" Exit ");
break;
//LOOPING THE SCREEN
//For Going back to first option
case 3:
SubMenu_4 = 0;
break;
//For Going back to last option
case -1:
SubMenu_4 = 2;
break;
}
break;
}
break;
//When a Sub-Menu is Selected
case 2:
//DISPLAY INFO
if (MainMenu == 1) { //if display info is selected,
EnterMode = 0; //EXITS back to MENU SELECTION
}
//SETTING VALUES
else if (MainMenu == 2) {
switch (SubMenu_2) {
//Temp Set
case 0:
lcd.setCursor(0,1);
lcd.print("Set Temp: ");
lcd.setCursor(10,1);
lcd.print(SV_t, 1);
lcd.setCursor(14,1);
lcd.print(" C");
break;
//Humidity Set
case 1:
//Skips the setting of Humidity
SubMenu_2 = 2;
//Since we dont need to control humidty
/*
lcd.setCursor(0,1);
lcd.print("Set Humid: ");
lcd.setCursor(11,1);
lcd.print(SV_h, 0);
lcd.setCursor(13,1);
lcd.print("% ");
*/
break;
//Exits back to main menu
case 2:
//goes back to main menu
EnterMode = 0;
//resetting back the sub menu to 0
SubMenu_2 = 0;
break;
}
}
//SETTING PID VALUES
else if (MainMenu == 3) {
switch (SubMenu_3) {
//Proportional Gain Set
case 0:
lcd.setCursor(0,1);
lcd.print("Set kP: ");
lcd.setCursor(8,1);
lcd.print(kP_T, 1);
//to clear uncertain spaces
if (kP_T >= 9.50) {
lcd.setCursor(12,1);
lcd.print(" ");
}
else if (kP_T >= 0.0 && kP_T <= 9.50) {
lcd.setCursor(11,1);
lcd.print(" ");
}
break;
//Integral Gain Set
case 1:
lcd.setCursor(0,1);
lcd.print("Set kI: ");
lcd.setCursor(8,1);
lcd.print(kI_T, 1);
//to clear uncertain spaces
if (kI_T >= 9.50) {
lcd.setCursor(12,1);
lcd.print(" ");
}
else if (kI_T >= 0.0 && kI_T <= 9.50) {
lcd.setCursor(11,1);
lcd.print(" ");
}
break;
//Derivative Gain Set
case 2:
lcd.setCursor(0,1);
lcd.print("Set kD: ");
lcd.setCursor(8,1);
lcd.print(kD_T, 1);
//to clear uncertain spaces
if (kD_T >= 9.50) {
lcd.setCursor(12,1);
lcd.print(" ");
}
else if (kD_T >= 0.0 && kD_T <= 9.50) {
lcd.setCursor(11,1);
lcd.print(" ");
}
break;
//Exits back to main menu
case 3:
//goes back to main menu
EnterMode = 0;
//resetting back the sub menu to 0
SubMenu_3 = 0;
break;
}
}
//SETTING OFFSET VALUES
else if (MainMenu == 4) {
switch (SubMenu_4) {
//Temperature OFFSET
case 0:
lcd.setCursor(0,1);
lcd.print("T Offset: ");
lcd.setCursor(10,1);
lcd.print(offset_t, 1);
//to clear unsused spaces
if (offset_t <= -0.50 && offset_t >= -9.50) {
lcd.setCursor(14,1);
lcd.print(" C");
}
else if (offset_t <= -10.0) {
lcd.setCursor(15,1);
lcd.print("C");
}
else if (offset_t >= 0.0 && offset_t <= 9.50) {
lcd.setCursor(13,1);
lcd.print(" C");
}
else if (offset_t >= 10.0) {
lcd.setCursor(14,1);
lcd.print(" C");
}
lcd.setCursor(15,1);
lcd.print("C");
break;
//HUMIDITY OFFSET
case 1:
lcd.setCursor(0,1);
lcd.print("H Offset: ");
lcd.setCursor(10,1);
lcd.print(offset_h, 1);
//to clear unsused spaces
if (offset_h <= -0.50 && offset_h >= -9.50) {
lcd.setCursor(14,1);
lcd.print(" %");
}
else if (offset_h <= -10.0) {
lcd.setCursor(15,1);
lcd.print("%");
}
else if (offset_h >= 0.0 && offset_h <= 9.50) {
lcd.setCursor(13,1);
lcd.print(" %");
}
else if (offset_h >= 10.0) {
lcd.setCursor(14,1);
lcd.print(" %");
}
lcd.setCursor(15,1);
lcd.print("%");
break;
//Exits back to main menu
case 2:
//goes back to main menu
EnterMode = 0;
//resetting back the sub menu to 0
SubMenu_4 = 0;
break;
}
}
break;
//Already in a sub-menu
case 3:
//For exiting menu 2
if (MainMenu == 2) {
EnterMode = 1;
}
//For exiting menu 3
else if (MainMenu == 3) {
EnterMode = 1;
}
//For exiting menu 4
else if (MainMenu == 4) {
EnterMode = 1;
}
break;
}
}
void ButtonStates() {
Serial.println(EnterMode);
//Serial.println(MainMenu);
left_State = digitalRead(left_btn);
ok_State = digitalRead(ok_btn);
right_State = digitalRead(right_btn);
if (ok_State == LOW) {
EnterMode++;
delay(150);
}
//For Changing Left and Right Keys during sub-menu or menu is selected
switch (EnterMode) {
//For MainMenu Switch
case 0:
if (left_State == LOW) {
MainMenu++;
delay(150);
}
else if (right_State == LOW) {
MainMenu--;
delay(150);
}
break;
//For SubMenu Switching
case 1:
switch(MainMenu) {
case 2: //Set Target Values
if (left_State == LOW) {
SubMenu_2++;
delay(150);
}
else if (right_State == LOW) {
SubMenu_2--;
delay(150);
}
break;
case 3: //Set PID Values
if (left_State == LOW) {
SubMenu_3++;
delay(150);
}
else if (right_State == LOW) {
SubMenu_3--;
delay(150);
}
break;
case 4: //Set Offset Values
if (left_State == LOW) {
SubMenu_4++;
delay(150);
}
else if (right_State == LOW) {
SubMenu_4--;
delay(150);
}
break;
}
break;
//For SubMenu Values Change
case 2:
switch (MainMenu) {
case 2: //Set Target Values
//For Selected SubMenu
switch (SubMenu_2) {
case 0: //If TEMPERATURE Set
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (SV_t <= 100.00) {
SV_t = SV_t + 0.5;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (SV_t > 28.00) {
SV_t = SV_t - 0.5;
delay(150);
}
}
break;
/*
case 1: //If HUMIDITY Set
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (SV_h <= 100) {
SV_h = SV_h + 1;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (SV_t > 20) {
SV_h = SV_h - 1;
delay(150);
}
}
break;
*/
}
break;
case 3: //Set PID Values
//For Selected SubMenu
switch (SubMenu_3) {
case 0: //If Proportional Gain is Set
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (kP_T <= 50.00) {
kP_T = kP_T + 00.5;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (kP_T > 1.00) {
kP_T = kP_T - 00.5;
delay(150);
}
}
break;
case 1: //If Integral Gain is Set
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (kI_T <= 50.00) {
kI_T = kI_T + 1;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (kI_T > 1.00) {
kI_T = kI_T - 1;
delay(150);
}
}
break;
case 2: //If Derivative Gain is Set
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (kD_T <= 50.00) {
kD_T = kD_T + 1;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (kD_T > 1.00) {
kD_T = kD_T - 1;
delay(150);
}
}
break;
}
break;
case 4:
//For Selected SubMenu
switch (SubMenu_4) {
case 0: //If Temperature Offset is selected
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (offset_t <= 50.00) {
offset_t = offset_t + 00.5;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (offset_t > -50.00) {
offset_t = offset_t - 00.5;
delay(150);
}
}
break;
case 1: //If Humidity Offset is selected
if (left_State == LOW) {
//MakI_Tng Sure SV is not above the max set value
if (offset_h <= 50.00) {
offset_h = offset_h + 1;
delay(150);
}
}
else if (right_State == LOW) {
//MakI_Tng Sure SV is not Below the min set value
if (offset_h > -50.00) {
offset_h = offset_h - 1;
delay(150);
}
}
break;
}
break;
}
//Enters Set PID Valuse Sub Menu
break;
case 4:
EnterMode = 0;
break;
}
}