#include <avr/wdt.h>
#include <EEPROM.h> //работа с памятью
#include "DHT.h" //подключаем библиотеку
#include <math.h> // для оператора isnan
#include <TimerOne.h>
//
#include <LiquidCrystal_I2C.h> // Подключаем библиотеку для работы с дисплеем по I2C
#define DHTPIN 4 // контакт, к которому подключаемся
const int ledPin = 13; // назначаем контакт к которому подключаемся
const int buzz = 12; //пищалка
const int RelayPin = 7;
#define BUTTON1 3 // номер пина кнопки
#define BUTTON2 2 // номер пина кнопки
#define INIT_ADDR 1023 // номер резервной ячейки
#define INIT_KEY 0 // ключ первого запуска. 0
bool btn = true;
// расскомментировать строчку датчика:
//#define //DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
int address = 0;
bool hasWritten = false; // Переменная для отслеживания, было ли выполнено записывание
volatile bool isErrTemp = false;
bool buttonPressed;
volatile float SetTemp = 0.0;
volatile bool intFlagUP = false;
volatile bool intFlagDOWN = false;
DHT dht(DHTPIN, DHTTYPE); // инициализируем датчик DHT
float ReadTemp(); // описание функции
volatile float t; // глобальная переменная
unsigned long timing; // Переменная для хранения точки отсчета
LiquidCrystal_I2C lcd(0x27, 16, 2);
//bool btn ;
int notes[] = {
1046, 784, 659, 880, 987, 932, 880, 784,
1318, 1568, 1750, 1396, 1568, 1318, 1046, 1174, 987,
1046, 784, 659, 880, 987, 932, 880,
784, 1318, 1568, 1750, 1396, 1568, 1318, 1046, 1174, 987,
1568, 1480, 1396, 1244, 1318, 830, 880, 1046, 880, 1046, 1174,
0, 1568, 1480, 1396, 1244, 1318, 2093, 2093, 2093,
1568, 1480, 1396, 1244, 1318, 830, 880, 1046, 880, 1046, 1174, 1244, 1174, 1046,
};
int times[] = {
450, 150, 300, 300, 150, 150, 300, 210,
210, 150, 300, 150, 150, 300, 150, 150, 450,
450, 150, 300, 300, 150, 150, 300,
210, 210, 150, 300, 150, 150, 300, 150, 150, 450,
150, 150, 150, 300, 150, 150, 150, 150, 150, 150, 150,
0, 150, 150, 150, 300, 150, 300, 150, 600,
150, 150, 150, 300, 150, 150, 150, 150, 150, 150, 150, 300, 450, 600,
};
int delays[] = {
450, 450, 450, 300, 300, 150, 300, 210,
210, 150, 300, 150, 300, 300, 150, 150, 450,
450, 450, 450, 300, 300, 150, 300,
210, 210, 150, 300, 150, 300, 300, 150, 150, 600,
150, 150, 150, 300, 300, 150, 150, 300, 150, 150, 150,
300, 150, 150, 150, 300, 300, 300, 150, 600,
150, 150, 150, 300, 300, 150, 150, 300, 150, 150, 450, 450, 450, 1200,
};
void setup() {
if (EEPROM.read(INIT_ADDR) != INIT_KEY) { // первый запуск
EEPROM.write(INIT_ADDR, INIT_KEY); // записали ключ
// записали стандартное значение темп SetTemp = 0.0
EEPROM.put(address, SetTemp);
}
EEPROM.get(address, SetTemp);
noTone(buzz);
LCD_setup();
Timer1.initialize(300000);
Timer1.attachInterrupt(calback);
pinMode(RelayPin, OUTPUT); //назначаем контакт на выход реле
pinMode(BUTTON2, INPUT); // кнопка пина на вход
pinMode(BUTTON1, INPUT); // кнопка пина на вход
pinMode(ledPin, OUTPUT); //назначаем контакт на выход
pinMode(buzz, OUTPUT);
//noInterrupts();
attachInterrupt(digitalPinToInterrupt(BUTTON1), FlagTempUP, RISING); // прерывание по кнопки 1 (изменение Т UP)
attachInterrupt(digitalPinToInterrupt(BUTTON2), FlagTempDOWN, RISING); //прерывание по кнопки 1(изменение Т DOWN)
// interrupts();
Serial.begin(9600);
dht.begin();
wdt_enable(WDTO_2S);
}
uint32_t ms, ms1 = 0;
void loop() {
wdt_reset();
float temp = ReadTemp();
isErrTemp = isnan(temp);
// EEPROM.get(address,SetTemp);
if (isErrTemp) {
setErrTempLcd();
DHTTemperatureError();
delay(1000);
temp = dht.readTemperature();
} else {
// !isErrTemp;
handleButtonPress();
SetLcdTemp();
TempUP();
TempDOWN();
TemperatureControlON(temp);
//WrEEprom();
//asm volatile ("jmp 0");
}
return temp ;
}
void calback() {
if (digitalRead(RelayPin) == HIGH) {
digitalWrite(ledPin, !digitalRead(ledPin));
}
}
float ReadTemp() // считывание данных температуры
{
//float f_rounded = round( t * 10) / 10.0;
// return f_rounded ;
//delay(1000);
return dht.readTemperature(); // температура в Цельсиях , считывает и возвращает температуру
}
//}
void FlagTempUP() {
static unsigned long millis_prev;
if (millis() - 60 > millis_prev)
intFlagUP = true;
millis_prev = millis();
}
void FlagTempDOWN() {
static unsigned long millis_prev;
if (millis() - 60 > millis_prev)
intFlagDOWN = true; // сбрасываемgDOWN = true;
millis_prev = millis();
}
bool TempUP() {
if ((intFlagUP) && (digitalRead(BUTTON1) == HIGH)) {
intFlagUP = false; // сбрасываем
SetTemp = SetTemp + 0.5; // увеличиваем температуру на 0.5 градус
SetTemp = constrain(SetTemp, -50.0, 50.0); //огранчиваем установку темературы от 0 до -50
tone(buzz, 493, 20);
return true;
// EEPROM.put(address, SetTemp);
}
}
bool TempDOWN() {
if ((intFlagDOWN) && (digitalRead(BUTTON2) == HIGH)) {
intFlagDOWN = false;
SetTemp = SetTemp - 0.5; // уменьшили температуру на 0.5 градус
SetTemp = constrain(SetTemp, -50.0, 50.0);
tone(buzz, 262, 20);
return true ;
// Serial.println("Уменьшили температуру");
// EEPROM.put(address, SetTemp); //Запись в EEPROM
}
}
void LCD_setup() {
lcd.clear();
lcd.init();
// Включаем подсветку
lcd.backlight();
// Устанавливаем положение курсора, 2-й столбец, 0-я строка
lcd.setCursor(2, 0);
// Выводим текст
lcd.print("Dachnik v1.0");
lcdBacklightINI();
lcd.setCursor(0, 1);
lcd.print("Made for Natalia");
delay(4000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("OutTemp");
lcd.setCursor(1, 1);
lcd.print("TempON");
}
void SetLcdTemp() {
float temp = ReadTemp(); // Считываем один раз
lcd.setCursor(9, 0);
lcd.print(temp, 1);
if (temp < (-9))
lcd.setCursor(14, 0);
lcd.print("C");
lcd.write(223);
lcd.print(" ");
//float f_rounded = round( SetTemp * 10) / 10.0;
lcd.setCursor(9, 1);
lcd.print(SetTemp, 1);
if (SetTemp < (-9.50))
lcd.setCursor(14, 1);
// lcd.print("");
lcd.print("C");
lcd.write(223);
lcd.print(" ");
}
void handleButtonPress() {
buttonPressed = digitalRead(BUTTON1) == LOW && digitalRead(BUTTON2) == LOW ;
if (buttonPressed) {
if (millis() - timing > 10000) {
btn = false;
lcd.noBacklight();
WrEEprom() ;
}
} else if (!btn) {
timing = millis();
lcd.backlight();
btn = true;
hasWritten = false;
}
}
//hasWritten = false; // Переменная для отслеживания, было ли выполнено записывание
void WrEEprom() {
bool statewrite = TempUP() || TempDOWN() ;
if (statewrite && !hasWritten) { // Проверка условий и того, выполнена ли запись ранее
timing = millis();
EEPROM.put(address, SetTemp);
Serial.print(" Запись в EEPROM ");
hasWritten = true; // Установка флага, что запись была выполнена
}
}
void DHTTemperatureError() {
uint32_t delayTime = 500; // Время задержки между миганиями (мс)
bool isVisible = true; // Флаг для определения видимости строки
lcd.backlight();
lcd.setCursor(9, 0); // Устанавливаем курсор на первую строку
lcd.print("Error");
//tone(buzz, 200,300);
delay(delayTime); // Задержка перед изменением видимости строки
tone(buzz, 462,150);
// Если строка была видимой, скрываем её, иначе - показываем
if (isVisible) {
lcd.setCursor(9, 0); // Устанавливаем курсор на первую строку
lcd.print(" "); // Заполняем строку пробелами для очистки
} else {
lcd.setCursor(9, 0);
lcd.print("Error");
}
isVisible = !isVisible; // Меняем состояние флага
}
void TemperatureControlON(float temp) {
float currentTemp = ReadTemp(); // Сохраняем текущее значение температуры
// Проверяем условия для включения реле
if ((currentTemp < 0 && SetTemp < 0 && currentTemp < SetTemp) || (currentTemp > 0 && SetTemp > 0 && currentTemp > SetTemp))
digitalWrite(RelayPin, HIGH); // Включаем реле
else {
digitalWrite(RelayPin, LOW);
digitalWrite(ledPin, LOW);
}
}
void lcdBacklightINI()
{
for (int i = 0; i < 68; i++){
tone(buzz, notes[i], times[i]);
delay(delays[i]);
lcd.noBacklight();
int b = times[i]/6;
delay(b);
lcd.backlight();
wdt_reset();
}
noTone(buzz);
}
void setErrTempLcd()
{
lcd.setCursor(9, 1);
lcd.print(SetTemp, 1);
if (SetTemp < (-9.50))
lcd.setCursor(14, 1);
// lcd.print("");
lcd.print("C");
lcd.write(223);
lcd.print(" ");
}