• Крышка с простым контроллером на Arduino

  • Tina

Привет всем форумчанам! На днях смастерил крышечку с контроллером на Arduino, решил поделиться, может кому-то будет полезно. Основными задачами, возложенными на контроллер были: - управление четырьмя каналами света по расписанию; - измерение температуры и ее контроль при помощи нагревателя и вентилятора; - симпатичный экранчик с кучей букав, производящий на окружающих неизгладимое впечатление Список покупок: - БП 12В, 2А; - стабилизатор 5В L7805ABV; - Arduino Nano V3.0 AVR ATmega328 P-20AU; - датчик температуры DS18B20; - Real Time Clock Модуль (DS1307); - 2х канальное реле 5В 10А; - LCD 1602 I2C; - светодиоды (1 x Hyper red, 1 x Royal Blue, 1 x Blue, 1 x Cyan, 1 x White 6000K, 1 x UV 420 nm); - драйверы (2 x LDD350L, 2 x LDD600L); - резисторы, конденсаторы, термоскотч и прочая мелочевка. Схема соединения основных элементов (полноразмерная схема в приложении) Программу для контроллера писал пару вечеров вооружившись гуглом и сочетаниями клавиш Ctrl+C, Ctrl+V. Получилось примерно так: #include <Wire.h> // Подключаем библиотеки #include "RTClib.h" // Подключаем библиотеки #include <LiquidCrystal_I2C.h> // Подключаем библиотеки #include <OneWire.h> // Подключаем библиотеки OneWire ds(10); // Назначаем датчику температуры 10-й вывод LiquidCrystal_I2C lcd(0x27,16,2); // Подключаем дисплей по i2c RTC_DS1307 RTC; // Подключаем часики int Hours_Start_Sunrise[4] = {5, 6, 8, 11}; // Начало рассвета по каналам час int Minutes_Start_Sunrise[4] = {0, 0, 0, 0}; // Начало рассвета по каналам минута int Hours_End_Sunrise[4] = {9, 10, 11, 11}; // Окончание рассвета по каналам час int Minutes_End_Sunrise[4] = {0, 0, 0, 30}; // Окончание рассвета по каналам минута int Hours_Start_Sunset[4] = {17, 16, 15, 17}; // Начало заката по каналам час int Minutes_Start_Sunset[4] = {0, 0, 0, 0}; // Начало заката по каналам минута int Hours_End_Sunset[4] = {20, 18, 18, 17}; // Окончание заката по каналам час int Minutes_End_Sunset[4] = {0, 0, 0, 30}; // Окончание заката по каналам минута int MinuteDay_Start_Sunrise[4]; // День в минутах для начала рассвета int MinuteDay_End_Sunrise[4]; // День в минутах для окончания рассвета int MinuteDay_Start_Sunset[4]; // День в минутах для начала заката int MinuteDay_End_Sunset[4]; // День в минутах для окончания заката int Current_MinuteDay; // Текущая минута суток int Current_Period[4]; // Текущая часть суток 1-рассвет, 2-день, 3-закат, 4-ночь для каждого ШИМ int Meridian_PWM[4] = {250, 250, 250, 250}; // Максимальное значение ШИМ int Midnight_PWM[4] = {0, 2, 0, 0}; // Минимальное значение ШИМ int Current_PWM[4] = {0, 2, 0, 0}; // Текущее значение ШИМ int TargetTemp = 26; // Температура, которую нужно поддерживать /* ******************************************** */ /* * * */ /* * ШИМ пин для UV+RB, B+C, CW, HR * */ /* * Пин - 3 - UV+RB - UV + Royal Blue * */ /* * Пин - 5 - B+C - Blue + Cyan * */ /* * Пин - 6 - CW - Cool White * */ /* * Пин - 9 - HR - Hyper Red * */ /* * * */ /* ******************************************** */ int PWM_Pin[4] = {3, 5, 6, 9}; // ШИМ пин для UV+RB, B+C, CW, HR int Relay1 = 7; // Пин реле для включения вентилятора int Relay2 = 8; // Пин реле для включения нагревателя void setup() { lcd.init(); // Инициализация LCD lcd.backlight(); // Включаем подсветку lcd.clear(); // Очистка дисплея Serial.begin(57600); // Подключаем порт Wire.begin(); // Включаем шину часиков RTC.begin(); // Включаем часики if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); //RTC.adjust(DateTime(__DATE__, __TIME__)); //RTC.adjust(DateTime(2012, 7, 12, 22, 48, 1)); } for (int i=0; i<=3; i++) { pinMode(PWM_Pin[i], OUTPUT); // Установка пин для ШИМ } for (int i=0; i<=3; i++) { analogWrite(PWM_Pin[i], Midnight_PWM[i]); // Установка минимального значения ШИМ Current_PWM[i]=Midnight_PWM[i]; // Установка текущих значений ШИМ в минимум } for (int i=0; i<=3; i++) { MinuteDay_Start_Sunrise[i]=60*Hours_Start_Sunrise[i] + Minutes_Start_Sunrise[i]; // Расчет минуты суток для начала рассвета MinuteDay_End_Sunrise[i]=60*Hours_End_Sunrise[i] + Minutes_End_Sunrise[i]; // Расчет минуты суток для окончания рассвета MinuteDay_Start_Sunset[i]=60*Hours_Start_Sunset[i] + Minutes_Start_Sunset[i]; // Расчет минуты суток для начала заката MinuteDay_End_Sunset[i]=60*Hours_End_Sunset[i] + Minutes_End_Sunset[i]; // Расчет минуты суток для окончания заката } pinMode(Relay1, OUTPUT); // Подключаем пин реле 1 как выход pinMode(Relay2, OUTPUT); // Подключаем пин реле 2 как выход digitalWrite(Relay1, HIGH); // Переключаем реле в режим "Выкл" (для этого сигнал должен быть "HIGH") digitalWrite(Relay2, HIGH); // Переключаем реле в режим "Выкл" (для этого сигнал должен быть "HIGH") } // Процедура расчета текущего периода и значения PWM по каналам void Led_Dim_PWM() { DateTime now = RTC.now(); Current_MinuteDay = (now.hour() * 60) + now.minute(); for (int i=0; i<=3; i++) { Current_Period[i]=4; if (Current_MinuteDay>=MinuteDay_Start_Sunrise[i] && Current_MinuteDay<=MinuteDay_End_Sunrise[i]) {Current_Period[i]=1;} if (Current_MinuteDay>MinuteDay_End_Sunrise[i] && Current_MinuteDay<MinuteDay_Start_Sunset[i]) {Current_Period[i]=2;} if (Current_MinuteDay>=MinuteDay_Start_Sunset[i] && Current_MinuteDay<=MinuteDay_End_Sunset[i]) {Current_Period[i]=3;} if (Current_Period[i]==1) { Current_PWM[i]=(float)(((float)Current_MinuteDay-MinuteDay_Start_Sunrise[i])/((float)MinuteDay_End_Sunrise[i]-MinuteDay_Start_Sunrise[i]))*((float)Meridian_PWM[i]-Midnight_PWM[i]); if (Current_PWM[i]<Midnight_PWM[i]) {Current_PWM[i]=Midnight_PWM[i];} analogWrite(PWM_Pin[i], Current_PWM[i]); } if (Current_Period[i]==2) { if (Current_PWM[i]!=Meridian_PWM[i]) { Current_PWM[i]=Meridian_PWM[i]; analogWrite(PWM_Pin[i], Current_PWM[i]); } } if (Current_Period[i]==3) { Current_PWM[i]=(float)(((float)MinuteDay_End_Sunset[i]-Current_MinuteDay)/((float)MinuteDay_End_Sunset[i]-MinuteDay_Start_Sunset[i]))*((float)Meridian_PWM[i]-Midnight_PWM[i]); analogWrite(PWM_Pin[i], Current_PWM[i]); } if (Current_Period[i]==4) { if (Current_PWM[i]!=Midnight_PWM[i]) { Current_PWM[i]=Midnight_PWM[i]; if (Current_PWM[i]<Midnight_PWM[i]) {Current_PWM[i]=Midnight_PWM[i];} analogWrite(PWM_Pin[i], Current_PWM[i]); } } } Serial.print(now.year(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.day(), DEC); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.print(" Current_MinuteDay: "); Serial.print(Current_MinuteDay, DEC); Serial.println(); for (int i=0; i<=3; i++) { Serial.print("Channel #"); Serial.print(i, DEC); Serial.print(", Current Period: "); if (Current_Period[i]==1) {Serial.print("Sunrise");} if (Current_Period[i]==2) {Serial.print("Meridian");} if (Current_Period[i]==3) {Serial.print("Sunset");} if (Current_Period[i]==4) {Serial.print("Midnight");} Serial.print(", Current PWM: "); Serial.print(Current_PWM[i], DEC); Serial.println(); } Serial.println(); // Выводим на дисплей текущее время lcd.setCursor(0, 0); lcd.print(now.hour(), DEC); lcd.print(":"); if (now.minute() < 10) {lcd.print("0");} lcd.print(now.minute(), DEC); // Выводим на дисплей текущие значения PWM по каналам lcd.setCursor(0, 1); lcd.print(Current_PWM[0]); lcd.print(" "); lcd.setCursor(4, 1); lcd.print(Current_PWM[1]); lcd.print(" "); lcd.setCursor(9, 1); lcd.print(Current_PWM[2]); lcd.print(" "); lcd.setCursor(13, 1); lcd.print(Current_PWM[3]); lcd.print(" "); } void loop () { // Вычисляем температуру byte data[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); delay(750); ds.reset(); ds.write(0xCC); ds.write(0xBE); data[0] = ds.read(); data[1] = ds.read(); int Temp = (data[1]<< 8)+data[0]; Temp = Temp>>4; Serial.print("Temperature = "); Serial.print(Temp, DEC); Serial.print(" C"); Serial.println(); // Выводим температуру на дисплей lcd.setCursor(6, 0); lcd.print("T="); lcd.print(Temp); lcd.print("C"); // Задаем режимы работы реле в зависимости от измеренной температуры if (Temp > TargetTemp) { digitalWrite(Relay1, LOW); digitalWrite(Relay2, HIGH); lcd.setCursor(12, 0); lcd.print("Cool"); Serial.println("Temp is high, cooling"); } if (Temp == TargetTemp) { digitalWrite(Relay1, HIGH); digitalWrite(Relay2, HIGH); lcd.setCursor(12, 0); lcd.print("None"); Serial.println("Temp is normal, standby"); } if (Temp < TargetTemp) { digitalWrite(Relay1, HIGH); digitalWrite(Relay2, LOW); lcd.setCursor(12, 0); lcd.print("Heat"); Serial.println("Temp is low, heating"); } Led_Dim_PWM(); // Выставляем частоту обновления данных 10 секунд delay(10000); } Все библиотеки в приложении, версия программы - arduino-1.0.5-r2 Итоговая конструкция выглядит вот так: Лицевая панель Дисплей показывает время, температуру, режим (нагрев или охлаждение), ШИМ по каждому каналу. Начинка Светодиоды и драйверы (да простят меня гуру паяльника и канифоли!) Датчик температуры в гидроизолированном кожухе З.Ы. Не судите строго, моя первая крышка! Немножко подредактировал программу. Исправил мелкие недочеты в работе дисплея. Версию 1.0.7 приложил.

Emma

Накрылось 1 реле, печаль.... Наверно поменяю на твердотельные

Rodney

Отлично - Просто, доходчиво, наглядно.

Diana3118

Реле поменял, подправил программу, после 4-х дней испытаний полет нормальный.

Alyssa1438

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

Chelsea

Да запросто, только я не самый опытный ардуинщик . Это моя первая программа. Пока все работает.

Danielle9144

Привет! Отличная тема! Заказал все компоненты на Aliexpress... Пока посылка в дороге, балуюсь в Proteuse. Собрал все до кучи и скетч опробовал... Может кому интересно... В архиве исходник для Proteuse скетч и HEX для прошивки...

Christopher3770

На днях делал еще 1 контроллер на arduino pro micro. В этот раз еще проще. Только свет, даже без дисплея. Очень долго не хотели работать часы. В конце концов заработали с немного модифицированной программкой. Все файлы прилагаю. Версия программы arduino 1.0.6

Michael3221

А какие у вас часы? просто я нашел как минимум 4 библиотеки не совместимые с моими часами, либо не совместимые со скетчем который как ни странно выложенн с либой.

Justin9867

Часы вот такие

Laura3673

Здравствуйте,а сделать такой свет под заказ возьметесь и сколько будет его себестоимость

Daniel

Здравствуйте! Вообще тему создавал как некоммерческую. Все зависит от того, на сколько Вы знакомы с паяльником. Всегда готов помочь с любыми вопросами. Если уж совсем с самоделками туго, могу попробовать собрать контроллер, но все на Ваш страх и риск. Список комплектующих можете приблизительно посмотреть на схеме. Сам контроллер ардуино+часы+дисплей обходятся где-то около 350-380 (по теперешним ценам точно не знаю). Думаю, договоримся, пишите!

Bryan1851

Как я понял вы не программист, либо начинающий. Просто в вашем варианте сборной программы есть один минус- при сбое в питании платплаты прога не проверяет яркость на данный момент времени, треть если выпонялся алгоритм рассвета при выключении включении света светодиоды гаснут и не светят до момента следующего алгоритма, например день или вечер и тд. То есть если днеем выключатель свет света в аквариуме не будет до вечера, до алгоритма закат! Тестил неделю и параллельно сочинял логику для алгоритма вычисления яркости то есть числа шим (255) по моменту времени включения.... Кароче жесть. взяв вашу прошу за основу так как простенько и более менее понятно.

Melissa3820

Здравствуйте, да, Вы правы, я вообще никогда раньше не имел дела с программированием. Может не правильно Вас понял, но если выдернуть мой светильник из розетки, а потом воткнуть на место, диоды загораются сразу Точно знаю, т.к. на работе очень часто выключают днем свет. Единственное - периодически почему-то после отключений сбивается время. Буду благодарен, если дадите советы по программе.

Melissa3820

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

Amy9618

Продолжаем развлекаться в свободное время и попутно обеспечиваем друзей аквариумистов светом! В этот раз жертвой эксперимента стала крышка природа для маленького преснячка. Канала 2: белый и красный+рояль. Мозги спрятал в коробок на боку крышки. Дисплея нет, датчика температуры нет. Только свет, настраиваемый с компьютера/ноута. Остается проблема с сбоем времени при отключении света... Программка: #include <Wire.h> // Подключаем библиотеки #include "RTClib.h" // Подключаем библиотеки RTC_DS1307 RTC; // Подключаем часики int Hours_Start_Sunrise[2] = {7, 6}; // Начало рассвета по каналам час int Minutes_Start_Sunrise[2] = {0, 30}; // Начало рассвета по каналам минута int Hours_End_Sunrise[2] = {11, 10}; // Окончание рассвета по каналам час int Minutes_End_Sunrise[2] = {0, 0}; // Окончание рассвета по каналам минута int Hours_Start_Sunset[2] = {17, 18}; // Начало заката по каналам час int Minutes_Start_Sunset[2] = {0, 0}; // Начало заката по каналам минута int Hours_End_Sunset[2] = {21, 22}; // Окончание заката по каналам час int Minutes_End_Sunset[2] = {0, 0}; // Окончание заката по каналам минута int MinuteDay_Start_Sunrise[2]; // День в минутах для начала рассвета int MinuteDay_End_Sunrise[2]; // День в минутах для окончания рассвета int MinuteDay_Start_Sunset[2]; // День в минутах для начала заката int MinuteDay_End_Sunset[2]; // День в минутах для окончания заката int Current_MinuteDay; // Текущая минута суток int Current_Period[2]; // Текущая часть суток 1-рассвет, 2-день, 3-закат, 4-ночь для каждого ШИМ int Meridian_PWM[2] = {250, 250}; // Максимальное значение ШИМ int Midnight_PWM[2] = {0, 0}; // Минимальное значение ШИМ int Current_PWM[2] = {0, 0}; // Текущее значение ШИМ /* ******************************************** */ /* * * */ /* * ШИМ пин для UV+RB, B+C, CW, HR * */ /* * Пин - 10 - HR+RB * */ /* * Пин - 11 - White * */ /* * * */ /* ******************************************** */ int PWM_Pin[2] = {10, 11}; // ШИМ пин для HR+RB, White void setup() { RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.begin(57600); // Подключаем порт Wire.begin(); // Включаем шину часиков RTC.begin(); // Включаем часики if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); //RTC.adjust(DateTime(__DATE__, __TIME__)); //RTC.adjust(DateTime(2014, 10, 28, 11, 17, 1)); } for (int i=0; i<=1; i++) { pinMode(PWM_Pin[i], OUTPUT); // Установка пин для ШИМ } for (int i=0; i<=1; i++) { analogWrite(PWM_Pin[i], Midnight_PWM[i]); // Установка минимального значения ШИМ Current_PWM[i]=Midnight_PWM[i]; // Установка текущих значений ШИМ в минимум } for (int i=0; i<=1; i++) { MinuteDay_Start_Sunrise[i]=60*Hours_Start_Sunrise[i] + Minutes_Start_Sunrise[i]; // Расчет минуты суток для начала рассвета MinuteDay_End_Sunrise[i]=60*Hours_End_Sunrise[i] + Minutes_End_Sunrise[i]; // Расчет минуты суток для окончания рассвета MinuteDay_Start_Sunset[i]=60*Hours_Start_Sunset[i] + Minutes_Start_Sunset[i]; // Расчет минуты суток для начала заката MinuteDay_End_Sunset[i]=60*Hours_End_Sunset[i] + Minutes_End_Sunset[i]; // Расчет минуты суток для окончания заката } } // Процедура расчета текущего периода и значения PWM по каналам void Led_Dim_PWM() { DateTime now = RTC.now(); Current_MinuteDay = (now.hour() * 60) + now.minute(); for (int i=0; i<=1; i++) { Current_Period[i]=4; if (Current_MinuteDay>=MinuteDay_Start_Sunrise[i] && Current_MinuteDay<=MinuteDay_End_Sunrise[i]) {Current_Period[i]=1;} if (Current_MinuteDay>MinuteDay_End_Sunrise[i] && Current_MinuteDay<MinuteDay_Start_Sunset[i]) {Current_Period[i]=2;} if (Current_MinuteDay>=MinuteDay_Start_Sunset[i] && Current_MinuteDay<=MinuteDay_End_Sunset[i]) {Current_Period[i]=3;} if (Current_Period[i]==1) { Current_PWM[i]=(float)(((float)Current_MinuteDay-MinuteDay_Start_Sunrise[i])/((float)MinuteDay_End_Sunrise[i]-MinuteDay_Start_Sunrise[i]))*((float)Meridian_PWM[i]-Midnight_PWM[i]); if (Current_PWM[i]<Midnight_PWM[i]) {Current_PWM[i]=Midnight_PWM[i];} analogWrite(PWM_Pin[i], Current_PWM[i]); } if (Current_Period[i]==2) { if (Current_PWM[i]!=Meridian_PWM[i]) { Current_PWM[i]=Meridian_PWM[i]; analogWrite(PWM_Pin[i], Current_PWM[i]); } } if (Current_Period[i]==3) { Current_PWM[i]=(float)(((float)MinuteDay_End_Sunset[i]-Current_MinuteDay)/((float)MinuteDay_End_Sunset[i]-MinuteDay_Start_Sunset[i]))*((float)Meridian_PWM[i]-Midnight_PWM[i]); analogWrite(PWM_Pin[i], Current_PWM[i]); } if (Current_Period[i]==4) { if (Current_PWM[i]!=Midnight_PWM[i]) { Current_PWM[i]=Midnight_PWM[i]; if (Current_PWM[i]<Midnight_PWM[i]) {Current_PWM[i]=Midnight_PWM[i];} analogWrite(PWM_Pin[i], Current_PWM[i]); } } } Serial.print(now.year(), DEC); Serial.print('/'); Serial.print(now.month(), DEC); Serial.print('/'); Serial.print(now.day(), DEC); Serial.print(' '); Serial.print(now.hour(), DEC); Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.print(" Current_MinuteDay: "); Serial.print(Current_MinuteDay, DEC); Serial.println(); for (int i=0; i<=1; i++) { Serial.print("Channel #"); Serial.print(i, DEC); Serial.print(", Current Period: "); if (Current_Period[i]==1) {Serial.print("Sunrise");} if (Current_Period[i]==2) {Serial.print("Meridian");} if (Current_Period[i]==3) {Serial.print("Sunset");} if (Current_Period[i]==4) {Serial.print("Midnight");} Serial.print(", Current PWM: "); Serial.print(Current_PWM[i], DEC); Serial.println(); } Serial.println(); } void loop () { Led_Dim_PWM(); // Выставляем частоту обновления данных 10 секунд delay(1000); }

Jenny

собрал эту схемку , все отлично работает и просто!!!! только сделал дополнительный выход на управление вентилятором охлаждения диодов, на рассвете он включается на закате отключается, и еще один выход на компрессор пенника также чтоб ночью отключался(для тишины) )))