Управление вентилятором в санузле
- Войдите на сайт для отправки комментариев
Купил ребёнку ArduinoUNO но у него как то не покатило, зато я заинтересовался. И так как осваивать для меня проще применительно к чему то, я придумал себе следующую задачу:
1. Управление двумя скоростями вентилятора санузла
2. Алгоритм в туалете: включился свет, через минуту включается первая скорость (предпологается что человек зашёл по большому), после выключения света включается вторая скорость для интенсивного проветривания
3. Алгоритм в ванной: при повышении влажности включается первая скорость, если начинается парилка включается вторая скорость
4. Алгоритм забытый свет: если в ванной или туалете забыли выключить свет то через 40 минут начинает работать пищалка, которая с паузами обращает внимание на невыключенный свет.
Для этой задачи я собрал схему:
И написал скейтч. Хотелось бы услышать коментарии, указания на ошибки и предложения по улучшению. Схему пока собрал только на мактке. Вместо реле светодиоды для наглядности. Пока не смог проверить только работу датчика влажности, его надо нести в ванную.
#include <MsTimer2.h>
#include <iarduino_DHT.h> // подключаем библиотеку для работы с датчиком DHT
iarduino_DHT sensor(2); // объявляем переменную для работы с датчиком DHT,
//указывая номер цифрового вывода к которому подключён датчик (сейчас 2pin)
byte RELE_1 = 10; //определение вывода реле медленная скорость
byte RELE_2 = 11; //определение вывода реле быстрая скорость
byte ZUMMER = 6; //определение вывода на сигнал не выключеного света
byte FOTO_1 = A0; //определение ввода датчика света туалета
byte FOTO_2 = A1; //определение ввода датчика света ванной
boolean sensor_1_sw = false;//переменная для состояния датчика влажности медленная скорость
boolean sensor_2_sw = false;//переменная для состояния датчика влажности быстрая скорость
boolean foto_1_sw = false; //переменная для состояния фоторезистора медленной скорости
boolean foto_2_sw = false; //переменная для состояния фоторезистора быстрой скорости
boolean rele_1_sw = false; //переменная для реле включения медленной скорости
boolean rele_2_sw = false; //переменная для реле включения быстрой скорости
boolean foto_off = false; //переменная для реле включения быстрой скорости после выключения света в туалете
int foto_1 = 0; //переменная для фоторезистора туалета
int foto_2 = 0; //переменная для фоторезистора ванной
int foto_1_time = 0; //переменная для счётчика времени фоторезистора туалета
int foto_off_time = 0; //переменная для счётчика времени после выключения фоторезистора туалета
int foto_2_time = 0; //переменная для счётчика времени фоторезистора ванной
int fLevel = 950; //уровень фоторезистора: меньше-темно, больше-светло
int time_on_1 = 60; //время ожидания, до включения медленной скорости, после включения света в туалете
int time_on_2 = 60; //время работы быстрой скорости после выключения света в туалете
int time_zummer = 2400; //время до включения зуммера после включения света в ванной или туалете
int zummer_pausa = 120; //время между сигналами зуммера
int hum_low = 60; //уровень влажности для включения первой скорости
int hum_hi = 80; //уровень влажности для включения второй скорости
void setup() {
pinMode (RELE_1, OUTPUT); //объявляем пин как выход на реле медленной скорости
pinMode (RELE_2, OUTPUT); //объявляем пин как выход на реле быстрой скорости
pinMode (ZUMMER, OUTPUT); //объявляем пин как выход на зуммер
pinMode (FOTO_1, INPUT); //объявляем пин как вход фоторезистора туалета
pinMode (FOTO_2, INPUT); //объявляем пин как вход фоторезистора ванной
}
void loop() {
if(sensor.read()==DHT_OK){ // читаем и обробатываем показания датчика влажности
if (sensor.hum>hum_low){
sensor_1_sw=true;}
else {
sensor_1_sw=false;
}
if (sensor.hum>hum_hi){
sensor_2_sw=true;}
else {
sensor_2_sw=false;}
} // заканчиваем читать и обробатывать показания датчика влажности
if (foto_1_time>time_on_1 -1 && analogRead(FOTO_1)<fLevel){ //блок включения второй скорости после выключения света в туалета
foto_off=true;} //если включался вентилятор от фоторезистора туалета
if (foto_off==true){
if (foto_off_time<time_on_2){
foto_2_sw=true;
foto_off_time++;}
else{
foto_2_sw=false;
foto_off=false;
foto_off_time=0;
}
} // заканчиваем блок включения второй скорости
if (analogRead(FOTO_1)>fLevel){ // считываем значение фоторезистора туалета
foto_1_time++; //в случае включения света начинаем считть время
}
else{foto_1_time=0;
}
if (foto_1_time>time_on_1){ //время ожидания до включения медленной скорости
foto_1_sw=true;
foto_1_time--;
}
else{foto_1_sw=false;
}
//управление зуммером
if (analogRead(FOTO_1)>fLevel || analogRead(FOTO_2)>fLevel){ // считываем значение фоторезистора ванной
foto_2_time++;
if (foto_2_time==time_zummer){ //время ожидания до включения зуммера
analogWrite(ZUMMER, 50); // включаем зуммер
delay(500); //время на которое включается зуммер
analogWrite(ZUMMER, 0); // выключаем зуммер
foto_2_time=foto_2_time - zummer_pausa; //пауза между сигналами
}
}
else{foto_2_time=0;
}
if (sensor_1_sw==true || foto_1_sw== true){ //включаем первую скорость
digitalWrite(RELE_1, HIGH );
}
else{
digitalWrite(RELE_1, LOW); //выключаем первую скорость
}
if (sensor_2_sw==true || foto_2_sw== true){ //включаем вторую скорость
digitalWrite(RELE_2, HIGH );
}
else{
digitalWrite(RELE_2, LOW); //выключаем вторую скорость
}
delay (1000); //задержка 1 секунда
}

Как успехи, вы свой проект реализовали? Как у вас используются разные скорости вентилятора, разные обмотки, или через диод или трансформатор?
У меня есть несколько замечаний/предложений
1. реле на выход ардуины вешать не стоит, и пин может сдохнуть от перегрузки, а если нет то выброс реле убьет. через транзистор с защитным диодом параллельно катушке реле
2. возле реле с транзистором поставить электролит с керамикой по питанию, на всякий случай
3. ну и защита от влаги само собой
Пока не реализовал. Сначала ждал блок реле. Теперь пытаюсь найти доступный по цене вентилятор с двумя скоростями. Через диод или трансформатор боюсь что довольно быстро выйдет из строя.
Спасибо за совет.
С реле уже понял и купил блок реле, у него отдельное питание и упраляется сигналом. С влагозащитой сильно заморачиваться не буду т.к. управление будет стоять в туалете а там влаги не очень много.
Сейчас пытаюсь найти подходящий вентилятор с двумя скоростями.
зачем двухскоростной? обычный вентилятор вполне себе диммируется, правда гадить помехами может, можно испльзовать симистр с зеро кросс и дкржать включенным например 0.3 секунды из 1 сек, так же здесь где-то были проекты с фазоимпульсным управлением, либо еще есть диммеры с фазовым управлением и испльзовать его.
0.47 микрофарады на 250 (и больше) Вольт переменки (и именно Х2)
прекрасно снижают обороты подобного вентилятора.
https://www.google.ru/search?q=%D0%BA%D0%BE%D0%BD%D0%B4%D0%B5%D0%BD%D1%8...
Ну вот наконец то я доделал свой проект. Он конечно ещё в обкатке, но работет в полне как я ожидал.
Схема относительно начальной поменялась:
1. Вместо датчика влажности DHT поставил датчик SI7021. Он работает в разы быстрее и нет такой инертности.
2. Добавил кнопку для ручного включения.
3. Добавил сервопривод регулирующий заслонку забора воздуха из туалета (при боьшой влажности заслонка закрывает забор из туалета полностью)
В алгоритме действий добавилось управление заслонкой, там всё просто - чем больше влажность в ванной тем больше закрыта заслонка в туалете. Кнопка включает вентилятор на вторую скорость на 2 минуты, повторное нажатие в этот период выключает вентилятор.
В процессе отладки выяснилось что датчик может показывать влажность больше 100% и после этого ООчень долго отходит. Поэтому при достижении 100% включается внутренний обогреватель датчика. Библиатеку для датчика брал эту https://github.com/enjoyneering/HTU21D
Скейтч частично понадёрган из примеров, но я постарался коментарии дать максимально понятные.
Ну и естественно жду коментариев.
#include <Wire.h> //подключем библиатеку необходимую для работы с датчиком влажности #include "HTU21D.h" //подключаем библиотеку для работы с датчиком влажности #include <Servo.h> //подключаем библиотеку для работы с сервоприводом HTU21D myHumidity; // объявляем переменную для работы с датчиком SI7021 Servo myServo; //создаём объект серво // ОПРЕДЕЛЕНИЕ ПЕРЕМЕННЫХ ДЛЯ ВВОДОВ И ВЫВОДОВ byte RELE_1 = 10; //определение вывода реле медленная скорость byte RELE_2 = 11; //определение вывода реле быстрая скорость byte ZUMMER = 6; //определение вывода на сигнал не выключеного света byte FOTO_1 = A0; //определение ввода датчика света туалета byte FOTO_2 = A1; //определение ввода датчика света ванной byte BUTTON_PIN = 4; //определение ввода с кнопки byte SERVO_PIN = 9; //определение вывода на серво // ОПРЕДЕЛЕНИЕ ПЕРЕМЕННЫХ, ПРИСВОЕНИЕ ИМ НАЧАЛЬНЫХ ЗНАЧЕНИЙ boolean sensor_1_sw = false;//переменная для состояния датчика влажности медленная скорость boolean sensor_2_sw = false;//переменная для состояния датчика влажности быстрая скорость boolean foto_1_sw = false; //переменная для состояния фоторезистора медленной скорости boolean foto_2_sw = false; //переменная для состояния фоторезистора быстрой скорости boolean rele_1_sw = false; //переменная для реле включения медленной скорости boolean rele_2_sw = false; //переменная для реле включения быстрой скорости boolean foto_off = false; //переменная для реле включения быстрой скорости после выключения света в туалете int foto_1 = 0; //переменная для фоторезистора туалета int foto_2 = 0; //переменная для фоторезистора ванной int foto_1_time = 0; //переменная для счётчика времени фоторезистора туалета int foto_off_time = 0; //переменная для счётчика времени после выключения фоторезистора туалета int foto_2_time = 0; //переменная для счётчика времени фоторезистора ванной int time_delay = 1000; //переменная задержки программы в милисекундах int fLevel = 600; //уровень фоторезистора: меньше-темно, больше-светло int time_on_1 = 120; //время ожидания, до включения медленной скорости, после включения света в туалете (* time_delay) int time_on_2 = 180; //время работы быстрой скорости после выключения света в туалете или нажатия кнопки (* time_delay)300 int time_zummer = 1800; //время до включения зуммера после включения света в ванной или туалете (* time_delay) int zummer_pausa = 60; //время между сигналами зуммера (* time_delay) int hum_low = 60; //уровень влажности для включения первой скорости int hum_hi = 90; //уровень влажности для включения второй скорости int humd = 0; //переменнная влажности int button_time = 0; //переменная для счётчика времени работы вентилятора от кнопки int angle = 0; //переменная угла сервопривода // ОБРАБОТКА КНОПКИ boolean flagPress = false; // признак кнопка в нажатом состоянии boolean flagClick = false; // признак нажатия кнопки (фронт) boolean button_state = false; // признак кнопки - включает или выключает вентилятр byte buttonCount= 0; // счетчик подтверждений состояния кнопки #define TIME_BUTTON 1 // время устойчивого состояния кнопки (* time_delay) // ДЛЯ МЕЛОДИИ const int songLength = 9 ; char notes[] = "cdfda ag "; int beats[] = {1,1,1,1,1,1,4,4,2}; int tempo = 120; // ОБЪЯВЛЕНИЕ ПИНОВ КАК ВХОД ИЛИ ВЫХОД void setup() { pinMode (RELE_1, OUTPUT); //объявляем пин как выход на реле медленной скорости pinMode (RELE_2, OUTPUT); //объявляем пин как выход на реле быстрой скорости pinMode (ZUMMER, OUTPUT); //объявляем пин как выход на зуммер pinMode (FOTO_1, INPUT); //объявляем пин как вход фоторезистора туалета pinMode (FOTO_2, INPUT); //объявляем пин как вход фоторезистора ванной pinMode (BUTTON_PIN, INPUT_PULLUP);//объявляем пин как вход кнопки с внутренней подтяжкой myServo.attach(SERVO_PIN); //подсоеденяем переменную myServo к пину servo_pin Serial.begin(9600); //инициализируем COM порт myHumidity.begin(); //инициализируем порт датчика влажности } void loop() { humd = myHumidity.readHumidity(); //чтение показаний датчика влажности // ВЫВОД ДАННЫХ НА COM ПОРТ Serial.println((String) "Vlaznost: " + humd + "%"); Serial.println((String) "Tualet: " + analogRead(FOTO_1) + " / time: " + foto_1_time + " / time after shutdown: " + foto_off_time ); Serial.println((String) "Vanna: " + analogRead(FOTO_2) + " / time: " + foto_2_time); Serial.println((String) "Buuton: " + digitalRead(BUTTON_PIN)+ " /state: " + button_state + " /time: " + button_time); Serial.println((String) "Angle: " + angle); Serial.println((String) "==================="); // УПРАВЛЕНИЕ СЕРВО if ( humd < 100 ){ angle = humd ; //если влажность меньше ста то присваиваем углу уровень влажности myServo.write(angle); //устанавливаем серво на угол = humd myHumidity.setHeater(HTU21D_OFF); } else { angle = 100; //если влажность боьше ста то присваиваем угл 100 myHumidity.setHeater(HTU21D_ON); } // БЛОК ОБРАБОТКИ СИГНАЛА КНОПКИ /* при нажатой кнопке flagPress= true * при отжатой кнопке flagPress= false * при нажатии на кнопку flagClick= true */ if ( flagPress == (! digitalRead(BUTTON_PIN)) ) { // признак flagPress = текущему состоянию кнопки // (инверсия т.к. активное состояние кнопки LOW) // т.е. состояние кнопки осталось прежним buttonCount= 0; // сброс счетчика подтверждений состояния кнопки } else { // признак flagPress не = текущему состоянию кнопки - состояние кнопки изменилось buttonCount++; // +1 к счетчику состояния кнопки if ( buttonCount >= TIME_BUTTON ) { // состояние кнопки не мянялось в течение заданного времени // состояние кнопки стало устойчивым flagPress= ! flagPress; // инверсия признака состояния buttonCount= 0; // сброс счетчика подтверждений состояния кнопки if ( flagPress == true ) flagClick= true; // признак фронта кнопки на нажатие } } // БЛОК УПРАВЛЕНИЯ СИГНАЛОМ ДЛЯ РЕЛЕ ОТ КНОПКИ if ( flagClick == true ) { // было нажатие кнопки flagClick = false; // сброс признака фронта кнопки button_state = ! button_state; // инверсия состояния признака кнопки (включает или вЫключает) } if (button_state == true && button_time < time_on_2) { button_time ++; } else { button_state = false; button_time = 0; } // ЧИТАЕМ И ОБРОБАТЫВАЕМ ПОКАЗАНИЯ ДАТЧИКА ВЛАЖНОСТИ if(humd != 255){ if (humd > hum_low){ sensor_1_sw = true;} else { sensor_1_sw = false; } if (humd > hum_hi){ sensor_2_sw = true;} else { sensor_2_sw = false;} } // заканчиваем читать и обробатывать показания датчика влажности // БЛОК ВКЛЮЧЕНИЯ ВТОРОЙ СКОРОСТИ ПОСЛЕ ВЫКЛЮЧЕНИЯ СВЕТА В ТУАЛЕТА // если включался вен��илятор от фоторезистора туалета if (foto_1_time > time_on_1 -1 && analogRead(FOTO_1)<fLevel){ foto_off = true;} if (foto_off == true){ if (foto_off_time < time_on_2){ foto_2_sw = true; foto_off_time++;} else{ foto_2_sw = false; foto_off = false; foto_off_time = 0; } } // заканчиваем блок включения второй скорости // ОБРАБАТЫВАЕМ СИГНАЛ ФОТОРЕЗИСТОРА ТУАЛЕТА if (analogRead(FOTO_1) > fLevel){ // считываем значение фоторезистора туалета foto_1_time++; //в случае включения света начинаем считть время } else{foto_1_time = 0; } if (foto_1_time > time_on_1){ //время ожидания до включения медленной скорости foto_1_sw = true; foto_1_time--; } else{foto_1_sw = false; } if (sensor_1_sw==true || foto_1_sw== true){ //включаем первую скорость if (foto_2_sw==false){ digitalWrite(RELE_1, LOW ); } } else{ digitalWrite(RELE_1, HIGH); //вЫключаем первую скорость } if (sensor_2_sw==true || foto_2_sw== true || button_state == true){ //включаем вторую скорость digitalWrite(RELE_1, HIGH); //вЫключаем первую скорость перед включением второй digitalWrite(RELE_2, LOW ); } else{ digitalWrite(RELE_2, HIGH); //вЫключаем вторую скорость } // УПРАВЛЕНИЕ ЗУММЕРОМ if (analogRead(FOTO_1) > fLevel || analogRead(FOTO_2) > fLevel){ // считываем значение фоторезистора ванной foto_2_time++; if (foto_2_time == time_zummer){ //время ожидания до включения зуммера // МЕЛОДИЯ int i, duration; for (i = 0; i < songLength; i++){ // пошаговое воспроизведениеиз массива duration = beats[i] * tempo; // длительность нот/пауз в ms if (notes[i] == ' '){ // если нота отсутствует? delay(duration); // тогда не большая пауза } else{ // в противном случае играть tone(ZUMMER, frequency(notes[i]), duration); delay(duration); // ждать пока проигрывается } delay(tempo/10); // маленькая пауза между нотами } // конец мелодии foto_2_time=foto_2_time - zummer_pausa; //пауза между сигналами } } else{foto_2_time=0; } // заканчиваем управление зуммером delay (time_delay); //задержка } // ЗАДАЁМ НОТЫ int frequency(char note) { // Эта функция принимает символ ноты (a-g), и возвращает // частоту в Гц для функции tone(). int i; const int numNotes = 8; // количество хранимых нот // Следующие массивы содержат символы нот и соответствующие им // частоты. Последний символ "C" (нота "ДО") в верхнем регистре // (большая), это сделано для того чтобы отличить ее от первой // ноты "с", более низкого тона. Если вы хотите добавить больше // нот, вы должны будете использовать уникальный символ для // каждой новой ноты. // Каждый "char" (символ), мы заключаем в одинарные кавычки. char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' }; int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523}; // Теперь мы будем искать во всем массиве, символ ноты и если // находим, возвращаем частоту для этой ноты. for (i = 0; i < numNotes; i++) // пошаговый перебор нот { if (names[i] == note) // если находим { return(frequencies[i]); // возвращаем частоту } } return(0); // Поиск символа не дал результата? Но, необходимо // вернуть какое-то значение, так вернем 0. }Привет! Вылазит вот такая ошибка:
Что надо исправить?
дак вроде же всё исчерпывающе на родном написано: 'HTU21D_OFF' was not declared in this scope.
А происходить так может из-за этого: E:\Arduino\Реле времени для сортира\
А происходить так может из-за этого: E:\Arduino\Реле времени для сортира\
Видимо причина в другом:
Как бы надеялся, что раз тема находится в "Проектах", то с повторением проекта не долно быть проблем...
У Вас случайно имя дериктории не русскими написан? Если да, то попробуйте изменить на латиницу.
Так сменил уже: D:\Sortir1\Sortir1.ino:
Я так понял 'HTU21D_ON' и 'HTU21D_OFF' не объявлены в программе...
Вы код используемых библиотек
#include "HTU21D.h"подложите в пост, они у Вас в папке со скетчемслучайно грохнул пост sadman-а О_О Верните ктонить, я просто процитировать хотел, да нажал не туда спьяну. :(
если enum обычный, он свободно передается в любую функцию ожидающую int.
А если он объявлен как enum class, тогда функцию надо писать, принимающую конкретно этот тип enum-а. Или делать int-у static_cast<>.
В самом верху есть ссылка на библиотеку.
если enum обычный, он свободно передается в любую функцию ожидающую int.
А если он объявлен как enum class, тогда функцию надо писать, принимающую конкретно этот тип enum-а. Или делать int-у static_cast<>.
Там история такая:
typedef enum : uint8_t { HTU21D_ON = 0x04, //heater ON HTU21D_OFF = 0xFB //heater OFF } HTU21D_HEATER_SWITCH; .... void HTU21D::setHeater(HTU21D_HEATER_SWITCH heaterSwitch) { }Там история такая:
typedef enum : uint8_t { HTU21D_ON = 0x04, //heater ON HTU21D_OFF = 0xFB //heater OFF } HTU21D_HEATER_SWITCH; .... void HTU21D::setHeater(HTU21D_HEATER_SWITCH heaterSwitch) { }Ну я чесноговоря такое обьявление в первый раз вижу.
тогда надо, наерна, передавать как HTU21D_HEATER_SWITCH::HTU21D_ON или HTU21D_HEATER_SWITCH::HTU21D_OFF.
хотя уточнение видимости (операция ::) к typedef вообще не должна относиться, только к enum class.
ХЗ, короче, надо у экспертов спрашивать, а не у алкашей всяких.
Вы код используемых библиотек
#include "HTU21D.h"подложите в пост, они у Вас в папке со скетчемСпасибо за помощь! Перекинул библиотеку "HTU21D" из папки C:\Users\...\Documents\Arduino\libraries в папку D:\arduino-1.8.7-windows\arduino-1.8.7\libraries и все скомпилировалось.!
Да, странная библиотека!
Если положить в папку скетча так как объявлена как локальная -#include "HTU21D.h"
не компилируется, а если положить в папку библиотек программы - компилируется
Изменил инклуд на #include <HTU21D.h> и перенес в папку библиотек ардуиновских скетчей, тоже компилируется
Да, странная библиотека!
Если положить в папку скетча так как объявлена как локальная -#include "HTU21D.h"
не компилируется, а если положить в папку библиотек программы - компилируется
Изменил инклуд на #include <HTU21D.h> и перенес в папку библиотек ардуиновских скетчей, тоже компилируется
Так и есть! Спасибо! Объявил библиотеку, как локальную #include "HTU21D.h". Кинул в папку со скетчем HTU21D.cpp и HTU21D.h, тоже компилируется!
У меня всё работает и мне нравится, но почему то через несколько часов ардуино зависает. Может зависнуть как с включённым так и с выключенным вентилятором. Грешу на китайцев, но пока не доходят руки поменять ардуино. Может кто нибуть знает какой то способ отслеживать эти зависания и пересбрасывать?
У меня всё работает и мне нравится, но почему то через несколько часов ардуино зависает. Может зависнуть как с включённым так и с выключенным вентилятором. Грешу на китайцев, но пока не доходят руки поменять ардуино. Может кто нибуть знает какой то способ отслеживать эти зависания и пересбрасывать?
А watchdog в Ардуине присутствует? И еще пожелание: перекоммутировать реле, соединив силовые контакты последовательно. Таким образом одно реле включает/выключает ветилятор, а второе переключает обмотки. Если вентилятор односкоростной, то второе реле просто не устанавливается. Таким образом если Ардуинка глюкнет, вентилятор не сгорит, так как исключается возможность включения 2-х обмоток одновременно.
У меня всё работает и мне нравится, но почему то через несколько часов ардуино зависает. Может зависнуть как с включённым так и с выключенным вентилятором. Грешу на китайцев, но пока не доходят руки поменять ардуино. Может кто нибуть знает какой то способ отслеживать эти зависания и пересбрасывать?
А watchdog в Ардуине присутствует? И еще пожелание: перекоммутировать реле, соединив силовые контакты последовательно. Таким образом одно реле включает/выключает ветилятор, а второе переключает обмотки. Если вентилятор односкоростной, то второе реле просто не устанавливается. Таким образом если Ардуинка глюкнет, вентилятор не сгорит, так как исключается возможность включения 2-х обмоток одновременно.
Присутствует и в arduino uno может даже работать, ну а не заработает - перешить bootloader
Выложить штоли мой первый праэкт, с описанием в стихах? К сажолению, в матерных.
Выложить штоли мой первый праэкт, с описанием в стихах? К сажолению, в матерных.
Было бы интересно почитать!
Спасибо, про watchdog почитаю. У меня обычный вентилятор и первая скорость сделана с помощью последовательного конденсатора.