#include <Wire.h>
#include <OneWire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
typedef enum
{
KEY_NOT_PRESS = 0,
KEY_PRESS_SHORT,
KEY_PRESS_LONG,
KEY_PRESS,
NUM_STATE_KEY
}
state_key_e;
typedef enum
{
TIME_STR = 0,
TEMP_STR,
FAN_STR,
}
state_menu;
#define I2C_DYSPLAY_ADDR (0x27)
#define PIN_ENC_A (2)
#define PIN_ENC_B (3)
#define PIN_ENC_SW (4)
#define PIN_TEMP_SENSOR (A0)
#define MAX_CNT_KEY_PRESS_SHORT (5)
#define MAX_CNT_KEY_PRESS_LONG (60)
#define MAX_DELAY_WORK_CHECK (100)
uint8_t arrow[8] = {
0b00000,
0b11000,
0b11100,
0b11110,
0b11111,
0b11110,
0b11100,
0b11000,
};
volatile int32_t cntEnc;
volatile boolean stateA;
volatile boolean lastStateA;
volatile boolean turnFlagEnc;
uint8_t statemenu;
uint8_t stateEncKey;
uint16_t KeyPressTime = 0;
boolean workingFlag = false;
boolean timeEditingFlag = false;
boolean tempEditingFlag = false;
boolean fanEditingFlag = false;
boolean heatingFlag = false;
boolean menunavstate = true;
uint8_t FanValue = 100;
uint8_t TempValue = 65;
uint8_t TempMeasured = 0;
uint32_t WorkTimer = 22800000;
uint8_t WorkTimer_h = 0;
uint8_t WorkTimer_m = 0;
uint8_t WorkTimer_s = 0;
uint16_t MainTimer = 0;
uint8_t blinkPeriod_time = 0;
uint8_t blinkPeriod_temp = 0;
uint8_t blinkPeriod_fan = 0;
const float BETA = 3950;
LiquidCrystal_I2C lcd(I2C_DYSPLAY_ADDR, 20, 4);
void setup() {
lcd.init(); // initialize the lcd
// Print a message to the LCD.
lcd.createChar(1, arrow);
lcd.backlight();
lcd.setCursor(2,0);
lcd.print("Time:");
lcd.setCursor(2,1);
lcd.print("Temp:");
lcd.setCursor(2,2);
lcd.print("Fan:");
lcd.setCursor(2,3);
lcd.print("STATE: SETTING");
lcd.setCursor(10,0);
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
lcd.print(WorkTimer_m);
lcd.setCursor(10,1);
TempMeasured = Get_Celsius_Temp();
lcd.print(TempMeasured);
lcd.print("/");
lcd.print(TempValue);
lcd.setCursor(18,1);
lcd.print("\xDF\C");
lcd.setCursor(10,2);
lcd.print("100");
lcd.setCursor(19,2);
lcd.print("%");
lcd.setCursor(0,0);
lcd.print("\x01");
//encoder
attachInterrupt(0, Enc_Callback_IRQ, CHANGE);
pinMode(PIN_ENC_A, INPUT_PULLUP);
pinMode(PIN_ENC_B, INPUT_PULLUP);
pinMode(PIN_ENC_SW, INPUT_PULLUP);
cntEnc = 0;
stateA = digitalRead(PIN_ENC_A);
lastStateA = stateA;
}
void loop() {
Enc_Button_Proc();
if (menunavstate) {
if (cntEnc > 2) cntEnc = 2;
if (cntEnc < 0) cntEnc = 0;
statemenu = cntEnc;
switch (statemenu)
{
case TIME_STR:
lcd.setCursor(0,1);
lcd.print("\x08");
lcd.setCursor(0,2);
lcd.print("\x08");
lcd.setCursor(0,0);
lcd.print("\x01");
break;
case TEMP_STR:
lcd.setCursor(0,0);
lcd.print("\x08");
lcd.setCursor(0,2);
lcd.print("\x08");
lcd.setCursor(0,1);
lcd.print("\x01");
break;
case FAN_STR:
lcd.setCursor(0,0);
lcd.print("\x08");
lcd.setCursor(0,1);
lcd.print("\x08");
lcd.setCursor(0,2);
lcd.print("\x01");
break;
}
}
Time_Editing();
Temp_Editing();
Fan_Editing();
TempMeasured = Get_Celsius_Temp();
if (!tempEditingFlag) {
lcd.setCursor(10,1);
lcd.print(TempMeasured);
lcd.print("/");
lcd.print(TempValue);
if ((TempValue < 100) || (TempMeasured < 100))
{
lcd.setCursor(16,1);
lcd.print("\x08");
if ((TempValue < 100) && (TempMeasured < 100))
{
lcd.setCursor(15,1);
lcd.print("\x08\x08");
if ((TempValue < 100) && (TempMeasured < 10)) {
lcd.setCursor(14,1);
lcd.print("\x08\x08");
}
}
}
}
if (workingFlag) {
if (TempValue > TempMeasured) {
lcd.setCursor(10,0);
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
lcd.print("\x08\x08\x08");
if (heatingFlag) {
lcd.setCursor(10,3);
lcd.print("HEATING");
}
else {
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("HEATING");
heatingFlag = true;
}
}
else {
if (!heatingFlag) {
lcd.setCursor(10,3);
lcd.print("DRYING");
if (millis() - MainTimer >= 1000) {
MainTimer += 1000;
WorkTimer -= 1000ul;
lcd.setCursor(10,0);
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
WorkTimer_s = ((WorkTimer / 1000ul) % 3600ul) % 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
lcd.print(":");
if (WorkTimer_s < 10) lcd.print("0");
lcd.print(WorkTimer_s);
}
}
else {
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("DRYING");
heatingFlag = false;
}
}
}
}
void Enc_Button_Proc(void) {
if (digitalRead(PIN_ENC_SW) == LOW) KeyPressTime++;
if (digitalRead(PIN_ENC_SW) == HIGH) {
if ((KeyPressTime >= MAX_CNT_KEY_PRESS_SHORT) && (KeyPressTime < MAX_CNT_KEY_PRESS_LONG) && (!workingFlag)) {
switch (statemenu)
{
case TIME_STR:
if (!timeEditingFlag) {
menunavstate = false;
cntEnc = WorkTimer / 600000ul;
timeEditingFlag = true;
}
else {
timeEditingFlag = false;
cntEnc = statemenu;
menunavstate = true;
lcd.setCursor(10,0);
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
}
break;
case TEMP_STR:
if (!tempEditingFlag) {
cntEnc = TempValue;
menunavstate = false;
tempEditingFlag = true;
}
else {
tempEditingFlag = false;
cntEnc = statemenu;
menunavstate = true;
lcd.setCursor(10,1);
TempMeasured = Get_Celsius_Temp();
lcd.print(TempMeasured);
lcd.print("/");
lcd.print(TempValue);
lcd.setCursor(18,1);
lcd.print("\xDF\C");
}
break;
case FAN_STR:
if (!fanEditingFlag) {
cntEnc = FanValue;
menunavstate = false;
fanEditingFlag = true;
}
else {
fanEditingFlag = false;
cntEnc = statemenu;
menunavstate = true;
lcd.setCursor(10,2);
lcd.print(FanValue);
if (FanValue == 0) {
lcd.setCursor(10,2);
lcd.print("OFF");
}
}
break;
}
}
if ((KeyPressTime >= MAX_CNT_KEY_PRESS_LONG) && (!timeEditingFlag) && (!tempEditingFlag) && (!fanEditingFlag)) {
if (!workingFlag) {
menunavstate = false;
workingFlag = true;
lcd.setCursor(0,0);
lcd.print("\x08");
lcd.setCursor(0,1);
lcd.print("\x08");
lcd.setCursor(0,2);
lcd.print("\x08");
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,0);
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
lcd.print("\x08\x08\x08");
if (TempValue > TempMeasured) {
lcd.setCursor(10,3);
if (heatingFlag) {
lcd.print("HEATING");
}
else {
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("HEATING");
heatingFlag = true;
}
}
else {
lcd.setCursor(10,3);
if (!heatingFlag) {
lcd.print("DRYING");
}
else {
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("DRYING");
heatingFlag = false;
}
}
}
else {
menunavstate = true;
workingFlag = false;
lcd.setCursor(10,0);
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
lcd.print("\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08");
lcd.setCursor(10,3);
lcd.print("SETTING");
}
}
KeyPressTime = 0;
}
}
inline void Time_Editing(void) {
if ((timeEditingFlag) && (!workingFlag)) {
blinkPeriod_time++;
if (WorkTimer < 35400000)
{
lcd.setCursor(14,0);
lcd.print("\x08");
}
if ((blinkPeriod_time > 10) && (blinkPeriod_time < 20)) {
if (cntEnc > 144) cntEnc = 144;
if (cntEnc < 1) cntEnc = 1;
lcd.setCursor(10,0);
WorkTimer = cntEnc * 600000ul;
WorkTimer_h = (WorkTimer / 1000ul) / 3600ul;
WorkTimer_m = ((WorkTimer / 1000ul) % 3600ul) / 60ul;
lcd.print(WorkTimer_h);
lcd.print(":");
if (WorkTimer_m < 10) lcd.print("0");
lcd.print(WorkTimer_m);
}
if (blinkPeriod_time > 20) {
lcd.setCursor(10,0);
lcd.print("\x08\x08\x08\x08\x08");
}
if (blinkPeriod_time > 30) {
blinkPeriod_time = 0;
}
WorkTimer = cntEnc * 600000ul;
}
}
inline void Temp_Editing(void) {
if ((tempEditingFlag) && (!workingFlag)) {
blinkPeriod_temp++;
if ((TempValue < 100) || (TempMeasured < 100))
{
lcd.setCursor(16,1);
lcd.print("\x08");
if ((TempValue < 100) && (TempMeasured < 100))
{
lcd.setCursor(15,1);
lcd.print("\x08\x08");
if ((TempValue < 100) && (TempMeasured < 10)) {
lcd.setCursor(14,1);
lcd.print("\x08\x08");
}
}
}
if ((blinkPeriod_temp > 15) && (blinkPeriod_temp < 30)) {
if (cntEnc > 119) cntEnc = 120;
if (cntEnc < 20) cntEnc = 20;
lcd.setCursor(10,1);
lcd.print(TempMeasured);
lcd.print("/");
lcd.print(TempValue);
}
if (blinkPeriod_temp > 30) {
if ((TempValue < 100) && (TempMeasured < 100)) {
lcd.setCursor(13,1);
lcd.print("\x08\x08");
if (TempMeasured < 10) {
lcd.setCursor(12,1);
lcd.print("\x08\x08");
}
}
if ((TempValue < 100) && (TempMeasured > 99)) {
lcd.setCursor(14,1);
lcd.print("\x08\x08");
}
if ((TempValue > 99) && (TempMeasured > 99)) {
lcd.setCursor(14,1);
lcd.print("\x08\x08\x08");
}
if ((TempValue > 99) && (TempMeasured < 100)) {
lcd.setCursor(13,1);
lcd.print("\x08\x08\x08");
if (TempMeasured < 10) {
lcd.setCursor(12,1);
lcd.print("\x08\x08\x08");
}
}
}
if (blinkPeriod_temp > 45) {
blinkPeriod_temp = 0;
}
TempValue = cntEnc;
}
}
inline void Fan_Editing(void) {
if ((fanEditingFlag) && (!workingFlag)) {
blinkPeriod_fan++;
if ((blinkPeriod_fan > 10) && (blinkPeriod_fan < 20)) {
if ((FanValue < 100) && (FanValue != 0))
{
lcd.setCursor(12,2);
lcd.print("\x08");
if ((FanValue < 10) && (FanValue != 0))
{
lcd.setCursor(11,2);
lcd.print("\x08\x08");
}
}
if (cntEnc > 99) cntEnc = 100;
if (cntEnc < 1) {
cntEnc = 0;
lcd.setCursor(10,2);
lcd.print("OFF");
lcd.setCursor(19,2);
lcd.print("\x08");
}
else {
lcd.setCursor(10,2);
lcd.print(FanValue);
lcd.setCursor(19,2);
lcd.print("%");
}
}
if (blinkPeriod_fan > 20) {
lcd.setCursor(10,2);
lcd.print("\x08\x08\x08");
}
if (blinkPeriod_fan > 30) {
blinkPeriod_fan = 0;
}
FanValue = cntEnc;
}
}
int8_t Get_Celsius_Temp(void) {
int analogValue = analogRead(A0);
float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
int8_t rounded_celsius = (int) celsius;
if (celsius < 1) rounded_celsius = 1;
return rounded_celsius;
}
static void Enc_Callback_IRQ(void) {
stateA = digitalRead(PIN_ENC_A);
if (stateA != lastStateA) {
turnFlagEnc = !turnFlagEnc;
if (turnFlagEnc) {
cntEnc += (digitalRead(PIN_ENC_B) != lastStateA) ? 1 : -1;
}
lastStateA = stateA;
}
}