Контроллер управления влажностью на Atmega328

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

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

Вторым очевидным решением было просто посадить вентилятор на отдельный выключатель и предоставить управление человеку. Но человеческий фактор таков, что вентилятор постоянно забывали включать, а если включали, то выключать. Эффективность работы вентилятора быстро стремилась к нулю.

Пришлось подключить к делу свое увлечение Arduino и несложными микроконтроллерами.

Пораскинув мозгами сформулировал

Требования к устройству управления



  1. устройство управления должно работать в автоматическом режиме;
  2. вентилятор должен включаться от повышения влажности;
  3. включение вентилятора не должно зависеть от текущего уровня влажности в квартире;
  4. вентилятор должен работать, когда в ванной комнате никого нет;
  5. устройство управление должно быть максимально простым и дешевым;


Выбор элементной базы


Прототип данного устройства создавался на отладочной плате Arduino Uno китайского производства:


Потом все переносилось в микроконтроллер Atmega328, прошитый стандартным ардуиновским загрузчиком.

Конечное устройство создавалось по принципу «я тебя слепила из того что было». Все элементы были приобретены ранее на просторах интернета под различные проектики или выдраны из неработающих устройств:



В качестве источника питания подошел LED driver 3x1вт от светильника, который вполне справился с питанием импульсного стабилизатора LM2596.
В качестве корпуса была применена кроссовая коробочка от старой АТС.

Подключение


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

  • Pin 1 (Reset) через резистор 10К к + (для избежания помех на этой ноге);
  • Pin 2 (D0) — не используется;
  • Pin 3 (D1) — не используется;
  • Pin 4 (D2) — катод «G» семисегментного индикатора;
  • Pin 5 (D3) — катод "." семисегментного индикатора;
  • Pin 6 (D4) — катод «A» семисегментного индикатора;
  • Pin 7 (+) — питание 3.5В;
  • Pin 8 (-) — земля;
  • Pin 9 (Clock) — не используется;
  • Pin 10 (Clock) — не используется;
  • Pin 11 (D5) — катод «F» семисегментного индикатора;
  • Pin 12 (D6) — катод «D» семисегментного индикатора;
  • Pin 13 (D7) — катод «E» семисегментного индикатора;
  • Pin 14 (D8) — катод «C» семисегментного индикатора;
  • Pin 15 (D9) — катод «B» семисегментного индикатора;
  • Pin 16 (D10) — не используется;
  • Pin 17 (D11) — не используется;
  • Pin 18 (D12) — не используется;
  • Pin 19 (D13) — управление схемой включения вентилятора;
  • Pin 20 (+) — питание 3.5В (дубль);
  • Pin 21 (Aref) — не используется;
  • Pin 22 (-) — земля (дубль);
  • Pin 23 (A0/D14) — фоторезистор с подтягивающим резистором 27К на землю;
  • Pin 24 (A1/D15) — вход с датчика DHT11;
  • Pin 25 (A2/D16) — общий анод 2-го разряда семисегментного индикатора через резистор 4.7К;
  • Pin 26 (A3/D17) — общий анод 1-го разряда семисегментного индикатора через резистор 4.7К;
  • Pin 27 (A4/D18) — кнопка с подтягивающим резистором 10К на +;
  • Pin 28 (A5/D19) — не используется;


На индикатор CPS03621BR даташит найден не был, поэтому выводы находились при помощи батарейки методом тыка. Индикатор оказался с общим анодом. Схема расположения катодов:
image

Вентилятор управляется при помощи симистора BT137.
Схему подключения взял с сайта avr.ru

Если кто-то вздумает повторять — ОСТОРОЖНО, на корпусе симистора напряжение 220В.



Алгоритм работы



Микроконтроллер с периодичностью раз в 10 секунд меряет влажность и температуру.
Влажность циклически накапливается в архиве из 6 значений. Если текущая влажность выше первой из архива более чем на 3% либо абсолютное значение влажности выше 85%, значит нужно включать вентилятор.
Вентилятор включается на 20 минут при отсутствии света на фоторезисторе.
Кнопка принудительно включает вентилятор на 20 минут (если он не работает) или выключает (если работает).
Все константы в алгоритме подбирались эксперементальным путем.

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

Полностью логику работы прибора можно описать конечным детерменированным автоматом.
Входной алфавит автомата состоит из следующих событий (в порядке приоритетов):
  • нажата кнопка ручного режима;
  • сработал датчик влажности;
  • горит свет;
  • не горит свет;
  • сработал таймер работы вентилятора.


Множество состояний:
  1. режим ожидания, вентилятор не работает, тайме отключен;
  2. требуется включение вентилятора, вентилятор не работает, таймер (при)остановлен;
  3. вентилятор работает в автоматическом режиме, таймер включен;
  4. вентилятор работает в ручном режиме, таймер включен;


Ну и таблица переходов состояний автомата:


Программирование


AVR-studio и прочих монстров я устанавливать не стал, а обошелся опять же тем, что было — IDE Arduino.

Создаю в файле board.txt новый контроллер, работающий на внутреннем кварце 8МГц:

atmega328_8.name=Atmega328 (5V, 8 MHz internal)

atmega328_8.upload.protocol=arduino
atmega328_8.upload.maximum_size=30720
atmega328_8.upload.speed=57600

atmega328_8.bootloader.low_fuses=0xE2
atmega328_8.bootloader.high_fuses=0xDE
atmega328_8.bootloader.extended_fuses=0x05
atmega328_8.bootloader.path=optiboot
atmega328_8.bootloader.file=optiboot_atmega328.hex
atmega328_8.bootloader.unlock_bits=0x3F
atmega328_8.bootloader.lock_bits=0x0F

atmega328_8.build.mcu=atmega328p
atmega328_8.build.f_cpu=8000000L
atmega328_8.build.core=arduino
atmega328_8.build.variant=standard


Подключаю дешевый программатор USBASP к ISCP разъему платы Arduino UNO и, вставив в панельку свой Atmega328P, прошиваю загрузчик.

Теперь мой микроконтроллер можно отлаживать и программировать через стандартный загрузчик на плате UNO, выбрав в среде соответствующую плату.

В данном проекте использовались готовые библиотеки для Arduino:



Полный код скетча
#include <DHT.h>
#include <SevenSegmentDisplay.h>



#define DEBUG        1
#define TIMER_PERIOD 2400

#define ctrPIN   13 //Дискретный вывод для вентелятора
#define dhtPIN   15 //Дискретный вход для датчика температуры
#define btnPIN   18 //Кнопка

// Указатель на функцию перезагрузки контроллера
void(* resetFunc) (void) = 0; // Reset MC function

// Инициируем светодиодную матрицу
SevenSegmentDisplay<true, BiDigit<17, 16> > ss(4, 9, 8, 6, 7, 5, 2, 3);

// Инициируем DHT11 на контроллере с частотой 8МГц
DHT dht(dhtPIN, DHT11, 3);// 8Мгц
//DHT dht(dhtPIN, DHT11); //16МГц

// Состояния FSM
enum TMode
  {
  tmWait,       //Режим ожидания
  tmNeedPower,  //Требуется включение вентилятора
  tmAutoPower,  //Вентилятор работает в автоматическом режиме
  tmManualPower //Вентилятор работает в ручном режиме
};
  
// Состояния отображения
enum TDisplayMode
  {
  tdmTemp       , //Отображение температуры
  tdmHum        , //Отображение влажности
  tdmTimer        //Отображение таймера  
};
  
  
//int h_prev;
int t,h,a0;

int h_arr[6];



void setup()
{
// Инициируем порт отладки
#ifdef DEBUG
    Serial.begin(9600);
    Serial.println("Humidity controller start ...");
#endif
// Инициируем выход управления 
    pinMode(ctrPIN, OUTPUT); // будем мигать лампочкой при передаче
    digitalWrite(ctrPIN, LOW); 
// Инициируем вход с кнопкой
    pinMode(btnPIN, INPUT);     
//Включаем подтягивающий резистор    
    digitalWrite(btnPIN, HIGH); 

    
// Инициируем датчик температуры DHT11    
    dht.begin();
// Считываем первоначальное значение влажности
    h = dht.readHumidity();
    for( int i=0; i<6; i++)h_arr[i] = h;

}

// Счетчик 0.5 секудных тактов
unsigned long cnt05 = 0;
unsigned long ms1   = 0;
// Флаг включения света
boolean flag_light = false;
// Флаг нажатия кнопки
boolean flag_btn   = false;
// Флаг влажерсти
boolean flag_hum   = false;
// Считчик таймера работы вентилятора
unsigned int timer = 0;
TMode mode         = tmWait;
TDisplayMode dmode = tdmTemp;
boolean blink_stat = false;   

void loop ()
{ 
   unsigned long ms = millis();
   int p = ms - ms1;

// Считываем состояние кнопки
   
   if( digitalRead(btnPIN) == LOW ){
      int n = 1;
      for( int i=0; i<9; i++ ){
         if( digitalRead(btnPIN) == LOW )n++;
         delay(10);
      }
      if( n > 9 )flag_btn = true;   
      delay(400);
#ifdef DEBUG
      Serial.println("Button is press");
#endif
   }//end if     

// Проверка, что прошло не менее 0.5 сек
   if( p < 0 || p > 500 ){
      cnt05++;
      ms1 = ms;
// Считываем состояние фоторезистора
      a0 = analogRead(A0);
      if( a0 > 1000 )flag_light = false;
      else flag_light = true;
// Каждые 10 секунд опрашиваем датчик DHT11 и меняем отображение дисплея     
      if( cnt05%20 == 0 ){    
         h = dht.readHumidity();
         t = dht.readTemperature();
// Если влажность изменилась на 3% или влажность превысила 85%   
         
         if( h - h_arr[5] > 3 || h > 85 )flag_hum = true;
// Исправлена ошибка из предыдущей версии
         for( int i=5; i>0; i--)h_arr[i] = h_arr[i-1];
         h_arr[0] = h;
#ifdef DEBUG
         Serial.print("VAL: Temp=");
         Serial.print(t);
         Serial.print(" H=");
         Serial.print(h);
         Serial.print(" A0=");
         Serial.print(a0);
         Serial.print(" X=");
         Serial.print(cnt05);
         Serial.print(" TM=");
         Serial.print(timer);
         Serial.print(" MODE=");
         Serial.print(mode);
         Serial.print(" DMODE=");
         Serial.print(dmode);
         Serial.println("");
#endif
// Переключаем дисплей
         switch( dmode ){
            case tdmTemp : dmode = tdmHum; break;
            case tdmHum  : dmode = tdmTimer; break;
            default:       dmode = tdmTemp;
         }//end switch
      }//end if( cnt05%20 == 0 )   
      blink_stat = !blink_stat;
      SetStatusFSM(); 
   }//end if( p < 0 || p > 500 ){   
   DisplayStatus(); 

}//end loop()     

/**
* Функция отображение разных параметров
*/
void DisplayStatus(){
// Настройка отображения режима в    
   int point = -1;
   switch( mode ){
      case tmNeedPower:
         point = 0;
         break;
      case tmAutoPower:
      case tmManualPower:
         if( blink_stat )point = 0;
         break;   
   }  
   switch( dmode ){
      case tdmTemp :
         ss.print((unsigned)t,point,50);
         break;
      case tdmHum  :
         ss.print((unsigned)h,point,50);
         break;
      case tdmTimer:
// Показываем минуты      
         if( timer > 120 )ss.print((unsigned)(timer/120),point,50);
// Показываем секунды
         else if( timer > 0 )ss.print((unsigned)(timer/2),point,50);
// Показываем 0
         else ss.print(0,point,50);    
//         ss.print((unsigned)(a0/100),point,50);
         break;
   }//end switch
   
}


/**
* Функция перехода автомата состояний
*/
void SetStatusFSM(){
   switch(mode){
// Режим ожидания     
      case tmWait :
         digitalWrite(ctrPIN, LOW);
// Нажата кнопка      
         if( flag_btn ){
            timer = TIMER_PERIOD;
            mode  = tmManualPower;
         }
// Если сработал датчик влажности
         else if( flag_hum ){
            timer = TIMER_PERIOD;
            mode  = tmNeedPower;
         }   
         break;
// Состояние ожилания работы вентилятора
      case tmNeedPower:
         digitalWrite(ctrPIN, LOW);
// Нажата кнопка      
         if( flag_btn ){
            mode  = tmManualPower;
         }
// Свет выключен
         else if( !flag_light ){
            mode  = tmAutoPower;
         }
         break;
// Состояние "Вентилятор работает в автомате"
      case tmAutoPower:
// Включить вентилятор
         digitalWrite(ctrPIN, HIGH);
// Таймер считает
         if( timer > 0 )timer--;
// Нажата кнопка      
         if( flag_btn ){
            mode  = tmWait;
            timer = 0;
         }
// Включился чвет      
         else if( flag_light ){
            mode  = tmNeedPower;
         }
// Таймер сработал
         else if( timer <= 0 ){
            timer = 0;
            mode  = tmWait;
         }
         break;
// Состояние "Вентилятор работает в ручном режиме"
      case tmManualPower:
// Включить вентилятор
         digitalWrite(ctrPIN, HIGH);
// Таймер считает
         if( timer > 0 )timer--;
// Нажата кнопка      
         if( flag_btn ){
            mode  = tmWait;
            timer = 0;
         }
// Таймер сработал
         else if( timer <= 0 ){
            timer = 0;
            mode  = tmWait;
         }
         break;
   } 
// Сбросить флани кнопка и влажность   
   flag_btn = false;
   flag_hum = false;

}




Проблемы



Первой проблемой, с которой столкнулся в реализации — не работал датчик DHT11. На Arduino UNO все нормально, а на голом микроконтроллер не работает. Проблема оказалась в частоте работы контроллера и таймингам протокола опроса DHT.
В контроллерах, работающих на частоте 8МГц в библиотеке DHT нужно обязательно указывать задержку «3» (третий параметр в конструкторе класса) DHT dht(dhtPIN, DHT11, 3);

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

Готовое устройство выглядит так:


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

Список полезных ссылок:


Все статьи мои статьи можно найти в моем блоге samopal.pro
Поделиться публикацией
Похожие публикации
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 25
    +2
    Решение, как поле для роста и дальнейшей автоматизации интересное, но громоздкое, да и незащищенная электроника в ванной — не лучший вариант, на мой взгляд.
    Я тоже задумывался на этот счет, но остановился на готовых решения данного вопроса, абсолютно сравнимых по цене, вот, например что подсказал гугль: вентилятор со встроенным датчиком, отдельный датчик, есть с датчиками присутствия и даже с закрывающимися жалюзями и индикацией. Плюс все это гораздо эстетичнее выглядит.
      0
      Согласен, готовое решение эстетичнее и надежнее. Если бы сейчас начинал с нуля, наверное бы и выбрал чего-нибудь готовое.
      Единственное, чего не увидел в готовых контроллерах — это алгоритма управления по скорости изменения влажности. Или по разности вне ванной и внутри.
      Ведь влажность в квартире может меняться и хотелось бы, чтобы вентилятор начинал работать при повышении влажности, а не по достижению фиксированного значения.
        –1
        Подскажите, готовые решения. Или хотя бы ключевое слово для поиска. Спасибо
        +1
        «незащищенная электроника в ванной» — защищается УЗО :) Но я бы выбрал всё таки 12-ти вольтовый вентилятор.

        По теме:
        «ОСТОРОЖНО, на корпусе симистора напряжение 220В» — у автора. До 60 вт можно использовать BT168 в TO-92 корпусе. А ещё проще — реле, чтобы не заморачиваться. Пятивольтовые мелкие релюшки ардуина щёлкает.
        И ещё дополню — газовые анализаторы не должны включать вентиляторы с щетками во избежание искр и кнопок там тоже нет.
        А так интересно, главное работает, мне тоже скоро нужен будет подобный агрегат, под крышей влажность понижать.
          0
          Про УЗО — согласен, но до него, думаю, не дойдет, если представить критическую ситуацию, то до КЗ и т.п. вся електроника тихонько выгорит и выключится, влажная среда и постояный ток дает все карты на электролиз.
          Про BT168 — тоже согласен, я ВТ151 на диммер в люстру вешал.
          Про пятивольтовые релюшки — я бы все равно вешал их через ULN2804 (К1109КТ23) или минимум необходимо ставить диод в обратку чтобы выходы порта потом по всему корпусу не собирать.
            0
            Что значит до узо не дойдет? С нормальным узо можно хвататься за провода (проверено соседом), ничего не будет. Единственное, что может случиться это убийство чипа, если коротнет на него, но до возгорания не дойдет — утечка сразу вызовет отключение узо.
              0
              Ну да, я про это и говорю, что еще до того, как у УЗО будет повод стрельнуть выгорят порты меги, оптрон может дать дуба, DC-DC конвертор уплывет и тп. Если бы была полная ардуина, то там диод Шоттки пустил бы дым или стабилизатор, при перегрузе на платах драйвер LED-ленты выгорит. А УЗО стрельнет, скорее всего, аж тогда когда на семистор капля ляжет, да и то, скорее всего, эта капля выведет из строя оптопару и пожжет резисторы ограничительные.
                0
                УЗО сработает если вы схватитесь на фазу и ток пойдет в заземление. А если схватитесь за фазу а ток пойдет через нейтраль — УЗО не сработает, т.к. не посчитает этот ток утечкой. Не стоит всю защиту от поражения током спихивать на УЗО, если вы к примеру пальцы в розетку сунете УЗО не сработает.
              0
              А нету таких симисторов ватт на 50-100, чтобы в изолированном корпусе и сразу же с опто-развязкой?
              0
              Я пытался найти 12 вольтовый вентилятор для ванной и не нашел. Разве что из автомобильного колхозить самостоятельно.
            0
            В качестве источника питания подошел LED driver 3x1вт от светильника, который вполне справился с питанием импульсного стабилизатора LM2596.
            Это какое-то весьма странное колдунство.

            С одной стороны плюс — коробочка led-драйвера герметичная, и высоковольтная часть преобразователя защищена от влаги.
            С другой — там рядом открытая цепь симистора, где тоже постоянно 220.
              0
              Стоило конечно взять вентилятор на 12 вольт
                0
                А где же его взять за разумные деньги?
                Не компьютерный же ставить
                  0
                  можно мне чуть-чуть ликбеза, пжл… А почему комповый бы не подошёл и какой вы имеете в виду, как лучший вариант?

                  *мне просто как раз сейчас нужно проблемку одну решить. Помочь конвекции, так сказать.
                    0
                    Мне кажется, что у «компьютерного» вентилятора просто производительность гораздо ниже — 100-300 м3/ч вентилятора ванной против 30-80 м3/ч куллеров комп.корпусов.
                      0
                      У компьютерного меньше размеры (толщина), меньше мощность и, соответственно, производительность.
                      Еще компьютерные не имеют креплений на трубу и к прочим аксессуарам вентиляции.
                        0
                        Компьютерный не способен развивать приличное давление, они предназначены для работы в условиях, когда сопротивление воздуха низкое. В компьютерном корпусе он обеспечит свои заявленные кубометры в час, а если поставить в вентиляционную трубу, то он мало что сможет выжать.
                          0
                          220-вольтные тоже не обеспечивают. Хоть и мощность больше, но они тоже слабо держат давление. Для того чтобы давление качать, нужны другие лопасти.
                  0
                  Казалось бы чего проще, подключил его к выключателю света и готово. Но, время работы света непостоянно и может быть недостаточно для уменьшения влажности, хотя данную проблему можно решить установкой таймера. К тому же, моим близким очень не нравится работающий вентилятор при принятии водных процедур, так как он «создает холодный ветер».

                  Можно было сделать включение вентилятора при выключении света, и отключение вентилятора по таймеру. Кажется все ваши начальные требования покрывает.

                  Хотя у вас получилось интереснее.
                    0
                    Зато сколько узнал и научился!
                    0
                    У меня вентилятор в ванной включается если свет горит больше 5 минут, и крутит еще 20 минут после отключения оного. А проблема сквозняка решается уменьшением оборотов когда включен свет, и 100% когда он выключен. Правда, эти вентиляторам нужна какая-то минимальная активная нагрузка чтобы симистор смог регулировать мощность на них, просто чудом подобрал экспериментально диапазон когда обороты вентилятора меняются от 0 до 100% и он составлял примерно 16 единиц из примерно 70 тиков таймера за полупериод, симистор ВТ131 более мощные вентилятор просто «не чувствуют» как нагрузку.
                      0
                      Тоже на самодельном контроллере?

                      У меня все плохо получилось с регулированием скорости вентилятора.
                      Мотор там асинхронный, при снижении мощности симистором начинает гудеть. Есть опасность остановки (если пылью забъется) и сгорания обмотки.
                      Думаю, что нужно применять многообмоточный с несколькими скоростями, либо постоянного тока, как советовали выше.
                      Осталось найти такие по адекватной цене
                        0
                        На половине мощности он еще сможет крутить и не гудеть, а если забъется настолько что с половиной мощности не сможет крутить — то его уже давно надо бы заменить, перед этим он будет сильно гудеть из-за сношенных подшипников.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое