#include <Arduino.h>
#include <LCDI2C_Multilingual.h>
#include <GyverMenu.h>
#include <GyverButton.h>
#include <OneWire.h>
#include <MsTimer2.h>
#include <EEPROM.h>
#include <StringN.h>
//Определение пинов
#define LED_RED 8
#define LED_GRN 10
#define OUT1 5
#define OUT2 6
#define ZERO 2
#define BUZZER 9
#define KEYB A0
#define DS18B20 7
//Таймоут датчика перегрева
#define OTHERHEAT_TIME 3000
//Определения включения и выключения выходов и индикации
#define LRED_ON digitalWrite(LED_RED,HIGH)
#define LRED_OFF digitalWrite(LED_RED,LOW)
#define LGRN_ON digitalWrite(LED_GRN,HIGH)
#define LGRN_OFF digitalWrite(LED_GRN,LOW)
#define OUT1_ON digitalWrite(OUT1,HIGH)
#define OUT1_OFF digitalWrite(OUT1,LOW)
#define OUT2_ON digitalWrite(OUT2,HIGH)
#define OUT2_OFF digitalWrite(OUT2,LOW)
#define T_ALERT tone(BUZZER,1000,400)
#define T_NO noTone(BUZZER)
//Режимы нагрева
#define ONE_HEAT 0
#define TWO_HEAT 1
#define AUTO_HEAT 2
//Переменная таймера перегрева
unsigned long timer_overhert=0;
//Перечисление функций клавиш
enum BUTT_FUNC {
BUT_LEFT,
BUT_RIGHT,
BUT_UP,
BUT_DOWN,
BUT_OK
};
struct CONFIG {
int temp;
bool OVH;
uint8_t mode;
int dt;
} cfg;
GButton butt[5];
GyverMenu menu(16, 2);
OneWire ds(DS18B20);
LCDI2C_Russian lcd(0x27, 16, 2);
int temperature = 10; // Глобальная переменная для хранения значение температуры с датчика DS18B20
long lastUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика
const int TEMP_UPDATE_TIME = 1000; // Определяем периодичность проверок готовности данных DS18B20
bool OVH_ERROR=false; // Флаг ошибки перегрева;
bool isMenu=false;
bool isWork=false;
uint8_t H=1;
//Сброс таймера перегрева по прерыванию
void zero(void) {
timer_overhert=millis();
OVH_ERROR=false;
}
// ---------------------
bool detectTemperature(void);
void flash(void);
// ---------------------
void setup() {
if(EEPROM.read(0)==1) {
EEPROM.get(1,cfg);
} else {
//Данные тестового меню
cfg.OVH=true;
cfg.mode=AUTO_HEAT;
cfg.temp=30;
cfg.dt=2;
EEPROM.write(0,1);
EEPROM.put(1,cfg);
}
Serial.begin(57600);
//Подключение прерывания
attachInterrupt(0, &zero, CHANGE);
//Таймер для мигания светодиодом
MsTimer2::set(200, flash); // период
MsTimer2::start();
interrupts();
//Инициализация дисплея
lcd.init();
lcd.backlight();
//Настройка выходов
pinMode(ZERO,INPUT_PULLUP); // Вход сигнала датчика перегрева
pinMode(LED_RED,OUTPUT); // Выход на красный светодиод
pinMode(LED_GRN,OUTPUT); // Выход на зеленый светодиод
pinMode(OUT1,OUTPUT); // Выход на реле 1
pinMode(OUT2,OUTPUT); // Выход на реле 2
pinMode(BUZZER,OUTPUT); // Выход на бузер
//Меню - ТЕСТ
menu.onPrint([](const char* str, size_t len) {
if (str) lcd.Print::write(str, len);
});
menu.onCursor([](uint8_t row, bool chosen, bool active) -> uint8_t {
lcd.setCursor(0, row);
lcd.print(chosen && !active ? '>' : ' ');
return 1;
});
menu.onBuild([](gm::Builder& b) {
if(!isWork && !OVH_ERROR) { b.Button("Run" , []() {if(temperature<cfg.temp){ lcd.clear(); isMenu=false; isWork=true;}}); } else {
b.Button("Stop" , []() {OUT1_OFF; OUT2_OFF; lcd.clear(); isMenu=false; isWork=false;});
}
b.Switch("Buzzer", &cfg.OVH, [](bool v) { Serial.println(v); });
// b.ValueStr("ValueStr", "foo");
// b.Label("Some line");
b.Select("Mode", &cfg.mode,"Low;High;Auto", [](uint8_t n, const char* str, uint8_t len) { Serial.print(n); Serial.print("-"); Serial.write(str, len); });
b.ValueInt<int>("Temp", &cfg.temp, 0, 90, 10, DEC, "C", [](int v) { Serial.println(v); });
b.ValueInt<int>("dT", &cfg.dt, 0, 5, 1, DEC, "C", [](int v) { Serial.println(v); });
// b.ValueFloat("ValueFloat", &valf, -5, 5, 0.25, 3, "mm", [](float v) { Serial.println(v); });
b.Button("Save", []() { EEPROM.put(1,cfg); menu.home(); });
b.Button("Reset", []() { cfg.OVH=true; cfg.mode=AUTO_HEAT; cfg.temp=30; cfg.dt=2; EEPROM.put(1,cfg); menu.home(); });
b.Button("Exit", []() { isMenu=false; lcd.clear(); });
});
// menu.refresh();
}
void loop() {
{ // Опрос кнопок
int analog=analogRead(KEYB);
butt[BUT_OK].tick(analog < 800 && analog > 600);
butt[BUT_RIGHT].tick(analog < 600 && analog > 400);
butt[BUT_DOWN].tick(analog < 400 && analog > 200);
butt[BUT_UP].tick(analog < 200 && analog > 100);
butt[BUT_LEFT].tick(analog < 100 && analog > 0);
}
//Вывод температуры
if(!isMenu){
if(detectTemperature()) {
lcd.setCursor(0,0);
lcd.print("Температура");
lcd.setCursor(12,0);
lcd.print(temperature);
}
if(isWork && !OVH_ERROR) {
LGRN_ON;
lcd.setCursor(0,1);
switch (cfg.mode) {
case ONE_HEAT:
lcd.print("Нагрев T1 > "); lcd.print(cfg.temp);
OUT1_ON;
OUT2_OFF;
break;
case TWO_HEAT:
lcd.print("Нагрев T2 > "); lcd.print(cfg.temp);
OUT1_ON;
OUT2_ON;
break;
case AUTO_HEAT:
lcd.print("Нагрев авто > "); lcd.print(cfg.temp);
if(temperature < cfg.temp/2 ){
OUT1_ON;
OUT2_ON;
} else {
OUT1_ON;
OUT2_OFF;
}
break;
default:
break;
}
if(temperature > cfg.temp) {isWork=false;}
} else {
LGRN_OFF;
lcd.setCursor(0,1);
lcd.print("Нагрев выкл."); if(OVH_ERROR)lcd.print("-OVH");
OUT1_OFF;
OUT2_OFF;
}
}
// Навигация по меню
if (butt[BUT_OK].isClick()) {if (!isMenu) {menu.refresh(); isMenu=true;} else {menu.set();}}
if (butt[BUT_UP].isClick() && isMenu) menu.up();
if (butt[BUT_DOWN].isClick() && isMenu) menu.down();
if (butt[BUT_LEFT].isClick() && isMenu) menu.left();
if (butt[BUT_RIGHT].isClick() && isMenu) menu.right();
// Проверка на сработку датчика перегрева
if((millis()-timer_overhert) > OTHERHEAT_TIME) {
// OVH_ERROR=true;
}
}
bool detectTemperature(){
static int last_temp;
int temp;
byte data[2];
ds.reset();
ds.write(0xCC);
ds.write(0x44);
if (millis() - lastUpdateTime > TEMP_UPDATE_TIME)
{
lastUpdateTime = millis();
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
data[0] = ds.read();
data[1] = ds.read();
//Формируем значение
temp = (data[1] << 8) + data[0]; temp = temp >> 4;
if (abs(temp-last_temp)>cfg.dt) {
last_temp=temp;
temperature=temp;
}
return true;
}
return false;
}
//Мигание светодиодами
void flash(void) {
static bool lred=false;
if(OVH_ERROR){
lred=!lred;
if(cfg.OVH) lred ? T_ALERT: T_NO;
digitalWrite(LED_RED,lred);
} else {
LRED_OFF;
T_NO;
}
}