Полив в моей теплице начинался честно: одно условие «включи насос в 7:30» в loop(). Потом появились вечерний полив, отдельный слот для рассады и законное желание сдвигать всё это хоть иногда — и скетч превратился в кашу из if-ов с магическими числами: чтобы сдвинуть утро на полчаса, я правил три места и забывал четвёртое. Расписание — это данные, а не код: массив слотов «час, минута, длительность», и правка интервала становится изменением одного числа в одной строке.
Здесь разберу именно эту машинерию: как держать слоты в массиве, почему проверка делается окном по минутам, а не равенством одной секунды, и зачем нужен флаг «уже полил в этом окне» — без него реле в пределах минуты щёлкает десятки раз. Границу «точный момент против окна» я подробно считал в уроке про срабатывание в 18:30, а годовое расписание с днями недели собрал в уроке про расписание на неделю — здесь суточные слоты и длительность в секундах.
Почвы и датчиков влажности здесь не будет: гейт «поливать, только если сухо» — отдельная история, она разобрана в уроке про автополив с датчиком почвы. Чистая хронометрия — полшага до той связки, и лучше, когда каждая ступень работает сама по себе.
Слоты в массиве и окно полива
Слот — три числа: час, минута, длительность в секундах. Три параллельных массива читаются проще двумерной таблицы: CHAS[3], MINUT[3], DLIT[3] — утро в 7:30 на девяносто секунд, вечер в 19:00 на две минуты, третий слот в запасе. Длительность я меряю секундами, а не «минутами полива»: капельной ленте важен объём, и перебор на полминуты за сезон выливается в литры, а литры — в топь у третьего ряда.
Окно — это минута слота: условие now.hour() == CHAS[i] && now.minute() == MINUT[i] истинно все шестьдесят секунд, пока идут секунды этой минуты. Отсюда два следствия. Первое: если в проходе цикла открыть реле и тут же закрыть, оно щёлкнет столько раз, сколько проходов уложится в минуту — при delay(1000) до шестидесяти. Второе: закрывать надо не по выходу из минуты, а по таймеру длительности на millis, иначе полив обрежется через секунду после старта.
Флаг polyto[i] гасит повторы: в первый проход внутри окна он разрешает открытие и тут же становится истинным, а сбрасывается только когда минута кончилась. Цикл обязан просыпаться чаще раза в минуту — мой потолок delay 250-500 мс; вешаете на loop тяжёлые задачи — держите неблокирующий стиль из урока про millis вместо delay: длинная пауза — это минута, которую можно проскочить целиком, и слот промолчит.
#include <Wire.h>#include <RTClib.h> RTC_DS3231 rtc;const int RELAY = 7; // модуль реле; насос питается ОТДЕЛЬНО, земля общаяconst int LED = 12; // дублирует состояние реле для стола const int CHAS[3] = {7, 19, 0}; // слоты: утро, вечер, запасconst int MINUT[3] = {30, 0, 0};const int DLIT[3] = {90, 120, 0}; // длительность в секундах bool polyto[3] = {false, false, false};bool idetPoliv = false;int aktSlot = -1;unsigned long startNasosa = 0; void setup() { Serial.begin(9600); pinMode(RELAY, OUTPUT); pinMode(LED, OUTPUT); digitalWrite(RELAY, LOW); // у части модулей логика инверсная - проверьте на LED модуля digitalWrite(LED, LOW); if (rtc.begin() == false) { Serial.println("DS3231 ne najden: SDA A4, SCL A5"); while (1) {} } Serial.println("Raspisanie: 07:30/90s, 19:00/120s");} void loop() { DateTime now = rtc.now(); for (int i = 0; i < 3; i++) { bool okno = (now.hour() == CHAS[i] && now.minute() == MINUT[i]); if (okno && !polyto[i]) { // вошли в окно - открыли один раз polyto[i] = true; idetPoliv = true; aktSlot = i; startNasosa = millis(); digitalWrite(RELAY, HIGH); digitalWrite(LED, HIGH); Serial.print("Poliv slot "); Serial.print(i); Serial.println(" start"); } if (!okno && polyto[i]) { // минута ушла - флаг чист к завтрашнему окну polyto[i] = false; } } if (idetPoliv && millis() - startNasosa >= (unsigned long)DLIT[aktSlot] * 1000UL) { idetPoliv = false; // закрытие по длительности, а не по выходу из минуты digitalWrite(RELAY, LOW); digitalWrite(LED, LOW); Serial.println("Poliv stop: dlitelnost vypolnena"); } delay(250);}Прогоните сценарий: T1 ставит слот на следующую минуту, S показывает текущее время, день недели и список тестовых слотов. Когда окно откроется, реле щёлкнет, LED дублирует состояние, и через пять секунд реле отпустит — на плате те же пять секунд превращаются в DLIT из массива, девяносто или сто двадцать секунд. Смотрите в мониторе на пары строк: старт одна строка, стоп одна строка; если увидите «старт, старт» — флаг потерялся, и именно это будет щёлкать реле в теплице.
Исполнителя выбирают до скетча. Реле с насосом — вариант для ёмкости: насос качает из бочки, и его ток определяет питание. Серво-краник — вариант для водопровода: серво поворачивает шаровой кран, насос не нужен вовсе, вода идёт под давлением; эта механика с расписанием уже собрана в уроке про кормушку на серво, только вместо корма — вода. Третий путь — соленоидный клапан: тихий и надёжный, но требует своих двенадцать вольт и не любит частые щелчки без протока.
Насос, реле и питание
Числа, на которые я опираюсь при сборке: типовой погружной насос на 5 В тянет 100-200 мА на ходу и заметно больше в момент старта; катушка реле-модуля съедает свои 70-90 мА постоянно. Сумма выходит за пределы порта USB, поэтому насос я питаю от отдельного блока, а не от пина 5 В платы: просадка при старте мотора перезагружает плату. Я собрал такую «перезагрузку в момент полива» и неделю искал её в скетче, пока не догадался смотреть на осциллограф питания.
Правила сборки короткие: земля насосного блока и платы соединяется в одну точку — реле без общего GND не поймёт управляющий сигнал; провод управления идёт с пина D7 на вход реле-модуля, и у части модулей логика инверсная — проверьте на светодиоде модуля до подключения насоса. И не берите ток насоса «с запасом от платы»: у пина 5 В при USB-питании лимит около половины ампера на всё сразу, катушка реле уже забрала свою долю.
Отдельно про старт. На ходу насос тянет свои 100-200 мА, но ротор в первый миг стоит, противо-ЭДС нулевая, и ток ограничивает только сопротивление обмотки: потребление подпрыгивает в два-три раза на долю секунды. Реле этот бросок переживает спокойно, а вот просадка на плате — нет: если насос сидел на её 5 В, плата уходит в перезагрузку именно в этот момент. Отсюда мой порядок включения: сначала питание на насосную половину, потом на плату — стартовый бросок случается до того, как скетч начал следить за окнами. Проверка после сборки честная: ручной запуск реле не должен ронять Serial-монитор и мигать диодом платы.
| Исполнитель | Чем хорош | Чем платит |
|---|---|---|
| Реле + насос 5 В (100-200 мА) | полив из ёмкости, дёшево и просто | отдельное питание и общий GND, стартовый ток |
| Серво + шаровой кран | вода из магистрали под давлением, без насоса | механика крана, серво греется под удержанием |
| Реле + соленоидный клапан | тихо и надёжно, идеально для капельницы | клапану нужны свои 12 В, катушка 300-500 мА |
Перезагрузка, EEPROM и переполнение int
Флаг polyto[] живёт в оперативке, а просадка питания в момент старта насоса — самая вероятная перезагрузка в жизни этого прибора, и случается она ровно внутри окна: плата взлетает заново, флаги обнулены, окно ещё открыто — и реле включает полив второй раз. Двухминутный полив превращается в четырёхминутный, а топь у третьего ряда — в норму. У меня это случилось дважды за один сезон, пока флаг не переехал в EEPROM: при открытии слота пишу единицу в свою ячейку, при закрытии ноль, в setup читаю обратно. Ресурс записи я считал в уроке про износ ячеек EEPROM: два слота в сутки — 730 записей в год, ячейка на сто тысяч циклов переживёт и вас, особенно если писать через update — он не трогает байт, если значение уже стоит.
Восстановление после сбоя требует одного решения: что делать, если плата проснулась внутри окна с EEPROM-флагом «полито». Я пропускаю слот — полив в три ночи после сбоя чаще вреден, и расписание догоняет себя за сутки. Обратный случай, когда плата проснулась до сдвига, флага ещё нет: скетч откроет окно заново и отыграет полную длительность, поэтому суммарный полив за ночь выходит двойным — EEPROM-флаг как раз и стоит между этими двумя историями. И в setup обязателен digitalWrite(RELAY, LOW) до всякой логики: после сброса пины всплывают, и реле-модуль с инверсной логикой может открыть насос на время загрузки — я видел, как это заливает подоконник.
Вторая ловушка — арифметика длительности. DLIT хранится в секундах, и умножение на 1000 обязано идти беззнаковым длинным: 120 секунд — это 120 000 миллисекунд, а int на Arduino Uno держит максимум 32 767; дальше число едет в минус, и реле закрывается сразу либо через случайный интервал. В скетче выше стоит (unsigned long)DLIT * 1000UL, и суффикс UL там не украшение, а страховка. Правило простое: всё, что умножается на 1000 и попадает в сравнение с millis, живёт в unsigned long — до 49,7 суток, потом счётчик переполнится, и у соседей по сайту есть отдельный урок про этот потолок.
И связка с переводом часов, потому что расписание живёт по локальному времени чипа. Весной при правиле 02:00-03:00 час перехода не существует: слот, назначенный на 02:30, раз в год молчит, и это честная плата за автоматику. Осенью час повторяется, но двойного полива не случится — EEPROM-флаг не обнуляется сам по себе, перезагрузки не было. Окна перехода, защита от двойного сдвига и час, который идёт дважды, — вся тема соседнего урока про перевод часов.
- 1. Зачем в каждом слоте флаг «уже полил»?
- 2. До скольких щелчков доходит реле без флага за минуту окна при цикле раз в секунду?
- 3. Как в моём скетче закрывается реле по окончании полива?
- 4. Почему насос не питают от пина 5 В платы?
- 5. Когда исполнитель «серво плюс кран» выгоднее насоса?
- Расписание — данные: массивы CHAS/MINUT/DLIT, слот правится одним числом без переписывания логики
- Окно — минута слота; условие истинно все 60 секунд, поэтому закрытие по таймеру длительности на millis
- Флаг polyto[i] ставится при открытии и сбрасывается при выходе из окна — иначе реле щёлкает до 60 раз
- Цикл просыпается чаще раза в минуту: delay до 500 мс, тяжёлые задачи — только в неблокирующем стиле
- Насос 5 В (100-200 мА) — от отдельного блока с общим GND; серво-краник берёт воду из магистрали без насоса
Частые вопросы по теме урока
- Зачем в каждом слоте флаг «уже полил»?
- Окно «час и минута совпали» истинно шестьдесят секунд подряд. Флаг разрешает открытие в первый проход и гасится только при выходе из окна. Условие окна истинно всю минуту — без флага открытие повторяется на каждом проходе цикла
- До скольких щелчков доходит реле без флага за минуту окна при цикле раз в секунду?
- Один щелчок на проход цикла, проходов в минуту до шестидесяти. В моём тепличном варианте это звучало как барабан, пока флаг не встал на место. До шестидесяти
- Как в моём скетче закрывается реле по окончании полива?
- Закрытие привязано к длительности слота в секундах, отсчёт ведёт millis от старта. Выход из минуты случится через 59 секунд — полив обрезался бы на середине. По таймеру длительности на millis: прошло DLIT секунд — выключить
- Почему насос не питают от пина 5 В платы?
- Катушка реле, датчики и дисплей уже съедают долю лимита; старт насоса просаживает питание и перезагружает плату. Отдельный блок с общим GND решает навсегда. У порта лимит около 500 мА на всё, а насосу нужно 100-200 мА и больше на старте
- Когда исполнитель «серво плюс кран» выгоднее насоса?
- Серво лишь поворачивает кран, а давление даёт водопровод — насос и его питание не нужны. Для бочки без давления кран бесполезен, качать надо насосом. Когда вода есть в магистрали под давлением