Автоматическое освещение комнаты на базе контроллера Аrduino

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

Планирование

В качестве датчика движения выбор пал на пироэлектрический инфракрасный сенсор HC-SR50, в первую очередь из-за большого угла обнаружения, порядка 120 градусов. Более подробно останавливаться на нем не будем, единственное о чем следует сказать так это то, что перемычка на сенсоре установлена в положение H. В этом режиме при каждом срабатывании сенсора на выходе остается логическая единица. По количеству сенсоров всё зависит от самой комнаты, в моём случае двух вполне достаточно.
Сигнал с сенсоров будет поступать на одно из двух реле в одном модуле, которое будет включать центральный контур освещения, но в ручном режиме будем управлять двумя реле. Одно отвечает за центральный, второе за периферийный контур.
Одним из условий автоматического управления будет проверка уровня освещенности вне помещения. Осуществлять это будем с помощью сенсора на основе микросхемы LM393.
Для управления в ручном режиме соберём маленькую плату с двумя тактовыми кнопками для удобства монтажа.
83a1021b7b584e5081ce518511ace1bd.png

Перемычка JD-Vсс — Vсс убирается, если на катушку реле будет подаваться отдельное питание, как я понял делается это для гальванической развязки. Для переключения реле необходимо входы IN1 или IN2 притягивать к земле.
8d1a3257b9784bd3b4b25df21f27d942.png

Подготовка к монтажу

По питанию в моем распоряжение было только напряжение 220 переменного и 12 постоянного тока. Поэтому для питания самого контроллера, реле и сенсоров используется простая схема понижения напряжения до пяти вольт.
23d85deb7dea49b1ae60c549b2fd9b43.jpg

Платы нарисованы в программе Sprint-Layout, довольно простые и по сути плата контроллера нужна для того чтобы удобно подключать сигналы.
ff8b224332dc468ca7adcd4e50cdf75d.JPG

8e49890399cf41128093a9fc7ca1ed1d.JPG

Платы произведены всеми любимой технологией ЛУТ.
3f4793acc6924dc0b7f6f27ac551dc26.jpg

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

Составление скетча

Скетч
// Проект автоматики освещения.
// Настройка пинов.
#define Sensor_1 10 // Пин первого сенсора НС-SR501.
#define Sensor_2 11 // Пин второго сенсора НС-SR501.
#define D0 3 // Пин датчика освещенности.
int Relay[2] = {8, 9}; // Пины реле.
int Button[2] = {5, 6}; // Пины кнопок.
// Переменные.
boolean Start_Sensor = false; // Переменная отражающая факт срабатывания датчика.
boolean relayEnabled[2] = {true, true}; // Состояние реле.
boolean buttonWasUp[2] = {true, true}; // Состояние кнопок.
unsigned long previousMillis = 0; /* Переменнтая для хранения
предыдущего времени срабатывания датчика. */
unsigned long activateTime; // Переменная для хранения времени срабатывания реле.
int value = 0; // Временная переменная для таймера.
// Константы.
const int T_hold = 10000; // Время удержания реле при отсутствии движения.
const int T_motion = 200; // Время от начала фиксирования движения до срабатывания реле.

void setup()
{
// Настройка пинов и их начальное состояние.
pinMode(D0, INPUT); // Датчик освещенности - вход.
for (int i = 0; i < 2; ++i)
{
pinMode(Relay[i], OUTPUT); // Реле - выходы.
pinMode(Button[i], INPUT_PULLUP); // Кнопки - входы с подтягивающим резистором.
digitalWrite(Relay[i], relayEnabled[i]); /* Начальное состояние реле высокое,
чтобы реле включилось необходимо подать низкий сигнал или минус. */
}
}

void loop()
{
if(digitalRead(D0)) // Считываем значение с датчика освещенности "Достаточно ли темно для автоматики?"
{
Sensor_Work();
if (relayEnabled[0] == true && Start_Sensor == true)
// Если состояние 1го реле высокое (отключено) и сработал один из датчиков.
{
relayEnabled[0] = false; // Изменить состояние реле на низкое (включено).
digitalWrite(Relay[0], relayEnabled[0]); // Включить первое реле.
activateTime = millis(); // Зафиксировать время включения реле.
while((millis() - activateTime) < T_hold)
{
// Задержка.
}
relayEnabled[0] = true; // Изменить состояние реле на высокое (отключено).
digitalWrite(Relay[0], relayEnabled[0]); // Отключить реле.
}
}
// Для определения клика сначала понимаем, отпущена ли кнопка прямо сейчас.
for (int i = 0; i < 2; ++i)
{
boolean buttonIsUp = digitalRead(Button[i]);
// Если кнопка была отпущена и (&&) нажата сейчас...
if (buttonWasUp[i] && !buttonIsUp)
{
/* может это клик, а может и ложный сигнал (дребезг), возникающий в
момент замыкания размыкания пластин кнопки, поэтому даем кнопке полностью
успокоиться */
delay(10);
// И снова считываем сигнал.
buttonIsUp = digitalRead(Button[i]);
if (!buttonIsUp)
{
// Если она все еще нажата...
relayEnabled[i] = !relayEnabled[i]; // меняем состояние сигнала на противоположный.
digitalWrite(Relay[i], relayEnabled[i]); // Включаем то реле сквитированной кнопки.
}
}
// Запоминаем последнее состояние кнопки для новой итерации.
buttonWasUp[i] = buttonIsUp;
}
}

void Sensor_Work() // Процедура опроса сенсоров.
{
if (digitalRead(Sensor_1) == HIGH || digitalRead(Sensor_2) == HIGH) /* Если один из
датчиков зафиксировал движение. */
{
// Запустить таймер.
if (millis() - previousMillis > T_motion)
{
previousMillis = millis();
value++;
}
}
else
{
Start_Sensor = false; // Возвращение в исходное состояние факта срабатывания.
value = 0;
}
if(value >= 10)
{
Start_Sensor = true; // Факт срабатывания датчика.
value = 0;
}
}


Монтаж

Датчики спрятаны в небольшую пластиковую коробку.
395ba020c72d413eb09b40bc41cba2c2.jpg

Все кабели, за исключением ответвлений к сенсорам, спрятаны в пластиковые короба.
389953b8af984641ac99ce8cd3ba4281.jpg

Вид смонтированного центрального щита.
baf7176a20b841e2bcc6a6f5b6a0472f.jpg

f1f690fa74b3424eb35d457966238985.jpg

Итог

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


Комплектация

Контроллер Arduino Pro Mini Atmega 328 5 В 16 МГц 1
Пироэлектрический инфракрасный сенсор HC-SR501 2
Сенсор освещенности на микросхеме LM393 1
Стабилизатор напряжения L7805CV 1
Конденсатор керамический 0,33 мкФ 1
Конденсатор керамический 0,1 мкФ 1
Гнездо на плату PBS 1×40 2.54 1
Переключатель SWD1–1 2
Клеммник винтовой двухконтактный 9
Стеклотекстолит 61×46 мм 1
Стеклотекстолит 40×20 мм 1
Тактовая кнопка 2
Текстолит 1
Люминесцентный светильник Camelion WL-4002, 16 Вт 12
Потолочный светильник с двумя лампами накаливания 1
Распределительная коробка 8
Кабель ПУНП 2×2.5
Кабель телефонный ШТЛП-4 0,12×7
Кабель канал (различных размеров)
Расходники (термоклей, клей Момент Кристалл, припой, канифоль, флюс ТАГС, наконечники)
Крепежные элементы (болты, гайки, саморезы, дюбеля, хомуты)

Спасибо за уделённое внимание.

Ссылки:
Автоматическая подсветка лестницы

© Geektimes