TempRelay/TempRelay.ino

184 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <microDS18B20.h> // Датчик температуры
#include <avr/wdt.h> // WatchDog для сброса в случае зависания
// Отладка вывода
#define DEBUG 1
// Отладка ввода температуры
#define DEBUG_INPUT 0
// Пин датчика температуры
#define PIN_SENSOR 2
// Пин управления реле
#define PIN_RELAY 5
MicroDS18B20<PIN_SENSOR> 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 для продолжения работы
}