Термореле для холодильника на Arduino Pro Mini и ds18b20.

pka_ua
Offline
Зарегистрирован: 03.11.2014

Есть у меня холодильник Nord. Уже не молодой, но вполне себе рабочий. Работал он себе, работал, как вдруг стал замечать, что не выключается он. Компрессор работает постоянно, наледь на "потеющей" стенке образовалась. Короче, термореле сломалось. Вызвали мастера и выяснился неприятный момент - данная модель холодильника шла с термореле, которое уже снято с производства, а другие реле имеют не совсем подходящие характеристики. Холодильник - штука полезная, поэтому, вздохнув, сказал, чтобы ставил хоть что-то. Новое реле выключало время от времени компрессор, но всё-таки температуру загоняло в минус и раз в день приходилось холодильник примерно на час-полтора выключать из розетки. Обзвон других мастеров-холодильщиков результатов не дал (кто с нордами вообще не работал, у кого тоже такого термореле не было) и встал извечный вопрос "Что делать?"

Решено было сделать своё термореле "с преферансом и поэтессами" с по-возможности наименьшим вмешательством в сам холодильник. Первым делом озадачился требованиями к реле. Поиск по форумам холодильщиков привёл к следующему списку требований:
- при включении напряжения сети - пауза 10 минут до включения двигателя независимо от температуры;
- при отключении, повторное включение не ранее 10 минут независимо от температуры;
- при перезагрузке - пауза 10 минут до включения двигателя независимо от температуры;
- если компрессор работает более 1 часа - принудительная остановка независимо от температуры.

Пауза перед каждым повторным включением для компрессора необходима. Это связано с тем, что примерно за 5 минут должно стравиться давление в компрессоре. Если компрессор включится раньше, то он будет испытывать повышенную нагрузку. Начнётся перегрев обмоток и для компрессора это может закончиться совсем печально.

Установить датчик в том-же месте, что и обычный не получалось, так как там уже стоял датчик термореле холодильника. Термореле холодильника я решил не трогать, а использовать как резервное, для страховки. Поэтому свой датчик я решил завести через трубку слива конденсата, а на время отладки, временно, завести его через уплотнитель двери (но, чувствую, это временное решение окажется постоянным). Для того, чтобы при случайном обрыве датчика холодильник не остался без управления, ввёл ещё одно правило:
- если температурный датчик оборван или неисправен, то компрессор работает в цикле (20 мин работа/40 мин отдых), при этом загорается аварийный светодиод.

Установка датчика в нестандартном месте привела к тому, что воспользоваться данными из справочника по термореле было нельзя. Там были параметры при установке в штатное место штатным образом. Поэтому, для начала, выбрав место установки датчика ds18b20, промерял температуры, при котором включался и выключался компрессор при уже установленном реле. Поскольку этот диапазон приводил к намораживанию, я просто поднял и температуру включения, и температуру выключения на градус. Это оказалось удачным решением. На другой модели холодильника и в другом месте установки это может оказаться и не так, придётся экспериментировать.

Для изготовления термореле я решил использовать 5-вольтовое Arduino Pro Mini, купленное в Китае (http://www.aliexpress.com/item/10Pcs-Lot-Pro-Mini-Module-Atmega328-5V-16M-For-Arduino-Compatible-With-Nano/1432639609.html)

и релейный модуль,

купленный там-же (http://www.aliexpress.com/item/Wholesale-Retail-New-1-Channel-H-L-Level-Triger-Optocoupler-Relay-Module-For-Arduino-5V-Hot/1321978586.html).

В качестве блока питания были использованы внутренности зарядного устройства для мобильных телефонов.

Термодатчик выполнен на ds18b20 и подключён к Arduino Pro Mini витой парой, выдернутой из кабеля локальной сети. Для герметичности место выводов залито термоклеем.

Вот фото собранного на макетке устройства. Как видно на фотографии, была ещё и звуковая сигнализация ошибки датчика при каждом отключении компрессора, но я от неё отказался и в итоговую схему пищалка не вошла.

Платы блока питания, Arduino Pro Mini и релейного модуля были соединены навесным монтажом и помещены в корпус с сетевой вилкой.

На тыльную сторону корпуса прикреплена розетка для наружной проводки, в которую и включается холодильник.

Такое решение не лишено недостатков - при паузах в работе компрессора холодильник обесточивается полностью, поэтому внутренняя подсветка не работает. С другой стороны отсутствует вмешательство в схему холодильника. Вот как это выглядит в работе.

Ну и программа для Arduino.

/*
termostat_for_nord.ino

Термореле для бытового холодильника

При включении напряжения сети - пауза 10 минут до включения двигателя независимо от температуры.
При отключении, повторное включение не ранее 10 минут независимо от температуры.
При перезагрузке - пауза 10 минут до включения двигателя независимо от температуры.
Если компрессор работает более 1 часа - принудительная остановка независимо от температуры.
Если температурный датчик оборван или неисправен, то компрессор работает
в цикле (20 мин работа/40 мин отдых), при этом загорается аварийный светодиод

Version: 20141018
*/

#include <avr/wdt.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// Температура включения компрессора
#define TEMPERATURE_MAX 5.0
// Температура отключения компрессора
#define TEMPERATURE_MIN -2.0
// Пауза перед включением компрессора (600000 = 10 минут)
#define DELAY_COMPRESSOR 600000
// Максимальное время работы компрессора (3600000 = 1 час)
#define MAXTIME_COMPRESSOR 3600000
// Реле подключено к 3 пину
#define RELE 3
// Датчик температуры подключён к 2 пину
#define ONE_WIRE_BUS 2
// Светодиод активности подключён к 13 пину
#define LED_ACTIVITY 13
// Свечение светодиода активности в мс
#define LED_ACTIVITY_ON 50
// Пауза светодиода активности в мс
#define LED_ACTIVITY_OFF 3950
// Светодиод ошибки датчика температуры подключён к 12 пину
#define LED_ERROR 12
// Время работы компрессора при ошибке датчика температуры (1200000 = 20 минут)
#define ERROR_COMPRESSOR_ON 1200000
// Время паузы компрессора при ошибке датчика температуры (2400000 = 40 минут)
#define ERROR_COMPRESSOR_OFF 2400000

float f_tempC;                         // Текущая температура
unsigned long ul_offTime;              // Время отключения компрессора
unsigned long ul_workTime;             // Время включения компрессора
unsigned long ul_newTime;              // Текущее время
unsigned long ul_deltaTime;            // Разница времени
unsigned long ul_actHeartLedTime;      // Время светодиода активности
boolean b_actLedOn;                    // Светодиод активности включён
boolean b_compressorOff;               // Компрессор выключен

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup() {
  wdt_enable(WDTO_2S);
  pinMode(RELE, OUTPUT);
  pinMode(LED_ACTIVITY, OUTPUT);
  pinMode(LED_ERROR, OUTPUT);
  digitalWrite(RELE, LOW);             // При загрузке компрессор отключён
  b_compressorOff = true;
  digitalWrite(LED_ACTIVITY, LOW);
  b_actLedOn = false;
  digitalWrite(LED_ERROR, LOW);
  sensors.begin();
  ul_offTime = millis();               // Запоминаем время начала работы программы
  ul_actHeartLedTime = ul_offTime;
}

// Функция вычисления разницы времени
unsigned long deltamills(unsigned long t_old, unsigned long t_new) {
  unsigned long delta;
  if ( t_old <= t_new ) {        
    delta = t_new - t_old;
  } else {
    delta = (4294967295 - t_old) + t_new;
  }
  return delta;
}

// Функция моргания светодиодом активности
void heartIndication(unsigned long ul_newLedTime) {
  unsigned long ul_deltaHeartTime = deltamills(ul_actHeartLedTime, ul_newLedTime);
  if(b_actLedOn){
      // Если светодиод активности включён, ждём интервала LED_ACTIVITY_ON мс
      if(ul_deltaHeartTime > LED_ACTIVITY_ON){
        digitalWrite(LED_ACTIVITY, LOW);
        b_actLedOn = false;
        ul_actHeartLedTime = ul_newLedTime;
      }
  } else {
    // Если светодиод активности выключен, ждём интервала LED_ACTIVITY_OFF мс
    if(ul_deltaHeartTime > LED_ACTIVITY_OFF){
      digitalWrite(LED_ACTIVITY, HIGH); 
      b_actLedOn = true;
      ul_actHeartLedTime = ul_newLedTime;
    }
  }
}

void loop() {
  wdt_reset();                         // Обнуляем WDT (сторожевой таймер)
  
  ul_newTime =  millis();              // Получаем текущее время

  heartIndication(ul_newTime);         // Моргаем светодиодом активности

  sensors.requestTemperatures();
  f_tempC = sensors.getTempCByIndex(0);  // Получаем температуру с датчика

  // Проверяем работоспособность датчика температуры
  if(( f_tempC > -20.0 ) && ( f_tempC < 50.0 )){ // Температурный датчик исправен
    digitalWrite(LED_ERROR, LOW);
    if ( b_compressorOff ) {                 // Если компрессор выключен
      ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
      if (ul_deltaTime > DELAY_COMPRESSOR) {  // Если разница времени простоя больше разрешенной
        if ( f_tempC > TEMPERATURE_MAX ) {    // Если температура больше максимально допустимой
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
      }
    } else {                                  // Если компрессор включен
      ul_deltaTime = deltamills(ul_workTime, ul_newTime); // Разница времени работы
      // Если температура меньше минимально допустимой или время работы больше допустимого
      if ( ( f_tempC < TEMPERATURE_MIN ) || ( ul_deltaTime > MAXTIME_COMPRESSOR ) ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
  } else {                                    // Температурный датчик неисправен или оборван
    digitalWrite(LED_ERROR, HIGH);
    if( b_compressorOff ){                    // Если компрессор выключен при неисправном датчике
        ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
        if (ul_deltaTime > ERROR_COMPRESSOR_OFF) {  // Если разница времени простоя больше разрешенной
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
    } else {                                  // Если компрессор включен при неисправном датчике
      ul_deltaTime = deltamills(ul_workTime, ul_newTime);
      if ( ul_deltaTime > ERROR_COMPRESSOR_ON ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
  }
}

 

melvladimir
Offline
Зарегистрирован: 08.03.2013

Тоже собрался такое делать, только для более старого холодильника :)
И еще хочу сделать регулятор и отображение температуры (от нерабочего парктроника одноцифровой), т.к. иногда надо сильнее намораживать, а иногда - слабее.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011
melvladimir
Offline
Зарегистрирован: 08.03.2013

вот взял и убил проект :) (заказал себе пару, мне не горит, подожду, тем более самому делать - дороже выходит).

toc
Offline
Зарегистрирован: 09.02.2013

pka_ua, Молодец!

Вопросы, ворчание, предложения:
1. Добавьте фотографию пациента в полный рост
2. ... и фотографию датчика температуры на его месте
3. почитайте про "конечный автомат". У вас вложенные ифы уже четырёхэтажные. При доработке и добавлении функций, программа станет громоздкой и трудно поддерживаемой.
4. фактически вы управляете холодильником. Переменная (строка 052) называется "компрессор...". Неочень.
5. эта же переменная называется "...выключен". Обычно значение true (или 1 или high) означает "включено". Инверсия значения и смысла мне мешает.
6. назовите перменную "холодильник включён".
7. тогда строки 062-063 лучше записать так:
b_fridgeActive = false;
digitalWrite(RELE, b_fridgeActive); // можно false вместо low

8. неужто вы убили родную зарядку от айпада?

В следующей версии ждём:
9. датчик открытой двери
10. своё освещение
11. звуковая сигнализация по событию "забыли закрыть дверь".
12. звуковая сигнализация по событию "хулиган поставил полную кастрюлю горячего борща" (дверь закрыта, компрессор включён, температура превышает TEMPERATURE_MAX и растёт).
13. доступный разъём для обновления прошивки и отладки.
14. логотип "powered by arduino" :)
15. включение спящего режима для экономии энергии. Например в 105 строке на одну секунду. В год съэкономите один киловатчас, если микроконтроллер 99% времери будет спать.

16. где заземление? не хорошо без него, мне кажется.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Не видно двух устройств DS18B20, т.к. делать на одном датчике 1-wire что-то серьезное - это себя не любить (у них бывают глюки)...

a5021
Offline
Зарегистрирован: 07.07.2013

Я писал для отличного от атмеги МК свою библиотеку 1-wire и ds18x20 и наблюдал эти устройства довольно внимательно. Ваших обвинений подтвердить не могу. Все там нормально с ними. Есть и глюки (куда ж без них), но они известны и что с ними делать -- понятно.

pka_ua
Offline
Зарегистрирован: 03.11.2014

Попробую по порядку

> 1. Добавьте фотографию пациента в полный рост

> 2. ... и фотографию датчика температуры на его месте

Датчик поставил в том месте, где намерзало больше всего. Сейчас датчик просто прижат к стенке, но при первой-же разморозке я его приклею.

> 3. почитайте про "конечный автомат". У вас вложенные ифы уже четырёхэтажные. При доработке и добавлении функций, программа станет громоздкой и трудно поддерживаемой

Попались на глаза 2 программки, позволяющие программировать arduino в релейной логике, но работу с датчикамия в них пока не понял :(

> 4-7

Ну, уже написал, как написал. Если буду корректировать режимы работы, то тогда и поправлю программу и код выложу. Без проверки в работе выкладывать не хочу.

> 8. неужто вы убили родную зарядку от айпада?

Эти зарядки, если их заказывать в Китае, да ещё и не поштучно, идут за рупь пучок. Естественно это не оригинал, но потребление небольшое, снятый корпус способствует охлаждению. Короче 3-й сорт - не брак.

> 9-12

Ну, даже не знаю. Терморегулятор делался для перевода холодильника из режима срочной замены в режим плановой замены, когда будут деньги на новый холодильник и настроение для его выбора по магазинам. Сейчас смотрю на него и думаю - работает, ну и пусть себе работает.

> 13. доступный разъём для обновления прошивки и отладки.

Разъём программирования на ардуинку я распаял, правда не изогнутый, а прямой. Так удобнее перепрошивать по месту. Для перепрошивки надо отвинтить 3 шурупа. В принципе, частые перепрошивки могут понадобиться только на этапе подбора температуры.

> 14. логотип "powered by arduino" :)

Где-то валялась переводка. Впрочем, на моём холодильнике она будет не заметна :)

> 15. включение спящего режима для экономии энергии

С этим я пока не разобралься. Надо будет почитать. Может, соориентируете по форуму на готовые примеры.

> 16. где заземление? не хорошо без него, мне кажется.

Если обратили внимание на вилку холодильника, то там всего 2 штырька и всё. Заземление на холодильнике не предусмотрено изготовителем. Корпус, который я использовал для реле, пластиковый, так что, думаю будет безопасно.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

a5021 пишет:

Ваших обвинений подтвердить не могу. Все там нормально с ними. Есть и глюки (куда ж без них), но они известны и что с ними делать -- понятно.

Ага, зайдите в раздел "Аппаратные вопросы" - там сейчас в топе как раз про "минус 127 градусов" с DS18B20, у меня известное "плюс 75" выскочило один раз за полтора года работы датчика в круглосуточном режиме, но ведь выскочило же!

a5021
Offline
Зарегистрирован: 07.07.2013

Мне не нужно никуда заходить. Посмотрите на исходник библиотеки OneWire и там вы без труда обнаружите, что базовые процедуры, типа read_bit/write_bit используют тупые задержки фиксированной величины, чтобы примерно попасть в середину импульса, и замерив уровень в этот момент, принять решение об информационной составляющей (0 или 1). Никого, похоже, не смущает, что производитель датчиков указывает разброс временных параметров в довольно широких пределах. А зря. Если верить спецификациям на чип,  то фиксированной задержкой (как это сделано в OneWire) можно не то, что в середину, а вообще в импульс не попасть. В этом случае, при полностью исправном датчике, с него будут считываться величины точнее всего характеризующие среднедневную величину флуктуаций солнечной радиации на обратной стороне луны, но никак не измеряемой температуры. И тот факт, что в большинстве случаев библиотека работает правильно, не значит, что библиотека будет работать правильно всегда. Да, методы там используемые охватывают некоторый дипазон значений, но совершенно точно, что не весь. И так часто наблюдаемая картина, когда датчик работает, но по достижению определенной, температуры начинает показывать фантастические значения, как раз и является иллюстрацией неправильного подхода к работе с датчиком со стороны автора библиотеки. Все очень просто -- от температуры меняются временные характеристики интефейса. Импульсы могут становиться длиннее или короче (зависит от направления изменения тепературы). Выставленные задержки в процедурах работы с шиной перестают попадать в заданный интервал. Отсюда и множество сообщений на форумах, что смена библиотеки часто помогает. Да, в разных библиотеках разные величины задержки и какая-то из библиотек имеет лучшие шансы подойти под некий конкретный датчик, а какая-то хуже. Но совершенно точно, что в большинстве случаев, сам датчик тут вообще ни при делах.

Методы основанные на задержках может выглядели прилично во времена древних низкоскоростных МК, типа 8051, когда и средств то не было, чтобы длительность импульса измерить, но для ардуины это выглядит полным анахронизмом. Таймеры атмеги вполне в состоянии измерять длительности с точностью до 1/16 микросекунды и чего-чего, а этого с избытком хватает для двольно "медленных" устройств шины 1-wire. Методы основанные на измерениях длительностей (в отличие от ныне практикующихся "попал-не_попал") полностью решают проблему "волшебных температур" и  прочих "дивных глюков", а заодно способны уберечь от ошибочного приписывания достойным устройствам несуществующих отрицательных качеств.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

a5021 пишет:

Методы основанные на задержках может выглядели прилично во времена древних низкоскоростных МК, типа 8051, когда и средств то не было, чтобы длительность импульса измерить, но для ардуины это выглядит полным анахронизмом. Таймеры атмеги вполне в состоянии измерять длительности с точностью до 1/16 микросекунды и чего-чего, а этого с избытком хватает для двольно "медленных" устройств шины 1-wire. Методы основанные на измерениях длительностей (в отличие от ныне практикующихся "попал-не_попал") полностью решают проблему "волшебных температур" и  прочих "дивных глюков", а заодно способны уберечь от ошибочного приписывания достойным устройствам несуществующих отрицательных качеств.

Ну так где Ваша версия библиотеки, измеряющая длительности при первом обращении к датчику и использующая эти параметры для получения безошибочных данных? В теории - я тоже понимаю, где плохо, но вот поправить - не в состоянии: проще пару датчиков прицепить и сравнивать их показания...

a5021
Offline
Зарегистрирован: 07.07.2013

Длительности должны измеряться не при первом обращении, а всегда. Именно по временнЫм характеристикам импульса надлежит делать вывод, о каком логическом уровне нам сообщает датчик. Моя библиотека написана для другого контроллера и портировать ее под ардуино целесообразности особой не вижу.  Единственное, о чем я хотел сказать, что не стоит обвинять приличное в общем-то железо в тех недостатках, которые ему не свойственны. И в ветке про аппаратные вопросы проблема в очередной раз разрешилась путем замены библиотеки, кстати.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Автор, как Вы заставили работать "сторожевого пса" на Про Мини? Проект отличный, просто и без лишних погремушек. У самого термостат шалит в холодильнике. Респект, утащу.

pka_ua
Offline
Зарегистрирован: 03.11.2014

> Автор, как Вы заставили работать "сторожевого пса" на Про Мини?

Да, в общем, просто почитал примеры использования wdt на Arduino.

> Респект, утащу.

На здоровье. :)

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Наверное у Вас "неправильные" пчелы. Мои Про Митни в вечный бутлуп уходят при использовании вочдога на стандартном загрузчике. 

Я пожалуй симистор 10А с МОСкой для надежности влуплю. Хватит 10А на пуске или побольше взять? С радиатором конечно.

pka_ua
Offline
Зарегистрирован: 03.11.2014

> Я пожалуй симистор 10А с МОСкой для надежности влуплю

Тоже поначалу думал обойтись без движущихся частей, но потом посмотрел на размеры контактов релюх холодильника и поставил реле. Не хотелось ставить радиаторы. Если у Вас нормально получится с симистором, то будет интересно посмотреть схему включения.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

У меня мешок этих BTA10 и MOC3063, а схема подключения в любом даташите на MOC есть. Ничего сложного. Обязательно покажу как внедрю.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Umka пишет:

Автор, как Вы заставили работать "сторожевого пса" на Про Мини? Проект отличный, просто и без лишних погремушек. У самого термостат шалит в холодильнике. Респект, утащу.

Если в результате запуска wdt видите "crazy led" - то надо менять прошивку на optiboot. Как - я тут на форуме ссылки давал, или на хабре поищите.

Umka пишет:

У меня мешок этих BTA10 и MOC3063, а схема подключения в любом даташите на MOC есть. Ничего сложного. Обязательно покажу как внедрю.

Там вопрос будет в параметрах снабберной цепочки. Остальное-то действительно несложно.

Тима
Тима аватар
Offline
Зарегистрирован: 11.04.2013

собрал подобное для управления котлом BAXI. Пока в стадии испытания...

   

Пока питается от зарядника телефона и подключен напрямую проводами. Жду с китая радиомодуль.

В последствии будет встроен в гнездо розетки и управлять по радиоканалу из зала.

pka_ua
Offline
Зарегистрирован: 03.11.2014

Umka пишет:

Автор, как Вы заставили работать "сторожевого пса" на Про Мини?

После этого вопроса я решил поподробнее изучить работу watchdog timer-а на arduino. Меня ожидал неприятный сюрприз. Оказывается, на большой доле плат этот таймер работает неправильно. Мало того, часто он приводит платы в такое состояние, когда помогает только перезаливка bootloader-a. :(

Поэтому вот версия скетча без использования сторожевого таймера.

/*
termostat_for_nord.ino

Термореле для бытового холодильника

При включении напряжения сети - пауза 10 минут до включения двигателя независимо от температуры.
При отключении, повторное включение не ранее 10 минут независимо от температуры.
При перезагрузке - пауза 10 минут до включения двигателя независимо от температуры.
Если компрессор работает более 1 часа - принудительная остановка независимо от температуры.
Если температурный датчик оборван или неисправен, то компрессор работает
в цикле (20 мин работа/40 мин отдых), при этом загорается аварийный светодиод

Version: 20141121
*/

#include <OneWire.h>
#include <DallasTemperature.h>

// Температура включения компрессора
#define TEMPERATURE_MAX 5.0
// Температура отключения компрессора
#define TEMPERATURE_MIN -2.0
// Пауза перед включением компрессора (600000 = 10 минут)
#define DELAY_COMPRESSOR 600000
// Максимальное время работы компрессора (3600000 = 1 час)
#define MAXTIME_COMPRESSOR 3600000
// Реле подключено к 3 пину
#define RELE 3
// Датчик температуры подключён к 2 пину
#define ONE_WIRE_BUS 2
// Светодиод активности подключён к 13 пину
#define LED_ACTIVITY 13
// Свечение светодиода активности в мс
#define LED_ACTIVITY_ON 50
// Пауза светодиода активности в мс
#define LED_ACTIVITY_OFF 3950
// Светодиод ошибки датчика температуры подключён к 12 пину
#define LED_ERROR 12
// Время работы компрессора при ошибке датчика температуры (1200000 = 20 минут)
#define ERROR_COMPRESSOR_ON 1200000
// Время паузы компрессора при ошибке датчика температуры (2400000 = 40 минут)
#define ERROR_COMPRESSOR_OFF 2400000

float f_tempC;                         // Текущая температура
unsigned long ul_offTime;              // Время отключения компрессора
unsigned long ul_workTime;             // Время включения компрессора
unsigned long ul_newTime;              // Текущее время
unsigned long ul_deltaTime;            // Разница времени
unsigned long ul_actHeartLedTime;      // Время светодиода активности
boolean b_actLedOn;                    // Светодиод активности включён
boolean b_compressorOff;               // Компрессор выключен

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup() {
  pinMode(RELE, OUTPUT);
  pinMode(LED_ACTIVITY, OUTPUT);
  pinMode(LED_ERROR, OUTPUT);
  digitalWrite(RELE, LOW);             // При загрузке компрессор отключён
  b_compressorOff = true;
  digitalWrite(LED_ACTIVITY, LOW);
  b_actLedOn = false;
  digitalWrite(LED_ERROR, LOW);
  sensors.begin();
  ul_offTime = millis();               // Запоминаем время начала работы программы
  ul_actHeartLedTime = ul_offTime;
}

// Функция вычисления разницы времени, в том числе и при длительной
// непрерывной работе более 49 суток
unsigned long deltamills(unsigned long t_old, unsigned long t_new) {
  unsigned long delta;
  if ( t_old <= t_new ) {        
    delta = t_new - t_old;
  } else {
    delta = (4294967295 - t_old) + t_new;
  }
  return delta;
}

// Функция моргания светодиодом активности
void heartIndication(unsigned long ul_newLedTime) {
  unsigned long ul_deltaHeartTime = deltamills(ul_actHeartLedTime, ul_newLedTime);
  if(b_actLedOn){
      // Если светодиод активности включён, ждём интервала LED_ACTIVITY_ON мс
      if(ul_deltaHeartTime > LED_ACTIVITY_ON){
        digitalWrite(LED_ACTIVITY, LOW);
        b_actLedOn = false;
        ul_actHeartLedTime = ul_newLedTime;
      }
  } else {
    // Если светодиод активности выключен, ждём интервала LED_ACTIVITY_OFF мс
    if(ul_deltaHeartTime > LED_ACTIVITY_OFF){
      digitalWrite(LED_ACTIVITY, HIGH); 
      b_actLedOn = true;
      ul_actHeartLedTime = ul_newLedTime;
    }
  }
}

void loop() {
  ul_newTime =  millis();              // Получаем текущее время

  heartIndication(ul_newTime);         // Моргаем светодиодом активности

  sensors.requestTemperatures();
  f_tempC = sensors.getTempCByIndex(0);  // Получаем температуру с датчика

  // Проверяем работоспособность датчика температуры
  if(( f_tempC > -20.0 ) && ( f_tempC < 50.0 )){ // Температурный датчик исправен
    digitalWrite(LED_ERROR, LOW);
    if ( b_compressorOff ) {                 // Если компрессор выключен
      ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
      if (ul_deltaTime > DELAY_COMPRESSOR) {  // Если разница времени простоя больше разрешенной
        if ( f_tempC > TEMPERATURE_MAX ) {    // Если температура больше максимально допустимой
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
      }
    } else {                                  // Если компрессор включен
      ul_deltaTime = deltamills(ul_workTime, ul_newTime); // Разница времени работы
      // Если температура меньше минимально допустимой или время работы больше допустимого
      if ( ( f_tempC < TEMPERATURE_MIN ) || ( ul_deltaTime > MAXTIME_COMPRESSOR ) ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
  } else {                                    // Температурный датчик неисправен или оборван
    digitalWrite(LED_ERROR, HIGH);
    if( b_compressorOff ){                    // Если компрессор выключен при неисправном датчике
        ul_deltaTime = deltamills(ul_offTime, ul_newTime); // Разница времени простоя
        if (ul_deltaTime > ERROR_COMPRESSOR_OFF) {  // Если разница времени простоя больше разрешенной
          digitalWrite(RELE, HIGH);           // Включаем компрессор
          b_compressorOff = false;
          ul_workTime = millis();             // Записываем время включения
        }
    } else {                                  // Если компрессор включен при неисправном датчике
      ul_deltaTime = deltamills(ul_workTime, ul_newTime);
      if ( ul_deltaTime > ERROR_COMPRESSOR_ON ) {
        digitalWrite(RELE, LOW);              // Выключаем компрессор
        b_compressorOff = true;
        ul_offTime = millis();                // Запоминаем время выключения компрессора
      }
    }
  }
}

Всё остальное осталось без изменений, поскольку удачно проработало больше месяца без единого сбоя.

Поскольку watchdog теперь за программой не следит, стоит расположить arduino в корпусе так, чтобы был виден светодиод активности. В принципе, для бытовых целей этого должно хватить, поскольку холодильник - довольно инерционная система и если что-то не так, то хоть кто нибудь за сутки заметит неправильную работу. Хотя watchdog жаль. :(

Если кто нибудь знает более менее устойчивое решение, позволяющее безопасно использовать watchdog на Arduino, то отпишитесь пожалуйста, ну или ткните, где можно почитать.

avton
avton аватар
Offline
Зарегистрирован: 11.05.2014

Самое простое не использовать загрузчик :) а шить через ISP.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Решение знаю только одно - сменить загрузчик на optiboot. Нужен программатор или вторая Ардуина в роли программатора. UsbAsp работает, причем даже из arduino ide. Нужно дописать кусок текста в boards.txt

pka_ua
Offline
Зарегистрирован: 03.11.2014

Т.е. простого решения для неспециалиста не существует? Хотя, для контроллера для любителей, возможности arduino и так впечатляют.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Ардуино как-бы сама по себе предполагает творчество и прошивку. Неспециалисту лучше готовое изделие купить.

pka_ua
Offline
Зарегистрирован: 03.11.2014

Umka пишет:
Ардуино как-бы сама по себе предполагает творчество и прошивку

С этим, в принципе, согласен.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

pka_ua пишет:

Т.е. простого решения для неспециалиста не существует?

Поверьте, это - именно "простое решение для неспециалиста". :) Почитать можно на хабре: habrahabr.ru/post/189744/, перешивается с помощью копеечного программатора USBASP, который подключается к ардуино по шести проводкам, включая землю и питание. Дольше объяснять, чем подключиться.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Часа три вчера воевал с Мини, Оптибутом и статьями с Хабра. Оптибут шьется, ок, но плата скетчи потом не принимает через USB-UART. Скорость порта менял. Не помогает. Что я делаю не так?

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Сам отвечаю. Разобрался я с собакой на Про Мини. В последней бете Arduino IDE, вообще ничего делать не нужно для прошивки Optiboot. Нужно только в списке плат выбрать Mini, а в файле boards.txt уже прописана нужная прошивка и скорость порта. Все шьется и заливается и даже (о чудо!) работает watchdog. 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Umka пишет:

Что я делаю не так?

Сам отвечаю.

Форум не читаете: http://arduino.ru/forum/apparatnye-voprosy/pro-mini-cherez-kakoi-programmator-proshche-zalivat  , и пишете результаты куда попало и как попало. Какая версия у Вашей "последней беты"? От какого числа хотя бы? В "ночной сборке" от 23 ноября - еще все по-старому:

atmega/ATmegaBOOT_168_atmega328.hex, и в бете 1.5.8 - тоже пришлось лезть руками и править boards.txt

--- hardware/arduino/avr/boards.txt.orig	2014-10-01 19:15:37.000000000 +0400
+++ hardware/arduino/avr/boards.txt	2014-12-01 23:34:57.211494363 +0300
@@ -577,7 +577,8 @@
 pro.menu.cpu.16MHzatmega328.bootloader.low_fuses=0xFF
 pro.menu.cpu.16MHzatmega328.bootloader.high_fuses=0xDA
 pro.menu.cpu.16MHzatmega328.bootloader.extended_fuses=0x05
-pro.menu.cpu.16MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
+## pro.menu.cpu.16MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
+pro.menu.cpu.16MHzatmega328.bootloader.file=optiboot/optiboot_atmega328.hex
 
 pro.menu.cpu.16MHzatmega328.build.mcu=atmega328p
 pro.menu.cpu.16MHzatmega328.build.f_cpu=16000000L

 

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Ответил где спросил, могу в другой раздел перенести.

Форум и наш и буржуйский весь перекопал по теме сторожевого таймера на Про Мини, но результатов внятных не добился.

Начал со статьи на Хабре. Все сделал по написанному - шьет, но скетчи не принимает.

optiboot_atmega328.hex не работает на моих платах.

optiboot_pro_16MHz.hex тоже не работает.

Заработал optiboot_atmega328-Mini.hex, который оказывается и был прописан изначально в boards.txt в разделе Arduino MINI.

Вот полный листинг раздела, я ничего не правил:

## Arduino Mini w/ ATmega328
## -------------------------
mini.menu.cpu.atmega328=ATmega328
 
mini.menu.cpu.atmega328.upload.maximum_size=28672
mini.menu.cpu.atmega328.upload.maximum_data_size=2048
mini.menu.cpu.atmega328.upload.speed=115200
 
mini.menu.cpu.atmega328.bootloader.high_fuses=0xd8
mini.menu.cpu.atmega328.bootloader.extended_fuses=0x05
mini.menu.cpu.atmega328.bootloader.file=optiboot/optiboot_atmega328-Mini.hex
 
mini.menu.cpu.atmega328.build.mcu=atmega328p
 
Нашел я это в бете 1.5.8, возможно и в стабильном релизе то же самое, не проверял. Так вот, этот загрузчик шьется и работает и вачдог с ним работает. А для его прошивки вообще ничего править не нужно, нужно только выбрать MINI плату в IDE. Не Pro Mini, а именно Arduino Mini. Отакот. Может это мои платы такие, но камешек то одинаковый у всех.

 

 

pka_ua
Offline
Зарегистрирован: 03.11.2014

Как и собирался, приклеил датчик ds18b20 к стенке холодильника.

 

Раньше он был просто прижат. Датчик приклеен так, чтобы его плоская часть прилегала к задней стенке холодильной камеры. Приклеивал термопистолетом, следя за тем, чтобы термоклей не попал на корпус датчика. По работе термореле никаких изменений нет, всё замечательно работает на второй прошивке (та, которая без watchdog).

Namelost
Offline
Зарегистрирован: 12.06.2015

Очень интересная статья!
Сам столкнулся с такой проблемой. Думаю также неинвазивно "починить".

Но интересут такой вопрос - насколько эта схема не повреждает сам компрессор у холодильника?

И можно ещё попросить фотографию, как провода входят внутрь холодильника? Это не сильно уменьшает теплоизоляцию?

prometheus
Offline
Зарегистрирован: 31.05.2011

Готовый, недорогий терморегулятор для холодильника - ZL-630A

Или подороже - ETC-974

 

Namelost
Offline
Зарегистрирован: 12.06.2015

Спасибо за ссылку, но мне нужен именно нетнвазивный вариант для холодильника на съёмной квартире.

Покупать новый - не вариант. И ковырять его нельзя - не совсем мне принадлежит вещь.

 

Или он может быть внешним, и к розетке подключённым?

prometheus
Offline
Зарегистрирован: 31.05.2011

Да, можно просто управлять подачей электропитания холодильнику.

Если мощность холодильника больше мощности терморегулятора, подключать нужно через реле, лучше твердотельные.

melvladimir
Offline
Зарегистрирован: 08.03.2013

Почти в начале темы были ссылки на готовые и я там писал, что заказал себе. Приехали, протестировал и установил на старый холодильник, который не выключался: реле на готовом может легко коммутировать 5А (максимум кажись 10А), просто разрезал фазу и подключил + сам контроллер питается от блока питания. Датчик температуры завел прямо через дверь, уплотнитель довольно мягкий, а провод - плоский. Провод приклеил к холодильнику скотчем, предварительно обезжирив поверхность.

Где расположить датчик? На усмотрение каждого. Я расположил на уровне нижней полки (под ней еще можно положить продукты). Выставил диапазон 3,5-5,5*С, работает классно.

prometheus
Offline
Зарегистрирован: 31.05.2011
сам контроллер питается от блока питания.

В моих примерах, питание не от блока питания, а от сети 220V.

melvladimir
Offline
Зарегистрирован: 08.03.2013

Да какая разница то? То ли блок питания вынесен, то ли распаян на плате термоконтроллера. Суть от этого практически не меняется. У меня блок питания подключен к той же вилке, что и холодильник, т.е. лишнюю розетку не занимает + от него можно запитать еще что-то небольшое и полезное, типа светодиодной подсветки в холодильнике, если её изначально не было и включать микриком от двери :)

prometheus
Offline
Зарегистрирован: 31.05.2011
Да какая разница то?

Разница только в цене вопроса :)

Ну и в компактности.

melvladimir
Offline
Зарегистрирован: 08.03.2013

в моём случае - это <4$ за контроллер и 2-4$ за БП (на 12В >100мА, это если нет в наличии) + сделать какой-то корпус (у меня как раз была прозрачная пластиковая коробочка, просверлил несколько отверстий и приклеил на двусторонний скотч).
Сам контроллер в коробочке: 60х50х25мм (без коробки: 50х40х20мм), ну а БП - возле розетки, его и не видно (60х40х30мм).

Namelost
Offline
Зарегистрирован: 12.06.2015

Всё же решился на вариант с ардуиной, так как он компактнее и не требует огромной коробки с яркими красными циферками.

pka_ua
Offline
Зарегистрирован: 03.11.2014

Namelost пишет:
Но интересут такой вопрос - насколько эта схема не повреждает сам компрессор у холодильника?

Я не случайно везде ввёл задержки 10 минут после выключения компрессора. Компрессору холодильника надо примерно 5 минут для того, чтобы сбросить давление в системе. Если компрессор выключить, а потом сразу включить, то он будет вынужден работать под гораздо большей нагрузкой. Собственно, для того, чтобы защитить компрессор от перегрева в холодильники ставят тепловое защитное реле. В моём случае такой ситуации просто не возникает - если компрессор выключился или пропало питание на короткое время, то компрессор повторно включится не ранее чем через 10 минут. Так что он работает в очень щадящем режиме.

Кроме того, реле устройства включается точно также, как и температурное реле - в разрыв цепи питания. Разницы с "родной" схемой нет за одним исключением - отключается не только компрессор, но и плафон подсветки.

Namelost пишет:
И можно ещё попросить фотографию, как провода входят внутрь холодильника? Это не сильно уменьшает теплоизоляцию?

Так руки и не дошли сделать по другому. Но это больше потому, что у меня на месте остался неподходящий, но установленный температурный датчик. Если бы его не было или там было свободное место, я бы завёл провода через штатные отверстия. Если это влияет на теплоизоляцию, то не сильно. По крайней мере электропотребление не увеличилось, скорее наоборот.

melvladimir
Offline
Зарегистрирован: 08.03.2013

Namelost пишет:

Всё же решился на вариант с ардуиной, так как он компактнее и не требует огромной коробки с яркими красными циферками.

Если использовать мини-про и всё паять очень компактно, то выдет примерно то же, что и покупное. Правда можно запрограммировать как угодно. Хотя у покупного функций с избытком! И гистерезис и задержка при повторном включении (если "свет" пропал) и выбор диапазона. В общем, я прикинул, посчитал: делать самому - будет больше, дороже да еще и ковыряться...

Другое дело, если делать всё с нуля. Тогда можно будет выйти на ту же стоимость по комплектухе и улучшить компактность и не запрягать "суперкомпьютер для арифметических действий".

Namelost
Offline
Зарегистрирован: 12.06.2015

Спасибо больше за код - сам бы с нуля написал такое очень не сразу. Пока тестовая сборка вообще на коленке сделана и выглядит как комок проводов. Планируется без пайки, так как в ней не силён и решение на бредбоарде будет куда надёжнее. Спасибо за идею использовать провода от витухи - реально удобное решение

Конечный результат скоро выложу в фотографиях.

bwn
Offline
Зарегистрирован: 25.08.2014

Namelost пишет:

Спасибо больше за код - сам бы с нуля написал такое очень не сразу. Пока тестовая сборка вообще на коленке сделана и выглядит как комок проводов. Планируется без пайки, так как в ней не силён и решение на бредбоарде будет куда надёжнее. Спасибо за идею использовать провода от витухи - реально удобное решение

Конечный результат скоро выложу в фотографиях.

бредборд для рабочего устройства, очень элегантный способ приобретения геммороя))))

Namelost
Offline
Зарегистрирован: 12.06.2015

Ну я бы так не сказал:

Лень было делать отдельный дисплей, проще использовать готовое решение.

Содержимое коробочки:

Питание платы и подключение к розетке:

Проводочки:

Пришлось поставить вентилятор на самое обледеневшее место:

 

bwn
Offline
Зарегистрирован: 25.08.2014

Ну таки у вас еще все впереди, по мере ослабления и окисления контактов.

В вашем варианте, ну кто мешает хотя бы к ножкам наны подпаяться. Неужели знакомых никого нет, за бутылку пива?

pka_ua
Offline
Зарегистрирован: 03.11.2014

Namelost пишет:

Содержимое коробочки

Посмотрел характеристики применённого твердотельного реле. Интересно, но существенно дороже, чем электромагнитное. Можете описать, как работает на индуктивной нагрузке (компрессор), были-ли какие-нибудь подводные камни в использовании?

Namelost
Offline
Зарегистрирован: 12.06.2015

У меня были проблемы с механическим - одно реле перестало работать, второе вроде работало, но я решил не рисковать + оно беззвучно "щёлкает". Ну и размер чуть больше, чем у совсем маленьких аналогов, но там нужна пайка. Решил, что без пайки такой большой гораздо надёжнее.

Вроде никаких камней - потребление за замыкание очень малое. Ну только цена. На ебее гораздо дешевле, чем в мстных магазинах радиодеталей. Стабильность работы - вроде нормальная.

Тут предупреждают об окислении контактов. Окислятся - поменяю. Да и распаивать будет такие маленькие пины для мня слишком муторно.

Да и сколько там этого окисления - 5 вольт искрить будут и взорвуться?

bwn
Offline
Зарегистрирован: 25.08.2014

Namelost пишет:

Тут предупреждают об окислении контактов. Окислятся - поменяю. Да и распаивать будет такие маленькие пины для мня слишком муторно.

Да и сколько там этого окисления - 5 вольт искрить будут и взорвуться?

Как раз и беда, что 5 вольт. Малейший окисел и сигнал начинает сбоить. Трудно диагностируемая, взрывающая мозг ошибка.

Namelost
Offline
Зарегистрирован: 12.06.2015

А какие симптомы? Просто контакта не будет? И как быстро должно окислиться? Там на замыкание вообще почти не нужен ни вольтаж ни ампераж.