Постоянный посетитель
|
ARDUINO для автоматизации аквариума (страница 3) |
Создал отдельную тему по вопросам использования простых и не дорогих плат ARDUINO для целей автоматизации аквариума. Схема коммутации в случае использования платы NANO: Программа для среды программирования Arduino: //*************************************************** // Скетч для управления релейным модулем, в котором * // использовано два канала. Используется также RTC * // Релейный модуль - с инверсной логикой на входе * // Автор: ZORS * // Версия 1. Дата 21.12.2013 02:40 * //*************************************************** //----------ИМПОРТ БИБЛИОТЕК------------------------- #include //Подключаем библиотеку для использования I2C интерфейса с модулем RTC #include //Подключаем библиотеку для использования модуля часов реального времени RTC RTC_DS1307 RTC; //Создаем переменную класса - для использования RTC //----------Объявляем разные переменные------------ const int RelayChn1 = 6; //Используем цифровой ПОРТ 6 для ПЕРВОГО канала релейного модуля const int RelayChn2 = 7; //Используем цифровой ПОРТ 7 для ВТОРОГО канала релейного модуля //----------Настройки времени и продолжительности включения реле //----------ПЕРВЫЙ канал---------------------------- const long StartRelCn_1 = 25200; //Время срабатывания в ПЕРВОМ канале релейного модуля (в секундах от начала суток) //в данном случае 25200 - это 7 часов 00 минут = ( 60секунд *60 минут *7 = 25200) const long DurationCh_1 = 10; //ДЛИТЕЛЬНОСТЬ срабатывания реле в ПЕРВОМ канале (в секундах) //----------ВТОРОЙ канал---------------------------- const long StartRelCn_2 = 37800; //Время срабатывания во ВТОРОМ канале релейного модуля (в секундах от начала суток) //В данном случае 10 часов 30 минут = (60 секунд * 60 минут * 10 часов + 60сек*30мин = 37800) const long DurationCh_2 = 15; //ДЛИТЕЛЬНОСТЬ срабатывания реле во ВТОРОМ канале (в секундах) //----------Модуль инициализации setup() - выполняется один раз при инициализации платы при подаче напряжение (и аналогичных событиях) void setup(){ pinMode(RelayChn1,OUTPUT); //Инициализируем порт для ПЕРВОГО канала как ВЫХОД pinMode(RelayChn2,OUTPUT); //Инициализируем порт для ВТОРОГО канала как ВЫХОД digitalWrite(RelayChn1,HIGH); //Устанавливаем на входах релейного модуля ВЫСОКИЙ уровень digitalWrite(RelayChn2,HIGH); //Т.к. используемый релейный модуль с опторазвязкой - управляется инверсной логикой Wire.begin(); //Инициируем I2C интерфейс RTC.begin(); //Инициирум RTC модуль // RTC.adjust(DateTime(__DATE__, __TIME__)); //С этой строки необходимо убрать комментарии один раз в начале, //для того, чтобы загрузить в RTC дату и время на момент компиляции программы //Иногда необходимо заливать СКЕТЧ на плату со снятым комментарием - для поправки //времени в RTC, НО оставлять такой СКЕТЧ в работе НЕЛЬЗЯ !!!!!!!!!!!!! } // КОНЕЦ ИНИЦИАЛИЗАЦИИ //-------------------------------------------------- void loop() // ПРОГРАММЫй безусловный ЦИКЛ { DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла //----------Раздел обработки реле по времени ---- long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках, //Это дает количество секунд с начала текущих суток //------------КАНАЛ 1------------------------------ if ((utime >= StartRelCn_1) && (utime //Если секунд с начала суток больше, чем задано для включения //Но, одновременно и меньше, чем задано для включения + длительность { digitalWrite(RelayChn1,LOW); //Устанавливаем на ПЕРВОМ входе релейного модуля НИЗКИЙ уровень - реле срабатывает } else //во всех остальных случаях { digitalWrite(RelayChn1,HIGH); //Устанавливаем на ПЕРВОМ входе релейного модуля ВЫСОКИЙ уровень - реле выключается } //------------КАНАЛ 2 - все аналогично ----------- if ((utime >= StartRelCn_2) && (utime { digitalWrite(RelayChn2,LOW); //Устанавливаем на ВТОРОМ входе релейного модуля НИЗКИЙ уровень - реле срабатывает } else { digitalWrite(RelayChn2,HIGH); //Устанавливаем на ВТОРОМ входе релейного модуля ВЫСОКИЙ уровень - реле выключается } }//------------Конец ЦИКЛА----------------------------- (Редактор текста на данном сайте - к сожалению, "ломает" красивое форматирование. PS: Выложил этот скетч на файлообменник : http://my-files.ru/h... В данной программе реализован, довольно-таки простой подход, а простота - основа надежности. Каждое из 2-х реле срабатывают один раз в сутки в указанное время, причем время указывается в количестве секунд от начала суток, и удерживается указанное количество времени в секундах. Такой способ задания времени - несколько сложен для понимания, но за это - не нагружает программу и процессор лишним функционалом, который понадобится всего один раз. Для определения времени наступления события начала включения и выключения реле - используется время в формате UNIX. Такой подход хорош тем, что даже если включение или перезагрузка платы произойдет в промежутке времени включения, то реле включится в оставшееся время. В случае с дозированием, это не много что дает, но в случае, если по аналогии будет сделано управление светом, то при подаче напряжения на плату, например, после пропадания напряжения питания, или после посадки напряжения, или др. аналогичных событий, включение и выключение реле произойдет корректно. У комплектных минутных и секундных таймеров "с розеткой" - об этом можно только мечтать....не реализован такой функционал, и еще у них есть один минус. Реле в таких таймерах - не удерживаемое, а переключаемое, со всеми вытекающими последствиями.... Для программирования нескольких включений каждого реле в течение суток - естественно, потребуется несколько другой подход....спрашивайте когда кому-то потребуется, пока не хочу все усложнять... В принципе, можно добавить константных переменных, содержащих время и длительность срабатывания, и соответственно добавить проверку на условия. Если количество необходимых срабатываний каждого реле в сутках больше чем 2 - лучше оформить проверку условий в отдельной функции. Как, говорил человек, учивший меня программированию - "все, что ты делаешь в программе больше двух раз - оформляй отдельной процедурой, или функцией". Главное ограничение этого подхода - включение и выключение реле - должно произойти в одних сутках. Если необходимо чтобы, реле включилось в одних сутках, а выключилось в других - необходимо разбить это задание на 2 задания, или применить другой метод проверки условий наступления событий включения и выключения. Весь этот пример тестировался на "живом" железе : Для наглядности отладки был еще подключен LCD дисплей 16 сим в 2 строках. Схема итоговая была такая: Обратите внимание, что при использовании I2C последовательного интерфейса - соединения значительно упрощаются. И LCD дисплей подключен транзитом через модуль RTC (часов реального времени). Никаких паяных соединений нет вообще....все скоммутировано - проводами с разъемами. Скетч - естественно, несколько другой использовался с добавлением строк инициализации и использования LCD 16x2. Плата использовалась типа такой: http://www.ebay.com/... цена примерно 350 руб. Релейный модуль http://www.ebay.com/... цена примерно 150 руб. Модуль часов реального времени: http://www.ebay.com/... Цена примерно 55 руб. Для сокращения бюджета можно использовать плату проще: http://www.ebay.com/... Цена примерно 200 руб. Если есть потребность подключить ЖК дисплейчик, то лучше брать ЖК дисплей (LCD) c I2C интерфейсом - это сильно упрощает коммутацию, и сокращает количество использованных портов на микроконтроллере. Например такой можно использовать : http://www.ebay.com/... цена около 180 руб. На ЖК можно выводить статусную информацию, информацию об ошибках, диагностическую информацию. Все это, конечно, можно и в последовательный порт компьютера выводить, но это не всегда удобно (скорее наоборот), поэтому я всегда использую какой-нибудь девайс для вывода информации. Для использования I2C интерфейса - необходима библиотека Wire. Она есть в стандартном дистрибутиве среды программирования Arduino. Для использования модуля RTC на микросхеме DS1307 нужна библиотека RTClib. Если ее не будет в стандартном дистрибутиве, то ее можно взять в интернет. Например здесь : http://arduino-info.... Необходимо, скачать, и разархивировать zip-файл в папку с понятным названием, например RTCLib. Затем эту папку поместить в папку, где среда Arduino хранит свои библиотеки. Если ставили среду программирования с настройками по умолчанию, то этой папкой будет : C:Program FilesArduinolibraries Сюда и помещайте папки с подключаемыми библиотеками. Если на этот момент, среда программирования была запущена - ее необходимо закрыть, и запустить заново. После этого библиотека будет доступна в меню Скетч/Импортировать библиотеку. Микросхема RTC модуля DS1307, как правило использует адрес на шине I2C равный 0x68 поэтому, необходимо проверить в библиотечных файлах, библиотеки RTClib наличие строки типа этой: #define DS1307_ADDRESS 0x68 Если будет использоваться LCD 16x2 с I2C интерфейсом, то - понадобиться библиотека LiquidCrystal_I2C. Можно скачать здесь : http://dvrobot.ru/lc... Как подключить к среде программирования Arduino - см. выше ВАЖНО : при использовании I2C устройств - в скетче, библиотека Wire - должна быть объявлена первой, иначе - будут ошибки компиляции. По этому примеру - все.... в следующем - присоединение термо-датчика DS18B20, и создание несложного терморегулятора..... Изменено 24.12.13 автор Z0RS |
|
#1907148 |
Посетитель
|
|
попробовал на другом компьютере... |
|
#1948833 |
|
Постоянный посетитель
|
|
lisenkow А Вы какую конкретно модель платы подключаете? На ней бутлоадер залит? Вообще, если просто любой терминальной программой (например гипертерминалом) попытаться присоединиться - то соединение создается? Можно так попробовать: В гипертерминале создать новое соединение, на порту соответствующем виртуальному порту платы. При создании соединения использовать следущюии параметры: Скорость 9600, бит данных = 8, четность = нет, стоповые биты = 1, управление потоком = аппаратное При удачном соединении не должно выскакивать ошибок, потом, будет идти время соединения в статусной строке внизу программы, и при нажатии клавиши ENTER на плате ардуино будет взмаргивать светодиод.... Если все так, то значит проблеммы с бутлоадером, если не так, то проблемы с присоединением, с драйверами/настройкой виртуального компорта или настройками порта в программе. Потом, еще проверьте какая скорость установлена на виртуальном ком-порту по умолчанию, иногда система выставляет 384000 или другие скорости отличные от 9600. Необходимо выставить 9600 - это скорость по умолчанию....или если необходима другая скорость - это оговаривается в документации на плату.... Ошибки синхронизации очень часть возникают из за несоответствия скоростей портов на разных сторонах....поиграйтесь с этим параметром... |
|
#1948839 |
Постоянный посетитель
|
|
#1948843 |
Новичок
2
10 года |
|
Есть ли у кого опыт управления реле через приемник/передатчик на 433 Мгц? В частности интересует схема для приемной части (в эфире постоянный сигнал не есть гуд). |
|
#1950840 |
Постоянный посетитель
|
|
plus Если Вы имеете ввиду девайс типа этого: http://www.ebay.com/... то это банальный удлинитель сигнала с TTL уровнем по радиоканалу 433 МГц, и высокий уровень на выходе будет означать наличие несущей в эфире. Присоединение тоже не сложное как бы ...питание и один управляющий вход TTL на стороне передатчика, ну и TTL выход на стороне приемника, к которому можно напрямую присоединить вход релейного модуля, или другой потребитель TTL уровня. Вот простейшая схема : https://encrypted-tb... Чтобы сделать использование этого модуля более "умным" и управляемым, на стороне приемника необходимо использовать более сложную логику, которая может быть реализована на каком-то микроконтроллере по-проще, например на серии ATMEL TINY. При использовании 2 микроконтрорллеров при обмене данными можно реализовать несложный протокол, результатом работы которого будет отсутствие постоянной несущей в эфире для обеспечения высокого выходного уровня, наличие защиты от чужого сигнала, и контроль передачи/приема. В принципе, мне кажется для этих модулей должны быть готовые библиотеки....хоть в Вашем случае для управления реле они особо и не нужны.... И есть еще вариант, где все вышеперечисленное реализовано в "железе", причем удлиняется уже не один канал с TTL уровнями, а несколько, и все кодирования/декодирования реализованы в МК на платах: http://www.ebay.com/... Но цена, конечно уже другая... |
|
#1951026 |
|
Новичок
2
10 года |
|
Спасибо за ответ. Жаба душит использовать на стороне приема arduino, хотя есть библиотека VirtualWire (здесь описание http://habrahabr.ru/... Думаю на простой логике что-то придумать, чтобы не писать лишний код для взаимосвязи двух микрух. |
|
#1951038 |
Постоянный посетитель
|
|
plus Да не обязательно ардуино использовать....Хотя какую нибудь NANO или MICRO рублей за 100 - было бы весьма логично, легко программируемо и бюджетно. Можно и просто собрать несложную схемку на кусочке монтажки, на которую поставить проц типа http://www.ebay.com/... Пару конденсаторв, резисторов и кварц....но по цене будет так же, как NANO без USB. Не будет смысла заморачиваться.... Вообще весьма бюджетных вариантов много.... |
|
#1951052 |
Малёк
30
Тихорецк 6 года |
|
Добрый день!! |
|
#1952973 |
|
Постоянный посетитель
|
|
Для того, чтобы организовать Миххаил - по крайней мере, необходимо иметь либо сетевую плату (EtherNet), либо аналогичный шилд. Эти устройства, как правило, подключаются посредством I2C интерфейса, и имеют соответствуюие библиотеки....одну из плат я уже описывал в этой теме. Но с использованием сетевых плат - есть одна проблема, а именно : функция передачи сформированного в буффере сообщения - имеет недетерминированную длительность....т.е. может выполняться довольно длительное время...т.к. процессор на плате один, и он не многозадачный, то можно потерять по времени некоторые другие события, например отключения или включения чего либо....Естественно это справедливо при использовании стандартных библиотек. Отказавшись от стандартных библиотечных функций - это можно разрешить, но программирование становиться очень сложным, и новичку это будет сделать очень сложно, практически невозможно. Платы EtherNet существуют 2х основных типов : на чипе ENC28J60. Например http://www.ebay.com/... и на чипе W5100. На основе этого чипа - есть и шилды и отдельные платы. Пример шилда http://www.ebay.com/... Использование W5100 - является более предпочтительным, когда требуется снижать нагрузку на микропроцессор основной платы Arduino, т.к. сетевые устройства на основе W5100 многие операции выполняют на микросхеме W5100, а в случае ENC28J60 - нагрузка на основной процессор платы - больше. Кроме сетевой платы, необходимо написать код самого WEB сервера... Потом, для организации контроля за протечками - потребуются сенсоры с TTL или с аналоговым или цифровым интерфейсным выходом...они есть в продаже на том же ebay.com Ну и так...далее... А вообще, Вы начинаете с очень непростой задачи.... |
|
#1953021 |
Завсегдатай, Кандидат в Советники
|
|
Z0RS Добрый день. На вашей блок-схеме с диммированием светодиодов Arduino получает питание от блока питания через преобразователь напряжения, правильно? Получатся, блок питания постоянно включен в сеть. В связи с этим вопрос: блок питания потребляет все время постоянную мощность в не зависимости от подключенной к нему нагрузки? Т.е. если светодиоды выключены, блок потребляет ту же мощность, что и при включенных? Это уже вопрос экономии денег за свет. Если это так, то может запитать aruino через что-то маломощное, а уже основной блок питания (и всю цепочку диодов) подключать к 220В через релейное соединение? Или я ошибаюсь? ЗЫ.Спасибо за тему, по информативности она может поспорить со специализированными форумами "ардуинистов" . |
|
#1953335 |
Малёк
30
Тихорецк 6 года |
ZORS (страница 3) |
Огромное спасибо что откликнулись так быстро!! |
|
#1953354 |
|
Постоянный посетитель
|
|
Дядька-рыбомор Нет, конечно....блок питания без нагрузки потребляет ток холостого хода, и мощность соответственно. Как правило это несколько процентов от номинальной мощности. Ардуино запитано от одного БП для экономии. Для увеличения надежности схемы, можно запитать от отдельного бп и сделать схему использования резервного источника, аккумулятора, например. Дядька-рыбомор Пожалуйста! Миххаил Я, если честно, не знаю... По сложности программирования - это сопоставимые задачи, если делать двухсторонний обмен. В любом случае, если будет использоваться EtherNet - будут присутствовать задержки неопределенной длительности при обработке данных этого протокола....и следовательно программирование задач с контролем времени - усложниться... С выбором конкретных моделей модулей WiFi или GSM - не подскажу, вопрос очень широкий, и конечный выбор оборудования зависеть только от Ваших требований. Модулей существует много разных, самый простой способ облегчить себе жизнь с выбором того или иного модуля - сначала найти на него документацию, и библиотеку функций с кодом примеров. Затем посмотреть код примеров и определить, насколько хорошо вы понимаете те идеи, которые заложены в реализации библиотечных функций...если все понятно - то такой модуль можно приобретать. Вообще если позволяют средства - лучше брать уже "раскрученные" шилды, т.к. для них все есть, и библиотеки, и примеры. Вот пример шилда с GSM : http://www.ebay.com/... Миххаил Как я могу знать что ВАМ нужно? Некоторые примеры периферии, такие как релейный модуль, датчик температуры - я уже приводил в этой теме....остальное аналогичное оборудование можете подобрать сами... Миххаил Не пользуюсь скайпом....впрочем как и аськой - практически не пользуюсь. |
|
#1953555 |
Посетитель
|
|
Z0RS Пришли тут мне арудино, но вот незадача - вместо i2c дисплея - обычный. Пока играюсь второй день, даже что-то получается. Но копаясь в инете наткнулся на такую штучку: http://www.aliexpres... Это очень плохо или терпимо - просто цена вроде более-менее. Цель - контроль Ph при подаче co2. |
|
#1953558 |
Постоянный посетитель
|
|
arch07 Ну не страшно....впринципе, продаются отдельные модули I2C интерфейса. Например для дисплея размерностью 16Х2 подойдет такой : http://www.ebay.com/... А при наличии достаточного количества цифровых портов OUTPUT - можно и без I2С использовать модуль дисплея. I2С - используется "не от хорошей жизни" - для экономии портов. В случае, когда используется дисплей напрямую на портах вывода - необходимо использовать другую библиотеку - она есть в стандартной поставке среды программирования ARDUINO и называется эта библиотека просто LiquidCrystal. Кстати, в примерах к этой библиотеке можно увидеть, как определяются порты для подключения дисплея. Так, что можете использовать ваш дисплей, я так понимаю что с количеством портов у Вас пока проблем нет. arch07 По цене - нормально. Считайте, 2 операц.усилителя (ОУ)это 100-150 рублей, платка, разъемы делали еще рублей 150, электрод дешевый - 600-700 рублей.....вообщем если сами бы собрали - получилось либо так же, либо дороже...Производители таких наборов выигрывают на эффекте масштаба производства. Понятно, что все преобразование предется писать самому, термокомпенсации нет, но ее можно реализовать, и если реализовывать то все равно пришлось бы программно, и что-то уж очень низкую точность указывают до 0,1 единицы.... Вообще, попадались и другие аналогичные наборы - может еще имеет смысл по-выбирать, по искать ? Для того чтобы сравнивать, и выбрать лучшее. |
|
#1953575 |
|
Посетитель
|
|
Z0RS насчет дисплея - китайцы мне все равно либо пришлют i2c модуль, либо вернут бабки - я пока 5 баксов запросил за 3 бакса я уже нашел подобный модуль на мой 2004 (четырехстрочный) дисплей. Вот тока ждать его еще 2-3 недели. потому и обидно. По поводу подключения без i2c - я в курсе, но по шине - решение изящней: лишние порты и проводов меньше. Думаю нагрузка на проц не сильно выше. Сильно поразила разница в размерах платы мега и нано. Я нано досель не видел. Така махонька, а скока могет. ПО Ph - мой химический тест от SERA имеет диапазон 4,5 - 9,0, шаг цветовой шкалы 0,5. Т.е. точность 0,25. Для пресняка вроде хватает. с учетом погрешностей 0,1 единицы набора вроде неплохо. А что дает термокомпенсация? Насколько она актуальна в полосе температур аквариума? сколько может наврать электрод при разнице температур градусов 5? И как калибровать все это? на плате только один потенциометр. Как я понимаю калибровать стоит по 3 точкам - желательно внизу, в середине и в конце диапазона. В наборе вообще тока одна бутылочка. А если еще температуру учитывать - тут вообще 9 точек калибровки минимум надо вводить. Программно я понимаю - имеем напряжение, по точкам калибровки привязываем их к значениям pH. промежуточные значения вычисляем линейной интерполяцией. Ну еще вводим поправку на температуру (благо датчиков температуры герметичных я набрал). С этим pH вообще вопросов полно - но запускать co2 без контроля стремно. Понятно, потом он нафик не нужен будет - процедура отладится и все заработает на "автомате", но пока заработает - можно и животину заморить. P.S. Еще глупый вопросик - как правильно подключить кнопку? Что-бы избежать дребезга? Задача запустить выполнение скрипта, который выполняется по времени по нажатию кнопки. Понятно, что на кнопку назначаем аппаратное прерывание и она запускает скрипт независимо от того наступило расчетное время или нет. пример: имеем NANO, кнопку. подключаем кнопку между D2 и +5V - нужен еще резистор 10 кОм от D2 на землю? Изменено 22.3.14 автор arch07 |
|
#1953634 |
Постоянный посетитель
|
|
arch07 Да. Для процессора разница в нагрузках, конечно, незначительна. Кстати, такие модули, которые используются с дисплеями, можно использовать для расширения количества портов ВВОДА/ВЫВОДА, без каких либо ограничений, и сложностей. Собственно, основой таких модулей и является микросхема - расширитель портов (IO ports expander). На микросхему PCF8574, на основе которой сделан I2C модуль для дисплея размерностью 16Х2, кстати есть готовая библиотека : https://github.com/s... Я обязательно, ее попробую, когда придут модули. Сделаю обзор, т.к. иногда требуется увеличить количество портов, из-за того, что некоторые вопросы и задачи не были учтены при покупке базовой модели платы ARDUINO. arch07 Ну "могет" то по большому счету - не плата, а микроконтроллер, на ней установленный. А размеры... да ...маленькие. arch07 Для Ваших требований к точности измерения pH - термокомпенсация даст не много. arch07 Для калибровки на плате вообще нет ничего. Плата то очень простая - это просто усилитель сигнала с очень высоким входным сопротивлением. Потенциометр, который на ней находится определяет коэффициент усиления предусилителя, и служит для согласования разных электродов с одной платой. Т.к. бывают электроды с сопротивлением в десятки мегоом (так называемые низкоомные) и в сотни и тысячи мегаом, для каждого из них, по идее необходимо менять входную часть, согласующую выходное сопротивление электрода и входное сопротивление предусилителя. Но иногда, в простейших случаях, пытаются это изменением коэффициента усиления (GAIN) сделать, для этого и потенциометр. Потом, может быть небольшой проблемой, отсутствие регулировки смещения напряжение на электроде. Плата выдаст смещенный (вот только не знаю на сколько, по идее нужно не менее 500 mV) и усиленный потенциал электрода. Назовем это "исправленным" потенциалом электрода. В Вашем случае калибровка будет выглядеть, как запоминание значения исправленного потенциала электрода в двух точках ( как правило с pH=7.0 pH=4.01). Наборы для приготовления буферных растворов с указанными pH - есть в продаже на ebay http://www.ebay.com/... Однако...они подорожали....я брал десяток по цене около 40 руб. Из этого набора нужны только 2 - с с pH=7.00 pH=4.01. Кстати о термокомпенсации - обратите внимание при какой температуре указнанные на упаковке значения pH соответствуют действительности. Калиброваться лучше по указанным pH, т.к. например буффер с pH=6.86 обладает меньшей точность, из за особенностей химических соединений входящих в состав. Если измеритель использовался бы в морском аквариуме то лучше калиброваться по точкам с pH=7.00 pH=10.01 Далее, при калибровке программа запомнит два значения и все остальные значения между ними или за ними, будут вычисляться как линейная интерполяция, с использованием простейшей функции вида f(x)= ax + b. Ну это в самом простейшем случае, и без термокомпенсации. Вообщем, Вы практически все правильно понимаете.....осталось дело за малым - реализовать... |
|
#1953684 |
Малёк
46
10 года |
|
Вот для этого кода нужно плавное включение света в заданное время и плавное выключение в другое заданное время. Помогите разобраться. |
|
#1954163 |
|
Постоянный посетитель
|
|
kirex05 Ваша основная ошибка - это использование конструкций типа нижеприведенной внутри главного цикла, т.е. внутри бесконечного безусловного цикла, организованного специальной и обязательной функцией loop() if(On_Time { if (Curent_Time >= On_Time && Curent_Time for(int fadeValue = 0; fadeValue { analogWrite(LR, fadeValue); } else for(int fadeValue = 255; fadeValue >= 0; fadeValue -=3) { analogWrite(LR, fadeValue); } } Эта конструкция буде много раз повторена в цикле и каждый раз при совпадении условий if (Curent_Time >= On_Time && Curent_Time будет выполнен ваш цикл изменения яркости for(int fadeValue = 0; fadeValue { analogWrite(LR, fadeValue); } Причем это будет выполнено с частотой процессора, т.е. яркость от 0 до 100 процентов будет увеличена за несколько микросекунд, что будет незаметно человеческому глазу....тем более у Вас шаг инкремента = 3. Т.е. пока условия выполняются светодиод будет вспыхивать с частотой главного цикла. Нарастание яркости будет очень кратковременным, а остальное время светодиод находится в состоянии максимальной яркости. В итоге, при этих условиях, светодиод будет гореть с яркостью чуть меньше максимальной.... Выход в том, чтобы делать приращения значения, которое пишется в аналоговый порт (ШИМ) не в каждом повторении главного цикла, а тогда когда это нужно, исходя из длительность периода увеличения яркости. Или можно, после функции analogWrite(LR, fadeValue); добавить задержку в цикл изменения яркости, например функцией delay(), подобрав в качестве аргумента значение, которое будет равно длительности периода увеличения яркости светодиода, выраженное в миллисекундах, деленное на 255. Но это очень и очень плохой путь...только для тестирования и опробования разных идей...для рабочей программы это использовать нельзя, т.к. delay() будет останавливать главных цикл loop() и контроль других событий времени - станет невозможным, или очень некачественным. Чтобы понять, как можно сделать, так чтобы главный цикл не был загружен задержками, и внутри него оставалась возможность обрабатывать другие события времени - посмотрите пример в данной теме с закатом и рассветом, там показано, как организовывать подобные конструкции внутри главного цикла loop(). Изменено 24.3.14 автор Z0RS |
|
#1954463 |
Малёк
46
10 года |
|
Z0RS Да поймите просто, что я в программировании почти полный ноль. Поэтому и прошу помощи у знающих людей. Я понял смысл того, что вы написали, но как воплотить всё это в реальность для меня проблема. |
|
#1954477 |
Постоянный посетитель
|
|
kirex05 Да все понятно.....просто пути стать более удаленным от нуля я Вам указал. Один из этих путей - это изучение и использование чужого опыта. Я еще раз предлагаю по-изучайте пример с рассветом и закатом. Это пример рабочий....он корректно отрабатывает в диапазоне одних суток, но можно изменив константу количества секунд в сутках заставить этот код отрабатывать и в других интервалах. Специально для вас привожу ссылку на обновленный код с расширенными комментариями: http://my-files.ru/4... А описание принципов работы - читайте на 2й странице темы. Код проще некуда. В главном цикле меньше 2х десятков строк кода. Некоторые строки разбиты на несколько частей для того чтобы код в редакторе убирался на ширину экрана, обычно я делаю такое разбиение по какому нибудь логическому или арифметическому оператору. Для того чтобы это исправить можно применить к тексту автоформатирование. Тогда, автоматический редактор приведет код к классическому виду с отступами по стандарту. Автоформатирование находится в меню сервис...может такой код для Вас будет нагляднее... В другом случае, если у Вас существует желание, ничего не изучать, и чтобы кто-то просто написал Вам полностью комплектное ПО для контроллера - то лучше обращаться к программистам фрилансерам на соответстующих сайтах...там бывает толковый народ со скромными запросами по оплате.... |
|
#1954558 |
|
Малёк
46
10 года |
|
Z0RS Спасибо за пример. Подскажите где я допустил ошибку. Не меняется максимальная яркость по каналам, всегда на максимум. #include //Подключаем библиотеку для использования I2C интерфейса с модулем RTC #include //Подключаем библиотеку для использования модуля часов реального времени RTC #define PWM_LW_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LW_MAX 128 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LW_PIN 11 //Пин порта, где будет ШИМ LW #define PWM_LR_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LR_MAX 200 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LR_PIN 3 //Пин порта, где будет ШИМ LR #define PWM_LB_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LB_MAX 255 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LB_PIN 12 //Пин порта, где будет ШИМ LB #define mn 60UL //Дополнительные константы для удобства #define hr 3600UL //Отражают соответствующие количества секунд #define d 86400UL RTC_DS1307 RTC; long sunrise_start = 11*hr+28*mn; //Начало восхода в 9 - 45 long sunrise_duration = 1*mn; //Длительность восхода 30 минут long sunset_start = 11*hr+30*mn; //начало заката в 21-15 long sunset_duration = 1*mn; //Длительность заката 30 минут long moonrise_start = 11*hr+30*mn ; //Начало луны в 9 - 45 long moonrise_duration = 1*mn; //Длительность восхода long moonset_start = 11*hr+32*mn; //Конец луны в 11 long moonset_duration = 1*mn; //Длительность заката луны //******************************************************************************************** void setup(){ Wire.begin(); //Инициируем I2C интерфейс RTC.begin(); //Инициирум RTC модуль analogWrite(PWM_LW_PIN, PWM_LW_MIN); //Пишем в порт минимальное значение analogWrite(PWM_LR_PIN, PWM_LR_MIN); analogWrite(PWM_LB_PIN, PWM_LB_MIN); //RTC.adjust(DateTime(__DATE__, __TIME__)); } // КОНЕЦ ИНИЦИАЛИЗАЦИИ //******************************************************************************************** void loop() // ПРОГРАММЫй безусловный ЦИКЛ { long pwm; DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла long Day_time = myTime.unixtime() % 86400; //сохраняем в переменную - время в формате UNIX //********************************************************************************************* // обработка интервала до восхода и после заката //********************************************************************************************* if ((Day_time (Day_time>=sunset_start+sunset_duration)) { //Или больше чем начало заката + длительность pwm = PWM_LW_MIN; //Величина для записи в порт равна минимуму pwm = PWM_LR_MIN; //********************************************************************************************* // обработка интервала восхода //********************************************************************************************* }else if ((Day_time>=sunrise_start) && //Если с начала суток больше чем начало восхода (Day_time pwm = ((Day_time - sunrise_start)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ pwm = ((Day_time - sunrise_start)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //********************************************************************************************* // обработка интервала заката //********************************************************************************************* }else if ((Day_time>=sunset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time pwm = ((sunset_start+sunset_duration - Day_time)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для заката величину для записи в порт ШИМ pwm = ((sunset_start+sunset_duration - Day_time)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm = PWM_LW_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ pwm = PWM_LR_MAX; } analogWrite(PWM_LW_PIN, pwm); //Пишем в порт вычисленное значение analogWrite(PWM_LR_PIN, pwm); // обработка интервала до восхода луны и после заката //********************************************************************************************* if ((Day_time (Day_time>=moonset_start+moonset_duration)) { //Или больше чем начало заката + длительность pwm = PWM_LB_MIN; //Величина для записи в порт равна минимуму //********************************************************************************************* // обработка интервала восхода луны //********************************************************************************************* }else if ((Day_time>=moonrise_start) && //Если с начала суток больше чем начало восхода (Day_time pwm = ((Day_time - moonrise_start)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ //********************************************************************************************* // обработка интервала заката луны //********************************************************************************************* }else if ((Day_time>=moonset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time pwm = ((moonset_start+moonset_duration - Day_time)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для заката величину для записи в порт ШИМ //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката луны, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm = PWM_LB_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ } analogWrite(PWM_LB_PIN, pwm); //Пишем в порт вычисленное значение }//------------Конец ЦИКЛА----------------------------- |
|
#1954578 |
Малёк
46
10 года |
|
Спасибо, уже разобрался |
|
#1954587 |
Постоянный посетитель
|
|
kirex05 Напишите точную маркировку вашего процессора на плате. И еще...этот код, который я привел в качестве примера нельзя "тупо в лоб" использовать для управления несколькими каналами ШИМ. Я проанализирую, что Вы напрограммировали и отвечу по-позже...пока ответьте по процессору... |
|
#1954593 |
|
Малёк
46
10 года |
|
Z0RS ATMEGA 2560 16AU 1346 Вот конечный результат: #include //Подключаем библиотеку для использования I2C интерфейса с модулем RTC #include "RTClib.h" //Подключаем библиотеку для использования модуля часов реального времени RTC // библиотека экрана #include "LiquidCrystal.h" LiquidCrystal lcd(8, 9, 4, 5, 6, 7); #define PWM_LW_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LW_MAX 128 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LW_PIN 11 //Пин порта, где будет ШИМ LW #define PWM_LR_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LR_MAX 200 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LR_PIN 3 //Пин порта, где будет ШИМ LR #define PWM_LB_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LB_MAX 235 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LB_PIN 12 //Пин порта, где будет ШИМ LB #define mn 60UL //Дополнительные константы для удобства #define hr 3600UL //Отражают соответствующие количества секунд #define d 86400UL RTC_DS1307 RTC; long sunrise_start = 11*hr+52*mn; //Начало восхода в 9 - 45 long sunrise_duration = 1*mn; //Длительность восхода 30 минут long sunset_start = 11*hr+54*mn; //начало заката в 21-15 long sunset_duration = 1*mn; //Длительность заката 30 минут long moonrise_start = 11*hr+54*mn ; //Начало луны в 9 - 45 long moonrise_duration = 1*mn; //Длительность восхода long moonset_start = 11*hr+56*mn; //Конец луны в 11 long moonset_duration = 1*mn; //Длительность заката луны //******************************************************************************************** void setup(){ Serial.begin(9600); lcd.begin(16, 2); // запускаем библиотеку экрана Wire.begin(); //Инициируем I2C интерфейс RTC.begin(); //Инициирум RTC модуль analogWrite(PWM_LW_PIN, PWM_LW_MIN); //Пишем в порт минимальное значение analogWrite(PWM_LR_PIN, PWM_LR_MIN); analogWrite(PWM_LB_PIN, PWM_LB_MIN); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); RTC.adjust(DateTime(2014, 7, 12, 22, 48, 1)); } //RTC.adjust(DateTime(2012, 7, 31, 21, 53, 1)); //RTC.adjust(DateTime(__DATE__, __TIME__)); } // КОНЕЦ ИНИЦИАЛИЗАЦИИ //******************************************************************************************** void loop() // ПРОГРАММЫй безусловный ЦИКЛ { analogWrite(10, 100); lcd.setCursor(0, 1); long pwm_LW; long pwm_LR; long pwm_LB; DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла long Day_time = myTime.unixtime() % 86400; //сохраняем в переменную - время в формате UNIX lcd.clear(); lcd.setCursor(11,0); lcd.print(myTime.hour(), DEC); lcd.print(":"); lcd.print(myTime.minute(), DEC); delay(1000); //********************************************************************************************* // обработка интервала до восхода и после заката //********************************************************************************************* if ((Day_time (Day_time>=sunset_start+sunset_duration)) { //Или больше чем начало заката + длительность pwm_LW = PWM_LW_MIN; //Величина для записи в порт равна минимуму pwm_LR = PWM_LR_MIN; //********************************************************************************************* // обработка интервала восхода //********************************************************************************************* }else if ((Day_time>=sunrise_start) && //Если с начала суток больше чем начало восхода (Day_time pwm_LW = ((Day_time - sunrise_start)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ pwm_LR = ((Day_time - sunrise_start)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //********************************************************************************************* // обработка интервала заката //********************************************************************************************* }else if ((Day_time>=sunset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time pwm_LW = ((sunset_start+sunset_duration - Day_time)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для заката величину для записи в порт ШИМ pwm_LR = ((sunset_start+sunset_duration - Day_time)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm_LW = PWM_LW_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ pwm_LR = PWM_LR_MAX; } analogWrite(PWM_LW_PIN, pwm_LW); //Пишем в порт вычисленное значение analogWrite(PWM_LR_PIN, pwm_LR); // обработка интервала до восхода луны и после заката //********************************************************************************************* if ((Day_time (Day_time>=moonset_start+moonset_duration)) { //Или больше чем начало заката + длительность pwm_LB = PWM_LB_MIN; //Величина для записи в порт равна минимуму //********************************************************************************************* // обработка интервала восхода луны //********************************************************************************************* }else if ((Day_time>=moonrise_start) && //Если с начала суток больше чем начало восхода (Day_time pwm_LB = ((Day_time - moonrise_start)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ //********************************************************************************************* // обработка интервала заката луны //********************************************************************************************* }else if ((Day_time>=moonset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time pwm_LB = ((moonset_start+moonset_duration - Day_time)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для заката величину для записи в порт ШИМ //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката луны, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm_LB = PWM_LB_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ } analogWrite(PWM_LB_PIN, pwm_LB); //Пишем в порт вычисленное значение }//------------Конец ЦИКЛА----------------------------- Изменено 25.3.14 автор kirex05 Изменено 25.3.14 автор kirex05 |
|
#1954597 |
Постоянный посетитель
|
|
kirex05 А этот код, который Вы привели в предыдущем сообщении - у меня работает. Я выкинул из него все что относится к LCD, т.к. он у меня не подключен, сделал для отладки длительность рассвета и заката по 3 минуты. По портам ШИМ на 11 пине и на 3 пине, этот код корректно отработал все интервалы. Кстати при отладке ненужно пихать в код всякую непотребщину...мне пришлось все это выкидывать и тратить на это время....больше я этого делать не буду... Приводите в пример очищенный кусок кода который можно компилировать и отлаживать сразу.... А что касается канала управления лунным светом, то с ним нужно поступать по другому... Т.к. тут есть переход через границу суток, то приведенный прием с ним работать не будет. Необходимо сделать другое время начала суток для отработки этого канала. Например, установим, что сутки для обработки лунного света начинаются в 20 часов ровно. В секундах это 72000. Ддя того, чтобы сменить время начала суток в системе UNIXTIME необходимо к прочтенному времени с RTC прибавить наше смещение, затем записать остаток от деления полученной величины в отдельную переменную и для обработки интервалов лунного света - использовать именно эту переменную. В коде нужно определить константу - смещение #drfine moonLightOffset 72000UL потом вот так мы определяем время начало суток для операций с дневным светом в 2х каналах: long Day_time = myTime.unixtime() % 86400; //сохраняем в переменную - время в формате UNIX А вот так нужно определить время начала суток для операций с лунным светом: long MoonDay_time = (myTime.unixtime() + moonLightOffset) % 86400; //сохраняем в переменную - время в формате UNIX НО интервалы восхода луны и заката луны - нужно задать относительно измененного вренени начала суток для луны, т.е. относительно Смещения - moonLightOffset. Например вот так: long moonrise_start = 2*hr+30*mn; //Начало восхода луны в 22 часа 30 минут (это с учетом смещения) long moonrise_duration = 30*mn; //Длительность восхода луны long moonset_start = 12*hr+45*mn; //Начало заката луны в 8 часов 45 минут (на следующие астрономические сутки) long moonset_duration = 30*mn; //Длительность заката луны И соответственно, в блоке проверки условий для луны использовать вышеприведенные переменные... Надеюсь, сами вставите это в код.... И еще....не используйте всеже функцию delay в главном цикле loop(). И в целях отладки не делайте длительность рассвета и заката равными одной минуте...делайте хотя бы 3 минуты. |
|
#1954662 |