Термошкаф и контроллер температуры на базе Arduino nano
- Войдите на сайт для отправки комментариев
Решил поделиться наработками.... и получить ХОРОШИЕ советы...
Поступил тут мне небольшой заказ (для товарища, т.е., бесплатно) на контроллер температуры в шкафу на балконе (там человек хранит всякие закатки/варенья/соленья и т.п.) До недавнего времени он использовал в качестве контроллера терморегулятор от холодильника. конструкция выглядела примерно так:
Щкаф разделен на два несвязанных отсека. В каждом отсеке установлен "нагреватель+вентилятор". Причем разведенная проводка подразумевает одновременное включение нагревателей. Нагреватель - это обычные лампочки на 220 вольт, а вентиляторы - от БП на 12 вольт.
Сразу мне показалось как-то простовато все. Ставим два термодатчика (терморезисторы), переменный резистор для установки температуры, реле с обвязкой и полевик для управления вентиляторами.
Достаточно быстро все было размещено в корпус
Провод с терморезисторами выносной, клеммники для подключения нагревателя, входного напряжения и вентиляторов. Три светодиода - индикаторы состояния и сетевой блок питания 220-> 12 Вольт.
Все проверено, реле включается, вентилятор включается, есть некие показания от терморезисторов.
Мой первоначальный план написания скетча выглядел достаточно просто...
Типа такого алгоритма:
1) проверяем датчики температуры Один раз в секунду. И выбираем минимальное значение (в разных отсеках шкафа может быть разная)
Если с датчиком что-то не так (не подключен, в обрыве и ли еще что-то) ставим код ошибки (1 - первый датчик не работает, 2 - второй не работает, 3- оба датчика не работают)
2) если минимальное значение температуры меньше некого установленного пользователем (с помощью переменника) и код ошибки не равен 3, включаем подогрев и запоминаем запоминаем температуру с которого начинается нагрев.
Чтобы реле не колбасилось (на граничном значении) греем пока минимальная температура с датчиков не станет выше установленной на несколько (допустим 7-10) градусов.
3) Если нагрев произошел - выключаем подогреватели, но оставляем на некоторое время работать вентиляторы...
4) если нагрев не произошел за некое установленное время - ставим код ошибки 4 (проблема с нагревателем).
Попутно, между делом сигналим светодиодом о наличии ошибки (вспышками, количество которых равно коду ошибки)
Получился такой вот код:
/* Терморегулятор на базе Ардуино нано концепция вер 3. Кратко. 31-10-2015 Даже описывать нечего. Есть процедура получения температуры с датчиков. Минимальная из них, но не =0 Если минимальное значение ниже некого установленного пользователем предела, включаем нагрев и греем пока не будет достигнута некая установленная планка относительно установленной температуры после этого еще немного работает вентилятор, "для утряски" =================================== термодатчики по 10 кОм Таблица значений: T -> ADC Middle =======|==========|========== 4 С -> 274 7 С -> 332..345 338 12 С -> 355..367 361 14 С -> 372..386 379 21 С -> 443..457 450 22 С -> 458..477 467 24 С -> 513..526 519 */ //отладочный вывод в ком-порт #define debug 1 //======== Определение пинов ========= #define relePin 12 #define ledRele 10 #define fanPin 11 #define ledFan 14 #define ledPower 3 #define t1Pin A1 #define t2Pin A2 #define adjPin A3 //интервал времени, если в течении которого не произошел нагрев датчика, то выдаем код ошибки 4 #define timeWorkTen 10000 long int startWorkTen = 0; //переменная содержит значение времени включения ТЭНа //Предопределяем интервал времени включения вентилятора #define timeWorkFan 5000 long int startWorkFan=0; //переменная содержит значение времени включения FAN long int timeReadTemperature = 0; //переменная содержит значение времени для считывания температуры //Предопределяем интервал времени считывания значения температуры 1 раз в секунду #define interval_read_temp 1000 // константы температурных диапазонов для регулировки #define min_set_temp 270 #define max_set_temp 350 // довесок ПЛЮС к температуре установленной пользователем до которого греем #define set_delta_temp 10 boolean releStatus = 0; //текущий статус реле boolean fanStatus = 0; //текущий статус вентилятора unsigned int heatStartTemp; //значение температуры ДО включения нагревателя unsigned int d_min_temp; // глобальная переменная "min температуры" unsigned int userSetTemp; // установленное пользователем (Алексом) значение температуры, которого следует держаться volatile byte errorCode = 0; //Код ошибки (1 - Первый датчик-Х, 2- 2-ой датчик -Х, 3 - оба датчика - Х, 4- нагреватель - Х) volatile long int changeTime = 0; //глобальная переменная следующего вызова процедуры отображения ошибки светодиодом #define pauseFlash 400 // пауза для красивого вывода кода ошибки // выполняется только при старте программы void setup() { #if debug Serial.begin(9600); #endif // инициализация пинов pinMode(relePin, OUTPUT); pinMode(ledRele, OUTPUT); pinMode(fanPin, OUTPUT); pinMode(ledFan, OUTPUT); pinMode(ledPower, OUTPUT); releOff(); fanOff(); changeTime = millis(); d_min_temp = get_min_temp(); // сразу делаем замер значений температуры, что бы понимать ГДЕ МЫ } //============================= // Основной цикл программы void loop() { if ((millis() - timeReadTemperature) >= interval_read_temp) // делаем замер температуры через некие интервалы времени { d_min_temp = get_min_temp(); #if debug Serial.print("Min_temperature: "); Serial.println(d_min_temp); Serial.print(" Set temp= "); Serial.println(userSetTemp); Serial.print(" errorCode= "); Serial.println(errorCode); Serial.print("heatStartTemp "); Serial.println(heatStartTemp); Serial.println("============="); #endif } //============= // если есть ошибки, то нужно сигнализировать об этом //errorCode=0; if (millis() >= changeTime) showError(errorCode); //если есть ошибки и наступило время для след. этапа отображения ошибки //============== // считываем значение с переменника и пересчитываем его в заданный диапазон userSetTemp = map(analogRead(adjPin), 0, 1023, min_set_temp, max_set_temp); // userSetTemp = 560; //============ // если миним. температура с датчиков ниже заданной и подогрев не включен и есть РЕАЛЬНЫЕ показания с датчиков, включаем подогрев if ((d_min_temp < userSetTemp) && (!releStatus) && (errorCode != 3)) { heatStartTemp = d_min_temp; //запоминаем температуру с которой стартовали if (errorCode = 4) errorCode = 0; fanOn(); releOn(); startWorkTen = millis(); // запоминаем время старта #if debug Serial.print("-------- Start HEAT. Time "); Serial.println(startWorkTen); #endif } //================== //выключаем если нагрели if ((releStatus) && (d_min_temp > (userSetTemp + set_delta_temp))) { releOff(); //fanOff(); startWorkFan=millis(); #if debug Serial.println("-------- Stop HEAT."); #endif } //================== //анализ ошибки нагревателя // если ТЭН включен, а температура осталась такой же (или еще хуже уменьшилась) в течении заданного промежутка времени // значит ТЭН не работает if ((releStatus) && (d_min_temp <= heatStartTemp) && (millis() - startWorkTen > timeWorkTen)) { errorCode = 4; } //============ //Если был включен ТОЛЬКО вентилятор (без реле) и он отработал нужный интервал времени - выключаем его if ((fanStatus) and (!releStatus) and ((millis()-startWorkFan)>=timeWorkFan)) { fanOff(); #if debug Serial.println("----------- Stop Fan."); #endif } } //end main loop //=============================== void releOn() //включение реле { digitalWrite (relePin, HIGH); digitalWrite (ledRele, HIGH); releStatus = true; } void releOff()//выключение реле { digitalWrite (relePin, LOW); digitalWrite (ledRele, LOW); releStatus = false; } void fanOn() //включение вентилятора { digitalWrite (fanPin, HIGH); digitalWrite (ledFan, HIGH); fanStatus = true; } void fanOff()//выключение вентилятора { digitalWrite (fanPin, LOW); digitalWrite (ledFan, LOW); fanStatus = false; } //=================== // Процедура получения значения температуры с датчиков // возвращаем только минимальное значение датчика // и тут же происходит определение ошибок (коды:1..3) int get_min_temp() { unsigned int t1, t2; t1 = readTemp(t1Pin); //читаем значение с первого датчика t2 = readTemp(t2Pin); timeReadTemperature = millis(); // if (errorCode < 4) errorCode = 0; //если не проблема с нагревателем, то пока ставим код ошибки 0, а далее посмотрим /* #if debug Serial.print("D1:"); Serial.println(t1); Serial.print("D2:"); Serial.println(t2); #endif */ if ((t1 == 0) and (t2 != 0)) //если РАБОТАЕТ только второй датчик { errorCode = 1; return t2; } if ((t1 != 0) and (t2 == 0)) //если РАБОТАЕТ только первый датчик { errorCode = 2; return t1; } if ((t1 == 0) and (t2 == 0)) //если НЕ РАБОТАЮТ ОБА датчика { errorCode = 3; return 0; } return (min(t1, t2)); //если предыдущие проверки не прошли - возвращаем минимальное значение температуры } //=================== // Функция считывания "усредненного" значения с нужного входа АЦП unsigned int readTemp(byte pin) { unsigned int tmpRead = 0; for (byte i = 0; i < 8; i++) { tmpRead += analogRead(pin); } tmpRead = tmpRead / 8; return tmpRead; } //====== Show error code ========= void showError(byte errorCode) { static byte showErrorCount; //Глобальная переменная, видимая только этой процедурой if (errorCode == 0) { digitalWrite(ledPower, HIGH); //Если нет ошибок, просто включаем светодиод changeTime = (millis() + pauseFlash); } else { if (showErrorCount == 0) //если попади сюда первый раз { showErrorCount = errorCode * 2; //ставим значение счетчика равное удвоенному коду ошибки digitalWrite (ledPower, LOW); //гасим светодиод changeTime = (millis() + 4 * pauseFlash); //следующий вызов через } else { if (showErrorCount % 2) //если внутренний счетчик кратен 2 { digitalWrite (ledPower, HIGH); //включаем светодиод showErrorCount = showErrorCount - 1; //уменьшаем значение счетчика changeTime = (millis() + pauseFlash / 4); //для красоты, след. вызов через половину заданного интервала } else { digitalWrite(ledPower, LOW); //если попадаем на нечетное значение, гасим светодиод showErrorCount = showErrorCount - 1; changeTime = (millis() + pauseFlash); } } } } //end show error
Однако не все так просто, как казалось на первый взгляд...
Кроме косяков с отображением кодов ошибок (в случае переполнения millis()) - этот момент надеюсь всорости решить) что-то меня еще беспокоит.
Как то неправильно выглядит принудительный сброс ошибки №4 при старте нагрева :(
Если внимательно отнестись к исходным данным, а именно нарисовать и рассмотреть все возможные комбинации, то получается много чего интересного:
Для подогрева можно испльзовать что нибудь другое, лампочки галогенки небольшие на 12V (батарея из лампочек соединеных параллельно) , подобрать такое количиство и мощность что бы ничего не дымило даже при отключенном вентиляторе. ТАкие испольщуют для подсветки в мебельных шкафах на полках или в кухонных козырьках - встраиваемые, от них тепла достаточно. Или можно использовать сушилки для обуви , которые вставляются в обувь. Датчики по температуре для надежности три штуки в отсек,работают по схеме "два из трех" если два верное значение- то норма, иначе если меньше двух то авария. Можно контроллировать ток на нагревательном элементе- если есть ток то норма иначе авария или неисправность. Схема должна работать даже если не включится ветилятор, при помощи естевственной циркуляции воздуха. Сделать дополнительные отверстия для естевственной циркуляци воздуха и нагреватели раположить соответственно.
Много можно накрутить, предусматреть дополнителные резервные нагреватели которые будут включаться если первые вышли из строя. Так же сигнализацию, как минимум, есть нет напряжения питания (~220В)
Кодовое слово: "Диммер и пропорциональное регулирование".
К сожалению, что есть - то и нужно использовать. Таковы, если хотите, условия игры. Есть торчащие из стены три пары проводов: питание 220, подключение ламп нагрева и тонкие - вентиляторы. Количество датчиков понятное дело можно было бы увеличить, но тут уже я сам себя ограничил (разведя и изготовя) плату под две штуки.
Насчет вентиляторов... Из моего опыта работы с вентиляторами, как правило полному выходу из строя предшествуют достаточно громкие и противные завывания... Одновременный выход из строя и темодатчика и вентилятора в одном отсеке возможен, но маловероятен. Я уверен, что из имеющихся кубиков вполне возможно соорудить НАДЕЖНУЮ и эффективную систему. Понятное дело, что "Диммер и пропорциональное регулирование" - хорошо, но не в моем случае.
Основные тезисы:
- Выход из строя нагревателей полностью (лампы соеденены паралельно-последовательно) КРАЙНЕ МАЛОВЕРОЯТЕН
- вентиляторы тянут холодный воздух через нагреватель далее в шкаф
- Выход из строя вентиляторА вполне можно отловить непропорциональным нагревом одного из отсеков шкафа (нагреватели в обоих отсеках работают одновременно).
- выход из строя термодатчика можно определить программно (в эл. схеме притяжка к земле)
- выход из строя (ну вдруг!) нагревателя - тоже можно определить программно (типа, 5 минут греем - а температура не равна нулю, но и не поднимается)
Пока не проверял, но уже существующих код (при полностью рабочих компонентах) уже должен работать. Главное предусмотреть возможные нештатные варианты и логику поведения при их возникновении
Все вышеуказанные диммеры уместятся вместо платы с реле. У меня 4 штуки на плате 60х55 и это неплотно. Плюсы - нет резкого включения и соответствено перегорания ламп, я для своего "погребка" 2,5х3х1,8м использую 4 галогеновых прожектора по 100Вт. Второй сезон без нареканий и без замен. Прожектор удобен тем, что никак горячей поверхностью ни к чему не прикоснуться, да и лампу повредить сложно. Весь диапазон диммирования разбит на 7 ступенек, сакрального смысла нет, просто прибавлял 40 единиц на ступеньку.
Алгоритм - включаем на минимум, через три минуты проверка, температура ниже предыдущей или равна, следующая ступенька и так до максимума. Если на максимуме тоже не нагревает, тогда уже alarm. Пока не было)))).
Диммеров два канала для надежности. Кстати, почему вентиляторы не задублировать?
Самое главное настройте автоматическую перезагрузку процессора при зависании а то повиснет и все погорит.(((
Соединить 2 или 3 сампы последовательно, чтоб даже при круглосуточной работе не горело дерево и вокруг проложите паранит или другое что не горючее. Пожар это страшная беда, никому не желаю!
И не зачем все усложнять упала температура ниже Т включили нагреватель и вентилятор до Т+5градусов.И так циклично.
Все эти ошибки и перепроверки как доп плюшки главное обеспечить базовые принцыпы пажаробезопасности!!!
Много букв, не осилил....
НО!
1. Термосвич ( или несколько) от пожара обязательно.
2. Нагреватель - две-три соединённые последовательно лампы.
3. Вентиляция работает всегда ( можно снижать обороты при отключнии нагрева)
4. ПИД регулятор. И лучше возьмите готовый
Всем спасибо за полезные советы. Пока реализовал следующее:
"вычищена и причесана" процедура вывода кода ошибок
Основная концепция, которая должна предотвратить ситуации с диагональным выходом из строя двух компонентов: включаем нагрев по минимальной (из двух) температуре, а выключаем по максимальной. Попутно (пока все хорошо и равномерно) замеряем промежутки времени доя нагрева и время остывания системы.
Если получили код ошибки 4 (ошибка нагревателя) переходим в аварийный режим работы - т.е. Греем по времени и остываем по времени.
во время тестирования на столе (с реальной лампочкой) все более менее ровно. Иногда происходила лажа с треском реле (при значительных расхождениях в показаниях датчиков сопоставимых с необходимой рзницей температур). Получалось, что сперва срабатывало условие включения (мин. Температура) и тут же выключение (по макс. Температуре). Решил вопрос пришлепкой-проверкой.
Думаю, что такой же эффект дал бы бОльший интервал между чтением показаний датчиков. Учитывая кучу неплановых пришлепок и довесков, Появилось острое желание нарисовать алгоритм на бумажке и еще раз вдумчиво рассмотреть все возможные варианты
Если кому интересно, текущий код могу показать.
но чувствую, что данный проект- это то, как не нужно проектировать.
Обязательно нагревательные элементы необходимо подключать последовательно с термопредохранителями.
Я ставлю три штуки на нагреватель, все соединяю последовательно.
можно применять и другой форм-фактор , благодаря наличию фланца лучше тепловой контакт.
Обязательно применять не менее трех штук, соединенных последовательно .
Вот спасибо. А чего-то про них и не в помнил. Я такие видел в утюге ;) кстати, забыл упомянуть, что отловил еще один аппаратный глюк. А именно, при чтении показаний с АЦП значения как то сильно прыгали. Решилось установкой небольшого кондесатора паралелльно резистору (притяжка к земле)
Делал себе на балконе нечто подобное, овощехранилище. В качестве нагревателя использовал термокабель, наподобие того, что в теплых полах используют, несколько витков на полу положил а над ним уже располагаются полки. Из электроники - обычный терморегулятор, через который в 220 включил термокабель. Установил температуру включения/выключения, и запускаю это всё в работу зимой, чтобы овощи хранилась/ не мерзли. Результат превзошел ожидания - лет 5 уже полет отличный. Термокабель в отличии от ламп накаливания пожаробезопаснее во много раз, как мне кажется, ну, и в плане перегорания, тоже.
как более подробно - где ставили конедесатор какой номинал ? - и какие именно показания прыгают - Интересно - у меня что то тоже плавают показания - На макете все ОК - как в среду эксплуатации начинается ))