#include <Wire.h>
#include <LCD_I2C.h>
#include <EEPROM.h>
/* borders setting */
#define DEF_T_MIN 40 //[°C]
#define DEF_T_MAX 77 //[°C]
#define DEF_HYST 2.0 //[°C] hyst=(i+1)/10 [0-127]=>[0.1-12.8]
#define DEF_FWDRET_DIFF 2 //[°C]
#define DISP_LIGHT_DURATION 10000 //[ms] interval po ktorom zhasne displej a nastavi sa vychodzie menu
#define DISPDELAY 2000 //[ms] interval nacitania prepisovania hodnot na displeji v kludovej polohe
/* HW setting */
#define RELAY_PUMP_PIN 11
#define RELAY_FAN_PIN 10
#define NTC_FWD_PWR_PIN 13
#define NTC_RET_PWR_PIN 12
#define NTC_FWD_PIN A0
#define NTC_RET_PIN A1
#define BETA_VALUE 3950
#define PIN_KEY_RIGHT 4 //pin for RIGHT key
#define PIN_KEY_UP 5 //pin for UP key
#define PIN_KEY_DOWN 7 //pin for DOWN key
#define PIN_KEY_LEFT 8 //pin for LEFT key
#define PIN_KEY_START 3 //pin for start fan key
#define PIN_KEY_STOP 6 //pin for stop fan key
#define DISP_LINE_LENGTH 20
/* menu setting */
#define DISP_TEMP 0
#define DISP_TMIN 1
#define DISP_TMAX 2
#define DISP_HYST 3
#define DISP_TDIFF 4
#define DISP_TEST_CERP 5
#define DISP_TEST_VENT 6
#define DEBOUNCE_DELAY 210 //[ms] min 1!
#define KEYUP 1
#define KEYDOWN 2
#define KEYLEFT 3
#define KEYRIGHT 4
#define KEYSTART 5
#define KEYSTOP 6
//stupen je na displeji DFh
char degreeC [3] = {0xDF, 'C', 0x00};
bool relayPump = false;
bool relayFan = false;
float tFwd, tRet;
//zapis do pamate
byte eepromLength = 504; //velkost pamate 512 (13 bytov na jeden zaznam 512/13 = 39 vyuzitelnych je 507 zvysok 8 bytov) (namiesto riadku eepromLength = EEPROM.length(); v setupe)
byte memShift = 13; //pocet bytov settingu, ktore sa ulozia v jednom kroku, prvy byte je status
byte memStatByte = 509; //adresa byte v pamati, kde sa ulozi stav ventilatora
byte memAddr = 0;
//status: bit 0: 1 - vymazane alebo nepouzite, 0 - prave aktivne
float hyst = DEF_HYST; //pri vypocte sa deli 10-mi, takze krok 0.1
float tMin = DEF_T_MIN; //minimalna teplota zapina cerpadlo
float tMax = DEF_T_MAX; //maximalna teplota -vypina ventilator
float tDiff = DEF_FWDRET_DIFF; //ked je rozdiel teplot mensi, vypne cerpadlo
float tempVal; //pouzivana pri editovani hodnot
int menuH = 0;
int menuV = 0;
bool editmode = false;
bool bckl = false;
unsigned long lastpress = 0;
unsigned long lastdisp = 0;
LCD_I2C lcd(0x27, DISP_LINE_LENGTH, 2);
//======================================================================================================================
//======================================================================================================================
void setup()
{
Serial.begin(9600);
pinMode(PIN_KEY_UP, INPUT_PULLUP);
pinMode(PIN_KEY_DOWN, INPUT_PULLUP);
pinMode(PIN_KEY_LEFT, INPUT_PULLUP);
pinMode(PIN_KEY_RIGHT, INPUT_PULLUP);
pinMode(PIN_KEY_START, INPUT_PULLUP);
pinMode(PIN_KEY_STOP, INPUT_PULLUP);
pinMode(RELAY_PUMP_PIN, OUTPUT);
pinMode(RELAY_FAN_PIN, OUTPUT);
pinMode(NTC_FWD_PWR_PIN, OUTPUT);
pinMode(NTC_RET_PWR_PIN, OUTPUT);
digitalWrite(RELAY_PUMP_PIN, 0); //Cerpadlovy pin 0 = OFF
digitalWrite(RELAY_FAN_PIN, 0); //Ventilatorovy pin 0 = OFF
lcd.begin(); // If you are using more I2C devices using the Wire library use lcd.begin(false)
// this stop the library(LCD_I2C) from calling Wire.begin()
lcd.noBacklight();
lcd.clear();
//bit 0: 1 vymazane, nepouzite
// 0 aktivne
//bit 7-1: hysterezia -deli sa 10timi - krok 0.1 stupna, 0 - 127 (0-12.7 °C)
byte stat = EEPROM.read(memAddr);
while((stat & 0x01) != 0) //while(bitRead(stat, 0) != 0)
{
memAddr += memShift;
if((memAddr + memShift) > eepromLength)
{
memAddr = eepromLength;
break;
}
stat = EEPROM.read(memAddr);
}
if(memAddr != eepromLength)
{
// Serial.print("Nacitanie hodnot z pamate: ");
EEPROM.get(memAddr + 1, tMin);
EEPROM.get(memAddr + 5, tMax);
EEPROM.get(memAddr + 9, tDiff);
hyst = float((stat >> 1)) / 10;
}
// else
// {
// Serial.println("Pouzitie vyrobnych nastaveni");
// }
tMin = (tMin < 0) ? 0 : tMin;
tMin = (tMin > 60) ? 60 : tMin;
tMax = (tMax < 60) ? 60 : tMax;
tMax = (tMax > 100) ? 100 : tMax;
hyst = (hyst > 12.6) ? 12.6 : hyst;
hyst = (hyst < 0.2) ? 0.2 : hyst;
if(tMax < (tMin + hyst))
{
if(tMin > (40 - hyst))
tMin = 40 - hyst;
tMax = tMin + hyst;
}
tDiff = (tDiff < 0) ? 0 : tMin;
tDiff = (tDiff > 4) ? 4 : tMin;
EEPROM.get(memStatByte, relayFan);
digitalWrite(RELAY_FAN_PIN, relayFan);
dispSet();
lastdisp = 3000;
}
//======================================================================================================================
//======================================================================================================================
void loop()
{
if(Serial.available() > 0)
{
char c = Serial.read();
if(c == 'a')
{
Serial.println(tFwd);
}
else if(c == 'b')
{
Serial.println(tRet);
}
else if(c == 'c')
{
Serial.println(relayPump);
}
else if(c == 'd')
{
Serial.println(relayFan);
}
// else if((c != 0x0D) && (c != 0x0A) && (c != 0))
// {
// Serial.println(c);
// }
}
int key = getKeyNumber();
unsigned long tm = millis(); //actual time
if(key)
{
lastpress = tm;
if(!bckl)
{
lcd.backlight();
bckl = true;
}
delay(DEBOUNCE_DELAY);
}
else
{
if(bckl)
{
if(tm > (lastpress + DISP_LIGHT_DURATION))
{
lcd.noBacklight();
bckl = false;
menuV = DISP_TEMP;
menuH = 0;
}
}
}
if(key == KEYLEFT)
menuH--;
else if(key == KEYRIGHT)
menuH++;
if(menuH < 0)
menuH = 0;
if(menuH > 3)
menuH = 0;
if(menuH == 0)
{
if(editmode)
{
editmode = false;
}
else
{
if(key == KEYUP)
{
if(menuV > DISP_TEMP)
menuV--;
}
else if(key == KEYDOWN)
{
if(menuV < DISP_TEST_VENT)
menuV++;
}
}
}
if(key)
{
if(key == KEYSTART)
{
if(relayFan)
{
lcd.clear();
lcd.print(" Ventilator");
lcd.setCursor(0, 1);
lcd.print(" je uz zapnuty");
}
else
{
relayFan = true;
digitalWrite(RELAY_FAN_PIN, relayFan); //zapne ventilator
EEPROM.write(memStatByte, 0x01);
lcd.clear();
lcd.print(" Zapnutie");
lcd.setCursor(0, 1);
lcd.print(" ventilatora");
}
delay(500);
}
else if(key == KEYSTOP)
{
if(relayFan)
{
relayFan = false;
digitalWrite(RELAY_FAN_PIN, relayFan); //vypne ventilator
EEPROM.write(memStatByte, 0x00);
lcd.clear();
lcd.print(" Vypnutie");
lcd.setCursor(0, 1);
lcd.print(" ventilatora");
}
else
{
lcd.clear();
lcd.print(" Ventilator");
lcd.setCursor(0, 1);
lcd.print(" je uz vypnuty");
}
delay(500);
}
if(menuV == DISP_TMIN) //+++++++++++++++++++++++++++++++++++++++++TMIN
{
if(menuH == 0)
{
dispMenuVal(1);
}
if(menuH == 1)
{
if(key == KEYRIGHT)
{
tempVal = tMin;
}
editmode = true;
if(key == KEYUP)
tempVal += 0.1;
if(key == KEYDOWN)
tempVal -= 0.1;
tempVal = (tempVal < 30) ? 30 : tempVal;
tempVal = (tempVal > 70) ? 70 : tempVal;
if(tempVal > (tMax - hyst))
tempVal = tMax - hyst;
dispMenuSet();
}
if(menuH == 2)
{
dispMenuQuest();
}
if(menuH == 3)
{
tMin = tempVal;
memWriteSetting();
dispSaved();
editmode = false;
menuH = 0;
}
}
else if(menuV == DISP_TMAX) //+++++++++++++++++++++++++++++++++++++++++TMAX
{
if(menuH == 0)
{
dispMenuVal(2);
}
if(menuH == 1)
{
if(key == KEYRIGHT)
{
tempVal = tMax;
}
editmode = true;
if(key == KEYUP)
tempVal += 0.1;
if(key == KEYDOWN)
tempVal -= 0.1;
tempVal = (tempVal < 60) ? 60 : tempVal;
tempVal = (tempVal > 90) ? 90 : tempVal;
if(tempVal < (tMin + hyst))
tempVal = tMin + hyst;
dispMenuSet();
}
if(menuH == 2)
{
dispMenuQuest();
}
if(menuH == 3)
{
tMax = tempVal;
memWriteSetting();
dispSaved();
editmode = false;
menuH = 0;
}
}
else if(menuV == DISP_HYST) //+++++++++++++++++++++++++++++++++++++++++HYST
{
if(menuH == 0)
{
dispMenuVal(3);
}
if(menuH == 1)
{
if(key == KEYRIGHT)
{
tempVal = hyst;
}
editmode = true;
if(key == KEYUP)
tempVal += 0.1;
if(key == KEYDOWN)
tempVal -= 0.1;
tempVal = (tempVal > 12.6) ? 12.6 : tempVal;
tempVal = (tempVal < 0.2) ? 0.2 : tempVal;
dispMenuSet();
}
if(menuH == 2)
{
dispMenuQuest();
}
if(menuH == 3)
{
hyst = tempVal;
memWriteSetting();
dispSaved();
editmode = false;
menuH = 0;
}
}
else if(menuV == DISP_TDIFF) //+++++++++++++++++++++++++++++++++++++++++HYST
{
if(menuH == 0)
{
dispMenuVal(4);
}
if(menuH == 1)
{
if(key == KEYRIGHT)
{
tempVal = tDiff;
}
editmode = true;
if(key == KEYUP)
tempVal += 0.1;
if(key == KEYDOWN)
tempVal -= 0.1;
tempVal = (tempVal > 10.0) ? 10.0 : tempVal;
tempVal = (tempVal < 0.0) ? 0.0 : tempVal;
dispMenuSet();
}
if(menuH == 2)
{
dispMenuQuest();
}
if(menuH == 3)
{
tDiff = tempVal;
memWriteSetting();
dispSaved();
editmode = false;
menuH = 0;
}
}
else if(menuV == DISP_TEST_CERP) //+++++++++++++++++++++++++++++++++++++++++TEST_CERP
{
if(menuH == 0)
{
lcd.clear();
lcd.print("Test zap. cerpadla");
lcd.setCursor(0, 1);
if(relayPump)
lcd.print("ZAPNUTE ");
else
lcd.print("VYPNUTE ");
}
else
{
if(menuH == 2)
{
menuH = 1;
if(key == KEYRIGHT)
{
if(relayPump)
relayPump = false;
else
relayPump = true;
digitalWrite(RELAY_PUMP_PIN, relayPump);
}
}
if(menuH == 1)
{
//lcd.setCursor(0, 0);
//lcd.print("Test zap. cerpadla");
lcd.setCursor(0, 1);
if(relayPump)
lcd.print("ZAPNUTE -> vypnut ");
else
lcd.print("VYPNUTE -> zapnut ");
}
}
}
else if(menuV == DISP_TEST_VENT) //+++++++++++++++++++++++++++++++++++++++++TEST_VENT
{
if(menuH == 0)
{
lcd.clear();
lcd.print("Test ventilatora ");
lcd.setCursor(0, 1);
if(relayFan)
lcd.print("ZAPNUTY ");
else
lcd.print("VYPNUTY ");
}
else
{
if(menuH == 2)
{
menuH = 1;
if(key == KEYRIGHT)
{
if(relayFan)
relayFan = false;
else
relayFan = true;
digitalWrite(RELAY_FAN_PIN, relayFan);
}
}
if(menuH == 1)
{
//lcd.setCursor(0, 0);
//lcd.print("Test ventilatora");
lcd.setCursor(0, 1);
if(relayFan)
lcd.print("ZAPNUTY -> vypnut ");
else
lcd.print("VYPNUTY -> zapnut ");
}
}
}
}
//po stlaceni tlacitka start sa spusti ventilator, az po dosiahnutie nastavenej maximalnej teploty, vtedy sa vypne. Zakazdym sa ulozi okamzity stav ulozeny v memStatByte EEPROM
//Dalsi start az po stlaceni tlacidla start. Tlacidlo stop vypne ventilator (tiez na trvalo s ulozenim hodnoty).
//ked teplota klesne pod 30°C
//Cerpadlo sa spusti pri minimalnej teplote a vypne sa po poklese pod minimalnu teplotu s odpocitanou hystereziou.
/*
*
*
*
*
*
*
*
*/
//doplnit
if((menuV == 0) && (tm > (lastdisp + DISPDELAY)))
{
lastdisp = tm;
if(menuH)
menuH = 0;
//zakazdym DISPDELAY cyklom zapnutie napatia na senzoroch, zmeranie teploty, vypnutie napatia na senzoroch a podla hodnot prepnutie rele
digitalWrite(NTC_FWD_PWR_PIN, 1);
digitalWrite(NTC_RET_PWR_PIN, 1);
//priemerna hodnota z desiatich merani
delay(5);
unsigned int tempsampleFwd = analogRead(NTC_FWD_PIN);
unsigned int tempsampleRet = analogRead(NTC_RET_PIN);
for (uint8_t i = 0; i < 9; i++)
{
tempsampleFwd += analogRead(NTC_FWD_PIN);
tempsampleRet += analogRead(NTC_RET_PIN);
}
digitalWrite(NTC_FWD_PWR_PIN, 0);
digitalWrite(NTC_RET_PWR_PIN, 0);
//priemerna hodnota z desiatich merani
float voltFwd = tempsampleFwd / 10;
float voltRet = tempsampleRet / 10;
tFwd = 1 / (log(1 / (1023. / voltFwd - 1)) / BETA_VALUE + 1.0 / 298.15) - 273.15;
tRet = 1 / (log(1 / (1023. / voltRet - 1)) / BETA_VALUE + 1.0 / 298.15) - 273.15;
/* ---- VENTILATOR ---- */
//kontrola maximalnej teploty
if(relayFan) //vypnutie ventilatora
{
if((tFwd > tMax) || (tFwd <= (tRet - tDiff))) //+kontrola spiatocky (musi byt chladnejsia ako vystupna z pece)
{
relayFan = false; //vypne ventilator
digitalWrite(RELAY_FAN_PIN, relayFan);
EEPROM.write(memStatByte, 0x00);
}
}
// else
// {
// if(tFwd < (tMax - hyst))
// {
// relayFan = true; //zapne ventilator
// digitalWrite(RELAY_FAN_PIN, relayFan);
// }
// }
/* ---- VENTILATOR END ---- */
/* ---- CERPADLO ---- */
if(relayPump)
{
//ak je min teplota - hyst. - vypnutie cerpadla +kontrola spiatocky (musi byt chladnejsia ako vystupna z pece)
if((tFwd < (tMin - hyst)) || (tFwd <= tRet))
{
relayPump = false;
digitalWrite(RELAY_PUMP_PIN, relayPump);
}
}
else
{
//ak je teplota vyssia, ako nastavena vystupna teplota a spiatocka, cerpadlo sa zapne
if((tFwd > tMin) && (tFwd > tRet + tDiff))
{
relayPump = true;
digitalWrite(RELAY_PUMP_PIN, relayPump);
}
}
/* ---- CERPADLO END ---- */
dispTemp(tFwd, tRet);
//
// Serial.print("Tfwd= ");
// Serial.print(tFwd, 1);
// Serial.print("°C, Tret= ");
// Serial.print(tRet, 1);
// Serial.println("°C");
// Serial.print("Cerpadlo: ");
// Serial.print(relayPump ? "ON" : "OFF");
// Serial.print(" Ventilator");
// Serial.println(relayFan ? "ON" : "OFF");
}
}
//======================================================================================================================
//======================================================================================================================
void dispSet(void)
{
lcd.clear();
lcd.print("Tmin:");
lcd.print(tMin, 1);
//lcd.print(degreeC);
lcd.print(" Tmax:");
lcd.print(tMax, 1);
//lcd.print(degreeC);
lcd.setCursor(0, 1);
lcd.print("Hyst: ");
lcd.print(hyst, 1);
//lcd.print(degreeC);
lcd.print(" Tdif:");
lcd.print(tDiff, 1);
}
//======================================================================================================================
//======================================================================================================================
void dispTemp(float tF, float tR)
{
//lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Tfwd:");
lcd.print(tF, 1);
lcd.print(" ");
lcd.setCursor(9, 0);
lcd.print(degreeC);
lcd.setCursor(11, 0);
lcd.print(" cerp:");
if(relayPump)
lcd.print("ON ");
else
lcd.print("OFF");
lcd.setCursor(0, 1);
lcd.print("Tret:");
lcd.print(tR, 1);
lcd.print(" ");
lcd.setCursor(9, 1);
lcd.print(degreeC);
lcd.setCursor(11, 1);
lcd.print(" vent:");
if(relayFan)
lcd.print("ON ");
else
lcd.print("OFF ");
}
//======================================================================================================================
//======================================================================================================================
void dispMenuVal(byte valnr)
{
lcd.clear();
if(valnr == 1)
lcd.print("Minimalna teplota");
if(valnr == 2)
lcd.print("Maximalna teplota");
if(valnr == 3)
lcd.print("Hysterezia cerpadla");
if(valnr == 4)
lcd.print("rozdiel spiatocky");
lcd.setCursor(0, 1);
if(valnr == 1)
lcd.print(tMin, 1);
else if(valnr == 2)
lcd.print(tMax, 1);
else if(valnr == 3)
lcd.print(hyst, 1);
else if(valnr == 4)
lcd.print(tDiff, 1);
lcd.print(degreeC);
}
//======================================================================================================================
//======================================================================================================================
void dispMenuSet(void)
{
lcd.setCursor(0, 1);
lcd.print("^[ ");
lcd.print(tempVal, 1);
lcd.print(" ]v");
lcd.print(degreeC);
lcd.print(" ");
}
//======================================================================================================================
//======================================================================================================================
void dispMenuQuest(void)
{
lcd.setCursor(0, 1);
lcd.print(tempVal, 1);
lcd.print(degreeC);
lcd.print(" Save? >");
}
//======================================================================================================================
//======================================================================================================================
void dispSaved(void)
{
lcd.clear();
lcd.setCursor((DISP_LINE_LENGTH - 5)/2, 0);
lcd.print("SAVED");
}
//======================================================================================================================
//======================================================================================================================
int getKeyNumber(void)
{
//read if PIN_KEY_x is pulled to ground (0)
if(!digitalRead(PIN_KEY_START))
return KEYSTART;
else if(!digitalRead(PIN_KEY_STOP))
return KEYSTOP;
else if(!digitalRead(PIN_KEY_UP))
return KEYUP;
else if(!digitalRead(PIN_KEY_DOWN))
return KEYDOWN;
else if(!digitalRead(PIN_KEY_LEFT))
return KEYLEFT;
else if(!digitalRead(PIN_KEY_RIGHT))
return KEYRIGHT;
else
return 0;
}
//======================================================================================================================
//======================================================================================================================
void memWriteSetting(void)
{
if(memAddr >= eepromLength)
memAddr = 0;
else
{
EEPROM.write(memAddr, 0xFF);
memAddr += memShift;
if((memAddr + memShift) > eepromLength)
memAddr = 0;
}
byte statusb = (byte)(hyst * 10);
EEPROM.write(memAddr, statusb << 1); //(memAddr, sw & 0xFE);
EEPROM.put(memAddr + 1, tMin);
EEPROM.put(memAddr + 5, tMax);
EEPROM.put(memAddr + 5, tDiff);
}
// //======================================================================================================================
// //======================================================================================================================
// void memList(int size)
// {
// int i;
// if(size > eepromLength)
// size = eepromLength;
// Serial.println("Memlist:");
// for(i = 0; i < size; i++)
// {
// byte b = EEPROM.read(i);
// Serial.print(b);
// Serial.print(" ");
// if(!((i+1) % 8))
// Serial.println("");
// }
// Serial.println("");
// }