2022-10-07 06:28:04 +00:00
|
|
|
|
#include <microDS18B20.h> // Датчик температуры
|
2022-10-07 06:28:17 +00:00
|
|
|
|
#include <avr/wdt.h> // WatchDog для сброса в случае зависания
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
|
|
|
|
// Отладка вывода
|
|
|
|
|
#define DEBUG 1
|
2022-10-07 06:28:04 +00:00
|
|
|
|
// Отладка ввода температуры
|
|
|
|
|
#define DEBUG_INPUT 0
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
|
|
|
|
// Пин датчика температуры
|
|
|
|
|
#define PIN_SENSOR 2
|
|
|
|
|
// Пин управления реле
|
|
|
|
|
#define PIN_RELAY 5
|
|
|
|
|
|
|
|
|
|
MicroDS18B20<PIN_SENSOR> sensor; // датчик на пине D2
|
|
|
|
|
|
|
|
|
|
// Лимит таймаутов
|
|
|
|
|
#define MAX_TIMEOUTS 10
|
|
|
|
|
|
|
|
|
|
// Структура для хранения данных о температуре и таймаутах
|
2022-10-07 06:41:55 +00:00
|
|
|
|
struct TIMEOUT_DATA
|
2022-10-03 13:46:22 +00:00
|
|
|
|
{
|
|
|
|
|
float temp;
|
2022-10-07 06:28:04 +00:00
|
|
|
|
uint32_t openTime;
|
|
|
|
|
uint32_t closeTime;
|
2022-10-03 13:46:22 +00:00
|
|
|
|
} timeouts[MAX_TIMEOUTS];
|
|
|
|
|
|
|
|
|
|
int timeouts_count = 0; // Общее количество зарегистрированных данных о тем-ре и таймаутах
|
|
|
|
|
|
|
|
|
|
// Макрос для регистрации данных о тем-ре и таймаутах (тем-ра в градусах цельсия, время открытия и закрытия в миллисекундах)
|
|
|
|
|
#define REGISTER_TIMEOUT(temp_C, openTime_ms, closeTime_ms) timeouts[timeouts_count++] = {temp_C, openTime_ms, closeTime_ms};
|
|
|
|
|
|
|
|
|
|
// Макрос для удобства записи таймаута в секундах (переводит в мс)
|
2022-10-07 06:28:04 +00:00
|
|
|
|
#define SEC_TO_MSEC(time) (long)time*1000
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
2022-10-07 06:41:55 +00:00
|
|
|
|
// функция сравнения элементов для qsort по возрастанию
|
|
|
|
|
int qsort_compare(const void *cmp1, const void *cmp2)
|
|
|
|
|
{
|
|
|
|
|
// Указатели для простоты работы
|
|
|
|
|
struct TIMEOUT_DATA *a = (struct TIMEOUT_DATA *)cmp1;
|
|
|
|
|
struct TIMEOUT_DATA *b = (struct TIMEOUT_DATA *)cmp2;
|
|
|
|
|
// если значение отрицательное, то a < b, если положительное, то a > b, иначе равны
|
|
|
|
|
return a->temp - b->temp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 13:46:22 +00:00
|
|
|
|
void setup()
|
|
|
|
|
{
|
|
|
|
|
// Для отладочной печати
|
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
Serial.begin(9600);
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-10-07 08:48:33 +00:00
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
|
|
|
// НИЖЕ РЕГИСТРИРУЕТСЯ ТЕМПЕРАТУРА И ТАЙМАУТЫ ОТКРЫТИЯ/ЗАКРЫТИЯ РЕЛЕ //
|
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
|
|
|
|
REGISTER_TIMEOUT(83, 300, SEC_TO_MSEC(150));
|
2022-10-03 13:54:57 +00:00
|
|
|
|
REGISTER_TIMEOUT(85, 300, SEC_TO_MSEC(120));
|
|
|
|
|
REGISTER_TIMEOUT(88, 300, SEC_TO_MSEC(90));
|
|
|
|
|
REGISTER_TIMEOUT(89, 300, SEC_TO_MSEC(70));
|
|
|
|
|
REGISTER_TIMEOUT(90, 300, SEC_TO_MSEC(50));
|
|
|
|
|
REGISTER_TIMEOUT(91, 300, SEC_TO_MSEC(40));
|
|
|
|
|
REGISTER_TIMEOUT(92, 300, SEC_TO_MSEC(35));
|
|
|
|
|
REGISTER_TIMEOUT(93, 300, SEC_TO_MSEC(30));
|
|
|
|
|
REGISTER_TIMEOUT(94, 300, SEC_TO_MSEC(25));
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
2022-10-07 08:48:33 +00:00
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
|
|
|
|
// ВЫШЕ РЕГИСТРИРУЕТСЯ ТЕМПЕРАТУРА И ТАЙМАУТЫ ОТКРЫТИЯ/ЗАКРЫТИЯ РЕЛЕ //
|
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
|
|
|
|
// Проверка что не было зарегистрировано больше данных, чем это возможно
|
2022-10-07 08:41:06 +00:00
|
|
|
|
if (timeouts_count > MAX_TIMEOUTS)
|
2022-10-03 13:46:22 +00:00
|
|
|
|
{
|
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
Serial.println("TIMEOUTS LIMIT REACHED ! ! !");
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
while(1); // Программа не запуститься дальше, если допущена ошибка
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 06:41:55 +00:00
|
|
|
|
// Сортировка массива по времени, критично для алгоритма
|
|
|
|
|
qsort(timeouts, timeouts_count, sizeof(timeouts[0]), qsort_compare);
|
|
|
|
|
|
2022-10-03 13:46:22 +00:00
|
|
|
|
// Настройка реле
|
|
|
|
|
pinMode(PIN_RELAY, OUTPUT); // Объявляем пин реле как выход
|
|
|
|
|
digitalWrite(PIN_RELAY, LOW); // Выключаем реле - посылаем сигнал 0
|
2022-10-07 06:28:04 +00:00
|
|
|
|
|
|
|
|
|
// запрашиваем новое измерение с датчика
|
|
|
|
|
sensor.requestTemp();
|
|
|
|
|
|
2022-10-07 06:28:17 +00:00
|
|
|
|
wdt_enable(WDTO_4S); // Включаем HARD_RESET с таймером на 4с
|
2022-10-03 13:46:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 06:28:04 +00:00
|
|
|
|
uint32_t tmr; // Для таймера опроса датчика
|
|
|
|
|
uint32_t lastRelayTime = 0; // Для управления реле
|
|
|
|
|
float currentTemp; // Текущая температура
|
|
|
|
|
|
2022-10-03 13:46:22 +00:00
|
|
|
|
void loop()
|
|
|
|
|
{
|
|
|
|
|
int relayState; // Значение реле на текущий момент
|
|
|
|
|
int i; // Счетчик для цикла перебора температур
|
|
|
|
|
uint32_t current_time = millis(); // Текущее время
|
2022-10-07 06:28:04 +00:00
|
|
|
|
|
|
|
|
|
#if DEBUG_INPUT == 1
|
|
|
|
|
byte n = Serial.available();
|
|
|
|
|
if (n == 0)
|
|
|
|
|
{
|
|
|
|
|
currentTemp = Serial.parseFloat();
|
|
|
|
|
}
|
|
|
|
|
#endif // DEBUG_INPUT
|
|
|
|
|
// конструкция программного таймера на 800 мс
|
|
|
|
|
if (current_time - tmr >= 800)
|
2022-10-03 13:46:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Обновляем переменную для таймера опроса датчика
|
|
|
|
|
tmr = current_time;
|
|
|
|
|
// читаем прошлое значение
|
|
|
|
|
if (sensor.readTemp())
|
|
|
|
|
{
|
2022-10-07 06:28:04 +00:00
|
|
|
|
#if DEBUG_INPUT == 0
|
2022-10-03 13:46:22 +00:00
|
|
|
|
currentTemp = sensor.getTemp();
|
|
|
|
|
#endif // DEBUG_INPUT
|
|
|
|
|
}
|
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
else
|
2022-10-07 06:28:04 +00:00
|
|
|
|
Serial.println("sensor.readTemp error");
|
2022-10-03 13:46:22 +00:00
|
|
|
|
#endif // DEBUG
|
|
|
|
|
// запрашиваем новое измерение
|
|
|
|
|
sensor.requestTemp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Подбор подходящих таймаутов по текущей температуре
|
|
|
|
|
for (i = 0; i < timeouts_count; i++)
|
|
|
|
|
{
|
|
|
|
|
// Если обнаружили пороговое значение, которое больше текущей температуры - берем предыдущее и прерываем поиск
|
|
|
|
|
if (timeouts[i].temp > currentTemp)
|
|
|
|
|
{
|
|
|
|
|
i--;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Если перебрали все пороги и температура выше - берем последний
|
|
|
|
|
if (i == timeouts_count)
|
|
|
|
|
i--;
|
|
|
|
|
|
2022-10-07 06:28:04 +00:00
|
|
|
|
relayState = LOW; // Считаем что если не попали во время открытия, то реле надо закрыть
|
|
|
|
|
// Если значение индекса параметров таймаута для данной температуры неотрицательное, значит нужно произвести работу с реле на текущей
|
|
|
|
|
|
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
Serial.print("Temp: ");
|
|
|
|
|
Serial.print(currentTemp);
|
|
|
|
|
Serial.print(" Time: ");
|
|
|
|
|
Serial.print(current_time);
|
|
|
|
|
Serial.print(" Relay: ");
|
|
|
|
|
Serial.print(lastRelayTime);
|
|
|
|
|
Serial.print(" index: ");
|
|
|
|
|
Serial.print(i);
|
|
|
|
|
#endif // DEBUG
|
2022-10-03 13:46:22 +00:00
|
|
|
|
if (0 <= i)
|
|
|
|
|
{
|
2022-10-07 06:28:04 +00:00
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
Serial.print(" openTime: ");
|
|
|
|
|
Serial.print(timeouts[i].openTime);
|
|
|
|
|
Serial.print(" closeTime: ");
|
|
|
|
|
Serial.print(timeouts[i].closeTime);
|
|
|
|
|
#endif // DEBUG
|
2022-10-03 13:46:22 +00:00
|
|
|
|
// Если время открытия ещё не истекло, то открываем реле
|
|
|
|
|
if (current_time < lastRelayTime + timeouts[i].openTime)
|
|
|
|
|
{
|
|
|
|
|
relayState = HIGH;
|
|
|
|
|
}
|
|
|
|
|
else // иначе,
|
|
|
|
|
// Если время привышает время закрытия, то необходимо сбросить время управления реле
|
2022-10-07 06:28:04 +00:00
|
|
|
|
if (current_time > lastRelayTime + timeouts[i].openTime + timeouts[i].closeTime
|
|
|
|
|
|| !lastRelayTime)
|
2022-10-03 13:46:22 +00:00
|
|
|
|
{
|
|
|
|
|
lastRelayTime = current_time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // иначе, выключить реле
|
2022-10-07 06:28:04 +00:00
|
|
|
|
{
|
2022-10-03 13:46:22 +00:00
|
|
|
|
relayState = LOW; // Считаем что если не попали во время открытия, то реле надо закрыть
|
2022-10-07 06:28:04 +00:00
|
|
|
|
lastRelayTime = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DEBUG == 1
|
|
|
|
|
Serial.println("");
|
|
|
|
|
#endif // DEBUG
|
2022-10-03 13:46:22 +00:00
|
|
|
|
|
|
|
|
|
digitalWrite(PIN_RELAY, relayState); // Изменяем значение сигнала на пине для управление реле
|
2022-10-07 06:28:04 +00:00
|
|
|
|
|
2022-10-07 06:28:17 +00:00
|
|
|
|
wdt_reset(); // Сброс WatchDog для продолжения работы
|
2022-10-03 13:46:22 +00:00
|
|
|
|
}
|