Автополив
- Войдите на сайт для отправки комментариев
Здравствуйте, в Ардуино я новичок, прошу сильно не пинать и помочь мне! Решил сделать автополив растений. Программу собрал сам из разных скетчей найденных в сети. Логика проста, в определенное время по часам на датчик влажности подается +5В и он начинает работать(якобы он быстро выходит из строя если постоянно под напряжением), если почва сухая поливает 4 секунды и ждет 1 минуту. Попутно выводится текущая влажность, время, и кол-во раз полива(своеобразная проверка мной Ардуины - если счетчик растет значит поливает)
Не могу избавиться от последнего delay в 4 сек, на это время как вы понимаете информация на дисплее замирает. Вот код
#include <DS3231.h> #include <Wire.h> // Comes with Arduino IDE #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); DS3231 rtc(SDA, SCL); Time RTC_T; const int HUMIDY_MIN = 700; const int HUMIDY_MAX = 300; int i=0; boolean flag = 0; unsigned long new_time = 0; #define POMPA_PIN 8 #define HUM_PIN 7 void setup(void) { //инициализируем часы rtc.begin(); //инициализируем дисплей lcd.begin(16,2); // включаем подсветку lcd.backlight(); // set cursor to positon x=0, y=0 lcd.home(); //POMPA_PIN пин управляет ПОМПОЙ pinMode(POMPA_PIN, OUTPUT); //HUM_PIN пин подает +5В на датчик влажности A3 pinMode(HUM_PIN, OUTPUT); digitalWrite(POMPA_PIN,HIGH); digitalWrite(HUM_PIN,LOW); } void loop(void) { lcd.setCursor(0, 0); static unsigned long wait = millis() + 60000; static unsigned int oldhumidy = 0; unsigned int humidy = analogRead(A3); if(humidy != oldhumidy && humidy >100) { oldhumidy = humidy; } ////выводит на дисплей показания влажности с задержкой 1с if(!flag){ flag=1; new_time=millis()+1000; } else if(millis() > new_time){ flag=0; lcd.clear(); lcd.print(humidy); lcd.setCursor(POMPA_PIN, 0); lcd.println(rtc.getTimeStr()); lcd.setCursor(0, 1); //печать счетчика полива(если значение растет,значит поливает) lcd.print(i); } //// /////управляет питанием датчика влажности А3 по времени RTC_T = rtc.getTime(); if (RTC_T.hour == 18 && RTC_T.min == 25) { digitalWrite(HUM_PIN,HIGH); } if (RTC_T.hour == 18 && RTC_T.min == 27) { digitalWrite(HUM_PIN,LOW); } ///// if(wait != 0 && wait-millis() > 10) { return; } else wait = 0; if(humidy > HUMIDY_MIN) { i++; digitalWrite(POMPA_PIN, LOW); delay(4000); digitalWrite(POMPA_PIN, HIGH); wait = millis() + 1*60000; } }
Пробовал разные варианты millis(), см. ниже, который не работают. Так же пробовал на примере кода с 46 по 59 строку избавиться от delay так же не выходит.
Одна и таже ошибка
#include <DS3231.h> #include <Wire.h> // Comes with Arduino IDE #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); DS3231 rtc(SDA, SCL); Time RTC_T; const int HUMIDY_MIN = 700; const int HUMIDY_MAX = 300; int i=0; boolean flag = 0; unsigned long new_time = 0; unsigned long previousMillis= 0; #define POMPA_PIN 8 #define HUM_PIN 7 void setup(void) { //инициализируем часы rtc.begin(); //инициализируем дисплей lcd.begin(16,2); // включаем подсветку lcd.backlight(); // set cursor to positon x=0, y=0 lcd.home(); //POMPA_PIN пин управляет ПОМПОЙ pinMode(POMPA_PIN, OUTPUT); //HUM_PIN пин подает +5В на датчик влажности A3 pinMode(HUM_PIN, OUTPUT); digitalWrite(POMPA_PIN,HIGH); digitalWrite(HUM_PIN,LOW); } void loop(void) { lcd.setCursor(0, 0); static unsigned long wait = millis() + 60000; static unsigned int oldhumidy = 0; unsigned int humidy = analogRead(A3); if(humidy != oldhumidy && humidy >100) { oldhumidy = humidy; } ////выводит на дисплей показания влажности с задержкой 1с if(!flag){ flag=1; new_time=millis()+1000; } else if(millis() > new_time){ flag=0; lcd.clear(); lcd.print(humidy); lcd.setCursor(POMPA_PIN, 0); lcd.println(rtc.getTimeStr()); lcd.setCursor(0, 1); //печать счетчика полива(если значение растет,значит поливает) lcd.print(i); } //// /////управляет питанием датчика влажности А3 по времени RTC_T = rtc.getTime(); if (RTC_T.hour == 18 && RTC_T.min == 25) { digitalWrite(HUM_PIN,HIGH); } if (RTC_T.hour == 18 && RTC_T.min == 27) { digitalWrite(HUM_PIN,LOW); } ///// if(wait != 0 && wait-millis() > 10) { return; } else wait = 0; if(humidy > HUMIDY_MIN) { i++; digitalWrite(POMPA_PIN, LOW); if(POMPA_PIN==LOW){ if (millis() -previousMillis >4000) previousMillis = millis(); digitalWrite(POMPA_PIN, HIGH); } wait = millis() + 1*60000; } }
Не нашел как редактировать сообщение.
В кодах ошибка в 1м в 54 строке lcd.setCursor(8, 0); и во 2м в 55 lcd.setCursor(8, 0);
Неудачно поигрался с автозаменой.
Обратите внимание на строку 80 в последнем скетче - какая-то она несбыточная )).
Спасибо, заменил на if(digitalRead(POMPA_PIN)==LOW){
та же ошибка проблема не решена.
эм, это что?
lcd.setCursor(8, 0);
это ошибка автозамены, в коде все верно. Пытался привести код в более наглядный вид.
Спасибо, заменил на if(digitalRead(POMPA_PIN)==LOW){
та же ошибка проблема не решена.
У Вас пин сконфигурирован как pinMode(POMPA_PIN, OUTPUT); , поэтому digitalRead() работать не будет.
Заведите переменную, какой-нибудь boolean pompaState, и работайте с портом через неё.
Спасибо, заменил на if(digitalRead(POMPA_PIN)==LOW){
та же ошибка проблема не решена.
У Вас пин сконфигурирован как pinMode(POMPA_PIN, OUTPUT); , поэтому digitalRead() работать не будет.
Заведите переменную, какой-нибудь boolean pompaState, и работайте с портом через неё.
По идее данная конструкция работать должна, строки типа "digitalWrite(led,!digitalRead(led));" отрабатываются вполне корректно.
Да, Вы правы, я попробовал - digitalWrite(led,!digitalRead(led)); работает.
Уважаемый Araris, возможно из-за того что сейчас утро, а может это никак не связано, я не могу изменить код с добавлением в него boolean pompaState. А точнее как я буду делать digitalWrite... Каждый раз добавлять pompaState =!pompaState ??
Управление пинами через переменные - это не необходимость, это, скорее, концептуальное, на будущее. Не хочу повторяться, тем более, что совсем недавно вот здесь http://arduino.ru/forum/programmirovanie/tft-24-touch-shield-nuzhna-pomoshch-v-programmirovanie-knopok-na-ekrane#comment-146768 я пытался описать такой подход.
Я изменил,так правильно? код писал с др. ПК попробовать смогу только позже, но ведь логики мы не меняли.
с pinMode() так ничего и не понял нужно объявлять OUTPUT чтоб управлять реле POMPA_PIN, или и без данной команды можно устанавливать состояние для POMPA_PIN
Чудеса, последний код, скомпилировался нормально, при подключении к ардуино не вгрузился с тойже ошибкой. потом я закрыл открыл Ардуино 1.6.6, код скомпилировался нормально, подключил плату, вгрузил все ОК.
Счетчик растет, но POMPA_PIN 8 никак не управляет реле, оно молчит и не щелкает.
UPD: загрузил скетч из первого поста, реле щелкает - значит физически все подключено правильно.
1. Ошибка "collect2.exe: error: ld returned 5 exit status" к конкретному скетчу отношения не имеет, это неполадки с Arduino IDE на конкретном компьютере. Проблема описана неоднократно, способы устранения - тоже.
2. Насчет использования переменной состояния реле - мне показалось, что Вы пока не до конца понимаете, зачем оно вообще надо. Будете программировать - понимание само придёт, всему свое время.
3. Пин, конечно же, надо переводить в режим OUTPUT.
Моя помпа питается от 220в. Реле на транзисторе п-н-п типа на POMPA_PIN разрывает фазу в эл. Цепи. При digitalWrite(POMPA_PIN, LOW) реле срабатывает и начинает полив, при digitalWrite(POMPA_PIN, HIGH) реле снова разрывает фазу и полив прекращается.
Уважаемый Araris, я очень благодарен за оказанную помощь и найденные ошибки. Для меня Вы говорите, почти загадками. Я посмотрю в сети инфу касаемо моей ошибки. Означает ли то что мой код верный, и не требует исправлений.
Если это возможно опишите человеко понятным языком, то что описано здесь ниже, millis() очень тяжело мне дается.
Про работу с миллис неплохо рассказано у Лешака
Если это возможно опишите человеко понятным языком, то что описано здесь ниже, millis() очень тяжело мне дается.
ОК, попробую. Надеюсь, по ссылке данной уважаемым bwn, Вы уже сходили, оно того стоит, я тоже на текстах Лешака многое постигал.
Для начала пару слов про millis(). После каждого запуска/ресета ардуиновский процессор начинает с нулевого значения отсчет, так сказать, внутреннего времени. Узнать, сколько там "натикало" мы можем, в частности, вызвав функцию millis(). Она вернет количество миллисекунд с момента старта/рестарта нашего скетча. Всегда иметь текущее значение внутреннего времени - чертовски удобно для множества применений, поэтому разобраться и понять millis() всё-равно Вам придется.
Есть важный нюанс: через приблизительно 50 дней работы скетча количество миллисекунд становится настолько большим, что не помещается уже в переменную типа unsigned long. Происходит переполнение, но это не страшно, просто millis() обнуляется и отсчет начинается с нуля. Этот нюанс надо учитывать для "долгоиграющих" устройств на Ардуино, Ваше к ним относится.
Теперь к скетчу.
Благодарю bwn и Araris за предоставленную информацию и помощь.
1. Да меня как новичка этот хитрый отрезок кода просто повергает в ужас. Если вернуться к скетчу из 1го поста
static
unsigned
long
wait = millis() + 60000; находится внутри loop, а значит при возврате на return в начало loop, wait примет новое значение? ведь millis() не обнуляются в начале loop.
В этом выражении wait-millis() > 10) wait выходит все время растет, также как и растет millis().
2. датчик влажности почвы возвращает значения от 0 до 1023, где 0 абсолютно мокро и 1023 абсолютно сухо. т.е. датчик если его не поливать, будет нам возвращать значения стремящиеся к 1023
выражение (humidy > HUMIDY_MIN) говорит, если текущее значение влажности суще(больше) чем минимальная влажность(самая сухая почва, при которой требуется полив) то полей.
3. нашел в сети еще один вариант как избавиться от моего delay() и адаптировал под свои нужны
и выяснил что ld.exe у меня рушится на стадии объявления библиотек, когда я раскоментировал пару строчек. Да у меня ВинХР. Буду пробовать переносить все на др. пк на вин7. Также и boolen pompaState рушила ld.exe
Araris , эта тема давно обсуждаема... про крах систем при переходе с 1999 на 2000 - давно забыли , так и с миллис()
например:
пусть период отслеживания 1000 mS
пусть крайняя фиксация миллис()=FFFFFE0C=4294966796 - это за 500 mS до переполнения
следФиксация миллис()=000001F4=500 - это спустя 500 mS после переполнения
вычисления:
в данной разрядной сетке , и по правилам вычитания - вычитание заменяется на сложение с дополнительным кодом вычитаемого значения
результат:
newMillis() - oldMillis() = 000001F4 - FFFFFE0C = 000001F4 = 000003E8 => 1000 mS
в чём проблема-то ?
она будет если период слежения больше периода переполнения миллис()....
...тогда нужно учесть колво переполнений и вычислить реальное значение
нет ?
1. Да меня как новичка этот хитрый отрезок кода просто повергает в ужас. Если вернуться к скетчу из 1го поста
static
unsigned
long
wait = millis() + 60000; находится внутри loop, а значит при возврате на return в начало loop, wait примет новое значение? ведь millis() не обнуляются в начале loop.
В этом выражении wait-millis() > 10) wait выходит все время растет, также как и растет millis().
2. датчик влажности почвы возвращает значения от 0 до 1023, где 0 абсолютно мокро и 1023 абсолютно сухо. т.е. датчик если его не поливать, будет нам возвращать значения стремящиеся к 1023
выражение (humidy > HUMIDY_MIN) говорит, если текущее значение влажности суще(больше) чем минимальная влажность(самая сухая почва, при которой требуется полив) то полей.
3. нашел в сети еще один вариант как избавиться от моего delay() и адаптировал под свои нужныи выяснил что ld.exe у меня рушится на стадии объявления библиотек, когда я раскоментировал пару строчек. Да у меня ВинХР. Буду пробовать переносить все на др. пк на вин7. Также и boolen pompaState рушила ld.exe
1. Да и плюньте на него. Замечу ещё раз, что в скетче
static
unsigned
long
wait = millis() + 60000;
выполняется один раз - почитайте про static, неспроста он там. Переменная wait, а также любая другая, в которую Вы будете помещать значения millis() - растет, так и должно быть, а почему - уже знаете.2. С датчиком вопрос снимается, я думал, что чем больше значение, тем больше влажность.
3. Этот код мною лучше понимается, думаю, и Вам легче будет.
С ld.exe разберётесь, Вы не первый попавший, проблема известная.
...
в чём проблема-то ?
она будет если период слежения больше периода переполнения миллис()....
...тогда нужно учесть колво переполнений и вычислить реальное значение
нет ?
Ой, извините, я не все понял про вычисления в разрядной сетке, я лучше своими словами напишу. В моём понимании проблема в том, что я повсюду использую конструкцию вида
if ( millis() - mySavedMillis ) > myDuration ) { ....... mySavedMillis = millis(); } , подразумевая, что у меня millis() всегда больше mySavedMillis. Но это не так, после переполнения я получу millis() гораздо меньший, чем mySavedMillis, и все мои ifы перестанут работать.
Поэтому для каждого такого ifа я пишу проверку вида
if ( millis() < mySavedMillis ) mySavedMillis = millis(); , имея себе в виду "ну пропустим срабатывание таймера раз в 49 дней 17 часов - да и фиг с ним."
Araris ,
не , не так.... не станет после преполнения миллис()=0 , вернее станет - на 1 mS.... а потом станет 1,2,3,4,5,6......4294967295
и на каждом проходе лупа произойдёт описанное выше....
В моём понимании проблема в том, что я повсюду использую конструкцию вида
1 - if ( millis() - mySavedMillis ) > myDuration ) { ....... mySavedMillis = millis();
...не забываем , что перед этими операторами mySavedMillis уже имеет некоторое значение
приведи пример "на пальцах" - когда не сработает 1
myDuration=10
mySavedMillis=FFFFFFFB=4294967291 ( за 5 mS до переполнения )
далее по лупу и по изменению миллис() ( пусть лууп имеет длину - 0 )
millis() - mySavedMillis =
FFFFFFFС - FFFFFFFB = 1 < 10
FFFFFFFD - FFFFFFFB = 2 < 10
FFFFFFFE - FFFFFFFB = 3 < 10
FFFFFFFF - FFFFFFFB = 4 < 10
00000000 - FFFFFFFB = 5 < 10
00000001 - FFFFFFFB = 6 < 10
00000002 - FFFFFFFB = 7 < 10
00000003 - FFFFFFFB = 8 < 10
00000004 - FFFFFFFB = 9 < 10
00000005 - FFFFFFFB = 10 < 10
00000006 - FFFFFFFB = 11 < 10 - ( millis() - mySavedMillis ) > myDuration ) - сработало !
if ( millis() - mySavedMillis ) > myDuration ) { ....... mySavedMillis = millis(); } , подразумевая, что у меня millis() всегда больше mySavedMillis. Но это не так, после переполнения я получу millis() гораздо меньший, чем mySavedMillis, и все мои ifы перестанут работать.
это не важно , что меньше !!!!!!!!!!!
важно то , что "расстояние" от того до этого , при условии постоянного увеличения значения миллис() - не зависит от перехода через переполнение миллис().....
засекли время = 23:00 , ждём интервал 2 часа......
в 01:00 разница составит именно 2 часа ( если не использовать разрядную сетку с учётом числа месяца )
операция 1+24-23=2 в системе миллис() решается "автоматически" = разрядная сетка и правила вычитания
кататак :)
Уважаемый SU-27-16 в коде который используется в скетче по вашему мнению есть защита от переставания срабатывания алгоритма через 50 дней?
01
static
unsigned
long
wait = millis() + 60000;
02
if
(wait != 0 && wait-millis() > 10) {
03
return
;
04
}
else
wait = 0;
05
06
if
(humidy > HUMIDY_MIN) {
07
i++;
08
digitalWrite(POMPA_PIN, LOW);
09
delay(4000);
10
digitalWrite(POMPA_PIN, HIGH);
11
wait = millis() + 1*60000;
12
}
и смотреть не хочется ( такой проблемы нет )...
я не вам всё это написал....
:)-
тревожит строка 01 в #25
зачем это ?
переход с абсолютной точки отсчёта к относительной и потом наоборот ? зачем ?
а весь крайний код выложить - не помешало бы.... чем куски обсуждать....
нет ?
есть только миг между миллис() и олдМиллис - зачем плодить "производные" от их разницы и потом смещать это значение на то , что выше ??
Спасибо за ответ.
Можно вообще убрать эти +60000, это не особо важно, а весь код например из 1го поста - второй
if ( millis() - mySavedMillis ) > myDuration ) { ....... mySavedMillis = millis(); } , подразумевая, что у меня millis() всегда больше mySavedMillis. Но это не так, после переполнения я получу millis() гораздо меньший, чем mySavedMillis, и все мои ifы перестанут работать.
это не важно , что меньше !!!!!!!!!!!
важно то , что "расстояние" от того до этого , при условии постоянного увеличения значения миллис() - не зависит от перехода через переполнение миллис().....
засекли время = 23:00 , ждём интервал 2 часа......
в 01:00 разница составит именно 2 часа ( если не использовать разрядную сетку с учётом числа месяца )
операция 1+24-23=2 в системе миллис() решается "автоматически" = разрядная сетка и правила вычитания
кататак :)
Всё, я понял, знака же там нет, они же unsigned !
Я ошибочно исходил из того, что 00000000 - FFFFFFFB = -5, а отрицательное число никогда не будет > myDuration. Блин, ганьба. Ещё раз перечитал http://playground.arduino.cc/Code/TimingRollover , где мои глаза раньше были ?
Спасибо большое, SU-27-16, в лоно истины меня вернули.
*посыпая голову пеплом, побрёл выжигать ересь из старых скетчей )).
Ещё раз перечитал http://playground.arduino.cc/Code/TimingRollover , где мои глаза раньше были ?
а мои - где ? я вообще такого не видел ! :)-
....надо будет прочитать :)
*посыпая голову пеплом, побрёл выжигать ересь из старых скетчей )).
зачем так круто ? работает - и пусть работает....
Блин, ганьба.
это что такое ? "ридна мова" ? я за 5 лет не смог постичь всю глубину и красоту....
песня есть... и любовь и ганьба... примерно понял - что это такое ....
:)
Это я разволновался, в данном случае переводится как "позорище" )).
...понял
:)
Сейчас у Вас датчик влажности включен постоянно (
digitalWrite(HUM_PIN,HIGH);
//заменить на LOW по окончании отладки.
).А что будет с измерением влажности, когда датчик начнет включаться (18:25) и выключаться (18:27) по часам ? В строке 40 ведь никто не проверяет, включен ли датчик в данный момент времени ?
И ещё, если датчик влажности работает всего две минуты в сутки, то перерыв между включениями помпы (1 минута) не слишком ли велик ? Ну, или наоборот, две минуты на работу датчика - не мало ли будет ? Может полив заканчивать стоит не по времени, а по достижении HUMIDY_MAX, незаслуженно забытой ?
Датчик без питания возвращает 0. Поливать вероятно лучше днём, вечером этого не делают. Интервалы безусловно нужно ещё опытным путём выбирать. В большинстве времени я работал с нагрузкой в виде лампы, помпу я подключал всего раз в самом начале, поэтому объёмы воды(секунды) у меня не выверены ещё. Касаемо датчика отметил что буквально за полчаса нахождения под напряжением в почве контактные дорожки датчика были заметно съедены. Поэтому чем меньше датчик будет работать, тем лучше. Да и анализировать влажность почвы чаще раза в день не нужно. Садовод я просто нулевой, поэтому я и отказался от himidy_max, потому что боюсь залить. Сейчас логика очень проста в текущей настройке он скорее будет недоливать чем пере. Хочу подобрать интервал работы датчика и помпы таким, чтобы включившись датчик запустил помпу подождал минуту, убедился в изменении влажности(стала меньше 700), выключился(как раз эти 2-3 минуты).
Также остались не решенными проблемы переполнения, первое и самое простое, что приходит в голову, поставлю счётчик на дни и буду ресетить на 49день, хотя и надеюсь что с вашей помощью найду более правильное решение. И проблемы зависания ардуины, что наверное самое главное, т.к. замечал что по мере моего взаимодействия с ардуино, периодически скетчи зависали.
Также остались не решенными проблемы переполнения, первое и самое простое, что приходит в голову, поставлю счётчик на дни и буду ресетить на 49день, хотя и надеюсь что с вашей помощью найду более правильное решение. И проблемы зависания ардуины, что наверное самое главное, т.к. замечал что по мере моего взаимодействия с ардуино, периодически скетчи зависали.
Вы меня разочаровываете ))), почитайте посты уважаемого SU-27-16 в этой теме, он прекрасно объяснил, почему проблемы переполнения не существует.
Проблемы зависания Ардуино в большинстве случаев связаны не с ошибками в скетче, а с аппаратной частью - некачественным питанием, плохим контактом, электромагнитными помехами извне и т.п.
К сожалению SU-27-16 особо вступать в дискуссию со мной не захотел, указав что не для меня пишет. Да и разочаровывать Вас я не хотел, и благодарен Вам за выстроенный диалог со мной. Но тем не менее из четких, коротких, хлестких сообщений SU-27-16 я понял, что:
copy из #19
в чём проблема-то ?
она будет если период слежения больше периода переполнения миллис()....
...тогда нужно учесть колво переполнений и вычислить реальное значение
нет ?
Нет. Имелся в виду случай, когда надо точно-точно знать, сколько миллисекунд прошло за большое-большое время. Вам это совсем не нужно, Вы не общее количество миллисекунд считаете, а маленькие отрезки по четыре и шестьдесят секунд.
Спасибо. Буду тестировать.
Whynot. , не передёргивай !!!!!
та тема-подтема была именно для Araris , и написал именно ему !!!! , т.к. тибе это было на том этапе не нужно....
Но тем не менее из четких, коротких, хлестких сообщений
...то ли лесть , то ли восхваления ? не надо нам таких !
...тогда нужно учесть колво переполнений и вычислить реальное значение
да , так и есть....
а что у вас за процессы по времени - раз в 2....3 месяца ?
тут проще перейти на часы реального времени с календарём...