Постоянный посетитель
|
ARDUINO для автоматизации аквариума (страница 4) |
Создал отдельную тему по вопросам использования простых и не дорогих плат 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 |
Малёк
46
10 года |
|
Z0RS Спасибо огромное. Вроде всё понял, буду переделывать. А что сделать чтобы обойтись без delay ? |
|
#1954676 |
|
Постоянный посетитель
|
|
kirex05 В вашем случае она вообще ненужна...а вообще можно использовать функцию millis() запоминать значение в некоторой переменной и сравнивать в главном цикле. Такой подход обеспечить непрерывность и скорость выполнения главного цикла...но свои НО также имеются.... |
|
#1954684 |
Малёк
46
10 года |
|
Z0RS Понял, убрал. |
|
#1954695 |
Малёк
46
10 года |
|
Извините за наглость, но может поможете ещё с кнопками. |
|
#1954700 |
Малёк
46
10 года |
|
Я пока кнопку держу H2 выключается, отпускаю кнопку он опять включается. |
|
#1954701 |
|
Постоянный посетитель
|
|
kirex05 Ну вообще управлять нагрузкой в стрктуре опроса кнопок - это моветон.... Лучше делать это через промежуточную переменную. Т.е вы изменяете переменную взависимости от нажатия кнопок, а потом в главном цикле на порту, который отвечает за нагрузку устанавливаете состояние в зависимости от промежуточной переменной.... То, что в каждом повторении главного цикла будет выполнятся функция digitalWrite(pin, вашаПеременная) - ничего страшного нет... |
|
#1954724 Нравится Дэмиан
|
Малёк
46
10 года |
|
Z0RS Смысл понял, а вот как воплотить это для меня опять прблема. |
|
#1954728 |
Постоянный посетитель
|
|
kirex05 Всмысле "проблема" ? Яж все подробно написал. Я уж не буду кейсы по обработке клавиш описывать. А в главном цикле для каждого порта должна быть функция, указанная выше. Но это в простейшем случае...если нагрузкой требуется и в ручную и автоматически управлять, то еще понадобится переменная-флаг для хранения режима управления нагрузкой. А в главном цикле потребуется проверка этого флага и соответствующие действия. И еще...у Вас в коде нет защиты от дребезга контактов....а кнопки его (дребезг имеется ввиду) имеют...посмотрите как это делается по поиску фразы "arduino debounce". http://arduino.cc/en... вот здесь простейший пример по ликвидации дребезга. |
|
#1954735 |
|
Малёк
46
10 года |
|
Z0RS Да не разберусь я нифига. И управление нужно и в ручную и в автомате. С дребезгом всё понял. Может я выложу свой код, а вы мне поможете с кропками? |
|
#1954743 |
Посетитель
|
|
Z0RS Очень прошу также сопровождать хотя бы ориентировочной калькулляцией по стоимости комплектующих. Также предлагаю обсудмть, ведь немного среди аквариумистов программистов - электронщиков, сколько можно добавить человеку, взявшемуся комплектовать и прошивать готовые изделия (вопрос корпуса - отдельная песня!) и снабжать ими заинтересованных. Учтите, приобретение плат - довольно долгая песня, почта у нас неспешна. |
|
#1954750 |
Постоянный посетитель
|
|
kirex05 В тему - не надо...на файлообменник выкладываете..сюда например http://my-files.ru/ А в тему ссылку. Посмотрю на досуге... сообщение FoxBat А Вы тему с конца читаете? Вообще в первом сообщении темы - цены на некоторые комплектующие были указаны....и где их можно посмотреть вслучае чего... сообщение FoxBat Вы не предлагайте, а начинайте обсуждать, я присоединюсь обязательно.... сообщение FoxBat Нет никакого вопроса с корпусом - есть множество вариантов...я иногда использую например пластиковые протяжные коробки по 90 рублей за шт. оргстекло и стойки латунные для монтажа плат. Вопросы с корпусом есть только у ленивых... сообщение FoxBat 3-4 недели в среднем.....из Тайваня и Китая...по России до 2 недель доходило, а в основном дней 5-6... Изменено 25.3.14 автор Z0RS |
|
#1954776 |
|
Малёк
46
10 года |
|
сообщение Z0RS Код выложил, вот ссылка: http://dropmefiles.c... |
|
#1954808 |
Малёк
46
10 года |
|
Вот так вот работает от одной кнопки |
|
#1955108 |
Завсегдатай, Кандидат в Советники
|
|
Z0RS Сижу и играюсь с вкл/выкл реле и димированием диодов и, честно говоря, надоело громоздкое написание времени событий либо в секундах unix или в виде типа "у*hr+х*mn". Подумал и попробовал задать значения времени через команду #define. К примеру, включение ламп (рассвет) в 8:00 зададим так #define SunRise 8*hr (или 28800 в секундах unix). Соответственно, в командах "if" или "else if" можно писать не время цифрами, а название события, т.е. SunRise. Мне кажется, это удобнее, особенно если одно и то же временное значение повторяется в нескольких местах. Стоит однажды его задать в начале скетча - и все. Проверил подобный скетч в программе - ошибок комп не нашел. На саму ардуину еще не компилировал, уже поздно, но на выходных попробую. Должно работать, вроде. ЗЫ. И вопрос - а можно ли задавать повторяющееся событие раз в 4 недели (это для "лунной подсветки", имитация полнолуния так сказать)? Изменено 26.3.14 автор Дядька-рыбомор Изменено 26.3.14 автор Дядька-рыбомор |
|
#1955330 |
|
Постоянный посетитель
|
|
сообщение Дядька-рыбомор Вообще, директива препроцессора #define для этого и задумывалась. Это директива макроподстановки. Поэтому необходимо помнить, что насколько бы короткое имя вы не придумали (левая часть) для правой части этой директивы ( а в правой части могут быть не только цифры, но и куски кода) все эти подстановки в коде при компиляции будут заменены на то, что будет содержаться в правой части этой директивы, и соответственно общий размер кода будет увеличен. В простейших случаях - да....удобство, но в более сложных случаях можно за удобство заплатить размером кода...а в случае AVR микроконтроллеров (и не только для тех, на основе которых построены платы ARDUINO) оптимизация размера кода - это актуально.... сообщение Дядька-рыбомор Вы о каком куске кода сейчас спрашиваете. Если о многокомандном таймере - то может обрабатыватся любой период с дискретностью одна секунда.....от одной и более... ...раз в 4 недели это .... 4 недели х 7дней х 24часа х 60минут х 60секунд = 2419200 секунд.... Это значение вставьте во второй параметр задания, и задание будет выполнятся раз в 4 недели. А если Вы так....теоретически спросили - то вообще нет проблем...запрограммировать можно все, что можно себе представить.... |
|
#1955373 |
Малёк
46
10 года |
|
Z0RS Здравствуйте. Вы не смотрели мой код? А то я так и не добился результата. |
|
#1955389 |
Постоянный посетитель
|
|
сообщение kirex05 Я посмотрел бегло....что сказать..очень много ошибок, особенно в условных выражениях. Я если честно, не всегда понимаю, как их разберет компилятор. Вы раньше на чем-то программировали? Это всего скорее не был язык Си или Си++. Вы поработайте над кодом еще...ближе к выходным посмотрю по-подробнее.... |
|
#1955400 |
|
Малёк
46
10 года |
|
сообщение Z0RS Да я же писал, что в программировании почти полный ноль. Данный код был составлен из нескольких, найденых на просторах интернета. Но он вроде работает, осталось только с кнопками разобраться. От этого весь процесс встал, рыбок просто жалко. Два дня уже сижу мудрю с условиями, переменными, флагами, а толку ноль. Спасибо, что не отказываете в помощи. |
|
#1955402 |
Завсегдатай, Кандидат в Советники
|
|
сообщение Z0RS Спасибо, понял. Просто я вообще не программист, последний раз еще в школьном кружке на бейсике году в 1990 примерно... Так что это вам, как профи, очевидно, а для меня это маленькое личное открытие , которое показывает, что я на правильном пути. Вы о каком куске кода сейчас спрашиваете. Если о многокомандном таймере - то может обрабатыватся любой период с дискретностью одна секунда.....от одной и более... Да, я именно о многокомандном таймере, вы правы. Т.е. меняем DAILY на необходимое временное значение, и задание будет выполняться с периодичностью хоть неделя, хоть год, я правильно понял? Изменено 27.3.14 автор Дядька-рыбомор |
|
#1955771 |
Постоянный посетитель
|
|
Дядька-рыбомор Абсолютно верно... Есть в этом методе и свои ограничения: "раз в месяц" - таким образом сделать не удастся - т.к. "месяц" понятие нечеткое - может 30 дней содержать, может 31, а может вообще 28. Для того, чтобы запрограммировать какое-то действие, которое должно, например, выполнятся 2 числа каждого месяца - его придется программировать отдельно и чуть сложнее... |
|
#1955838 |
|
Малёк
46
10 года |
|
Z0RS Простите за мою наглость, но осмелюсь спросить по поводу моей просьбы. |
|
#1955864 |
Завсегдатай, Кандидат в Советники
|
|
сообщение Z0RS Это понятно. Но относительно луны все довольно просто: лунный цикл между двумя полнолуниями примерно 29,5 суток, поэтому лунные ночи можно довольно просто запрограммировать. Насколько это имеет практическое значение для аквриумных растений (скорее это важнее для рыб)я не знаю, но теоретически интересно. |
|
#1955897 |
Постоянный посетитель
|
|
kirex05 Спросить можно....но я Вам и так уже не раз дал понять, что копаться в чужих кодах - особой заинтересованности нет у меня. Вообще, работа по оптимизации кода - одна из самых сложных работ...и у меня есть другие интересы, кроме как убивать свое свободное время на то, чтобы у кого-то хорошо получилось...Потом, обработка меню - это не самое любимое занятие...ну не хочется мне это делать...я и для себя этот момент всячески обхожу...Кнопок с опросом по аналоговому сигналу - у меня тоже нет, чтобы проверить некоторые моменты. Я не знаю, есть ли дребезг значений у такого способа опроса кнопок. Потом.... Вы сами то тоже работайте над кодом. Идеи я вам озвучил но могу более расширенно повторить... Главная идея, которая должна быть реализована в программах на однопоточных микроконтроллерах - это "короткий" по времени исполнения главный цикл. Поэтому Обработку события нажатия на кнопку, и реакцию на нажатие нужно разделять.... В одном месте необходимо зафиксировать нажатие на кнопку изменением состояния переменной флага. Это сделать в структуре условного оператора if или в структуре множественного выбора case. И все..из структуры нужно выходить, а в главном цикле сделать простую строчку (или несколько) - изменение состояния порта в соответствие с установленным флагом, типа этого: digitalWrite(pinOutPort_01, flagOutPort_01); Эта строка должна быть в теле главного цикла в самой левой позиции, т.е. не должна входить ни в какие условные операторы. Не нужно боятся что, в каждом повторении главного цикла будет выполнятся запись в порт одного и того же значения. От этого состояние порта - не изменяется. Флаг состояния порта можно менять по нескольким кнопка и по разным условиям. И лучше, если флаг состояния будет обрабатываться в одном проходе по главному циклу, а изменение состояния порта в другом...специально для этого ничего делать ну нужно, просто указанная строка с функцие записи в порт должна быть по ходу кода выше чем условные операторы, отвечающие за изменение состояния флага. Потом, если порт управляется какой-то програмной частью, то необходимо ввести еще один флаг. Флаг режима работы - ручной/автоматический (0/1). И обходить часть кода, которая отвечает за выявление условий изменения состояния порта в автоматическом режиме, когда этот флаг установлен в 0. Попробуйте это реализовать в тестовом примере. Это основная концепция...Таким образом можно обрабатывать некоторое количество портов. Когда количество портов станет довольно большим, и в одном проходе по главному циклу их будет обрабатываться большое количество таким образом, что длительность главного цикла станет критичной - тогда порты будет необходимо обрабатывать по одному в каждом проходе, или по нескольку, выбирая обрабатываемый порт из массива, а указатель массива инкременировать "по кругу" - т.е. до максимума количества портов и затем сброс на первый элемент массива. Вообще, если в программе порты обрабатываются в единой концепции и в количестве больше 2 - лучше применять массивы, это сложнее, но программный код становиться во много раз компактнее и легко читаемым и очень масштабируемым. Потом ненужно использовать конструкции, уравнивающие булиновкие выражения типа A |
|
#1955985 |
|
Малёк
46
10 года |
|
Z0RS Да я не прошу оптимизировать мой код, и меню мне тоже не надо. Мне нужна только возможность включения и выключения света LW и LR кнопками (UP-Вкл., DOWN-Выкл.), независимо от времени. А также возможность включения и выключения нагревателя Н2 кнопками (LEFT-Вкл., RIGHT-Выкл.), независимо от температуры. А с дребезгом я сам разберусь. Просто поймите меня, я в программировании не силён. Вот и прошу пмощи у добрых людей. Изменено 28.3.14 автор kirex05 |
|
#1956000 |
Постоянный посетитель
|
|
kirex05 Понимаете, включая или выключая свет принудительно нажатием кнопки, вы должны потом как-то вернутся в автоматический режим, либо по нажатию кнопки либо по другому событию. По какому событию вы хотите восстанавливать автоматический режим? |
|
#1956101 |