#include // Датчик температуры #include // WatchDog для сброса в случае зависания // Отладка вывода #define DEBUG 1 // Отладка ввода температуры #define DEBUG_INPUT 0 // Пин датчика температуры #define PIN_SENSOR 2 // Пин управления реле #define PIN_RELAY 5 MicroDS18B20 sensor; // датчик на пине D2 // Лимит таймаутов #define MAX_TIMEOUTS 10 // Структура для хранения данных о температуре и таймаутах struct { float temp; uint32_t openTime; uint32_t closeTime; } 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}; // Макрос для удобства записи таймаута в секундах (переводит в мс) #define SEC_TO_MSEC(time) (long)time*1000 void setup() { // Для отладочной печати #if DEBUG == 1 Serial.begin(9600); #endif // DEBUG // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // НИЖЕ РЕГИСТРИРУЕТСЯ ВРЕМЯ И ТАЙМАУТЫ ОТКРЫТИЯ/ЗАКРЫТИЯ РЕЛЕ // // ЗНАЧЕНИЯ ДОЛЖНЫ БЫТЬ ОТСОРТИРОВАНЫ ПО ВОЗРАСТАНИЮ ТЕМПЕРАТУРЫ // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // REGISTER_TIMEOUT(83, 300, SEC_TO_MSEC(150)); 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)); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // ВЫШЕ РЕГИСТРИРУЕТСЯ ВРЕМЯ И ТАЙМАУТЫ ОТКРЫТИЯ/ЗАКРЫТИЯ РЕЛЕ // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Проверка что не было зарегистрировано больше данных, чем это возможно if (timeouts_count >= MAX_TIMEOUTS) { #if DEBUG == 1 Serial.println("TIMEOUTS LIMIT REACHED ! ! !"); #endif // DEBUG while(1); // Программа не запуститься дальше, если допущена ошибка } // Настройка реле pinMode(PIN_RELAY, OUTPUT); // Объявляем пин реле как выход digitalWrite(PIN_RELAY, LOW); // Выключаем реле - посылаем сигнал 0 // запрашиваем новое измерение с датчика sensor.requestTemp(); wdt_enable(WDTO_4S); // Включаем HARD_RESET с таймером на 4с } uint32_t tmr; // Для таймера опроса датчика uint32_t lastRelayTime = 0; // Для управления реле float currentTemp; // Текущая температура void loop() { int relayState; // Значение реле на текущий момент int i; // Счетчик для цикла перебора температур uint32_t current_time = millis(); // Текущее время #if DEBUG_INPUT == 1 byte n = Serial.available(); if (n == 0) { currentTemp = Serial.parseFloat(); } #endif // DEBUG_INPUT // конструкция программного таймера на 800 мс if (current_time - tmr >= 800) { // Обновляем переменную для таймера опроса датчика tmr = current_time; // читаем прошлое значение if (sensor.readTemp()) { #if DEBUG_INPUT == 0 currentTemp = sensor.getTemp(); #endif // DEBUG_INPUT } #if DEBUG == 1 else Serial.println("sensor.readTemp error"); #endif // DEBUG // запрашиваем новое измерение sensor.requestTemp(); } // Подбор подходящих таймаутов по текущей температуре for (i = 0; i < timeouts_count; i++) { // Если обнаружили пороговое значение, которое больше текущей температуры - берем предыдущее и прерываем поиск if (timeouts[i].temp > currentTemp) { i--; break; } } // Если перебрали все пороги и температура выше - берем последний if (i == timeouts_count) i--; 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 if (0 <= i) { #if DEBUG == 1 Serial.print(" openTime: "); Serial.print(timeouts[i].openTime); Serial.print(" closeTime: "); Serial.print(timeouts[i].closeTime); #endif // DEBUG // Если время открытия ещё не истекло, то открываем реле if (current_time < lastRelayTime + timeouts[i].openTime) { relayState = HIGH; } else // иначе, // Если время привышает время закрытия, то необходимо сбросить время управления реле if (current_time > lastRelayTime + timeouts[i].openTime + timeouts[i].closeTime || !lastRelayTime) { lastRelayTime = current_time; } } else // иначе, выключить реле { relayState = LOW; // Считаем что если не попали во время открытия, то реле надо закрыть lastRelayTime = 0; } #if DEBUG == 1 Serial.println(""); #endif // DEBUG digitalWrite(PIN_RELAY, relayState); // Изменяем значение сигнала на пине для управление реле wdt_reset(); // Сброс WatchDog для продолжения работы }