Полуавтоматическое управление насосом скважины с помощью STM32 в среде Ардуино
Многие обладатели приусадебных участков имеют на своих владениях водяные скважины, и, возможно, сталкивались с проблемой заиливания колодца/протухания воды за время простоя скважины с осени по весну.
Так уж случилось, что скважина на моем участке простаивала несколько лет, а когда пользовались, то отбирали очень мало воды.
Попытавшись почистить ее различными способами, было приобретено понимание, что не так уж все плохо и достаточно обеспечить стабильный отбор воды. Для этого было собрано несложное устройство, состоящее из блока питания с переходником микро-usb, (зарядное от телефона, на фото отсутствует), платы blue pill на базе камушка stm32f103c8t6, модуля реле, двухполюсного магнитного пускателя, обычного кнопочного выключателя закрытого типа, и собрано в распаечной коробке.
Плату микроконтроллера подготовил по мануалу HWman 'а. В комментариях была просьба уточнить, что STM32 можно прошить специальным загрузчиком, что в последующем позволяет программировать её через USB, как и обычные ардуинки.
Программирую с помощью плагина в Visual Studio Community. Установка плагина примитивная, не составит никакого умственного труда. Добавлю только, что плагин требует установленной ARDUINO IDE. Профессионалов, полагаю, смутит подобный подход, однако готовое изделие стабильно работает более полугода и выполняет поставленную задачу. И все же, я открыт для сотрудничество по идеям улучшения устройства.
Получаем крайне удобную среду с синтаксическим анализом кода, IntelliSense, и что субъективно немаловажно — темную тему оформления. Ибо глазоньки.
Прошиваем платку:
/*
Name: Nasos.ino
Created: 23.02.2017 19:08:20
Author: Ksiw
Архитектура программы заключается в установлении флага на включение реле различными способами, дабы в последстви проверить его(флага) статус и тогда переключить реле в соответственное положение.
Если кнопка ручного включения не зажата, то цикл выполняется примерно 10 раз в секунду.
Если кнопка зажата, то вначале дается десятая секунды во избежание дребезга, далее, проверка состояния кнопки происходит 20 раз/сек.
99% всего времени камень отдыхает пребывая в delay()
*/
unsigned long Work = 2UL*60; /*2 минуты работы*/ // укажи тут время работы в минутах, с приведением типов
//это не просто какая то дичь... Однако! Без приведения умножение вычислялось неверно.
const unsigned long Sleep = (unsigned long)20*60; //а тут простоя
unsigned long TimeLeft; //осталось секунд до переключения
int tempo = iter; //сразу вывести
int iter = 10; //пропускать итераций перед следующим выводом в порт
unsigned long timeNextSwich;
int button = PB4; //пин кнопки
unsigned long WorkTime, SleepTime ; // время в миллисекундах продолжительность включения насоса в минутах
bool handOn = false; //флаг ручного включения
bool flag; //флаг статуса реле
int RelayPin = PB7; //пин управления реле
unsigned long PreviousMillis = 0;
unsigned long CurrentMillis = millis();
unsigned long fullTimeIteration = 4200000000; //вычисление времени рестарта программы //(long 4,294,967,295)
//---------------------прототипы
void SwichFlag();
void SwichRelay();
void Button();
unsigned long SecToMillis(unsigned long);
void ResidueTime();
void ResetTimeToWork();
//-------------------------------------в начало программы---------------------------
void(*resetFunc) (void) = 0;
//********************************ПУСК*******************************************
void setup()
{
Serial.begin(115200);
flag = false; //включение реле при загрузке микроконтроллера
//-----------Инициализация вывода реле
pinMode(RelayPin, OUTPUT);
pinMode(button, INPUT);
digitalWrite(RelayPin, flag);
Serial.println("");
WorkTime = SecToMillis(Work);
SleepTime = SecToMillis(Sleep);
PreviousMillis = millis();
}
void loop() //****************************ЦИКЛ**********************************************
{
while(true)
{
CurrentMillis = millis(); //текущее время
ResetTimeToWork(); //проверка переполнения milis()
SwichFlag(); //проверка необходимости переключения
SwichRelay(); //переключили реле, если флаг изменился
ResidueTime(); //вывод в порт
Button(); //обработка кнопки
tempo++;
handOn = false;
delay(100);
}
}
//-------------------------------------переключение флага----------------------------------------------
void SwichFlag()
{
if(flag && CurrentMillis-PreviousMillis>=SleepTime)
{
PreviousMillis = CurrentMillis;
flag = false; //если разница предыдущего замера и текущего времени больше времени сна, но уставим флаг на включение
Serial.println("Flag On");
}
else if(!flag && CurrentMillis-PreviousMillis>=WorkTime) //Иначе, если реле включено и пришло время выключаться, переключим флаг в "выключено"
{
PreviousMillis = CurrentMillis;
flag = true;
Serial.println("Flag OFF");
}
}
//-------------------------------------работа кнопки-------------------------------------------------------
void Button()
{
if(digitalRead(button)==HIGH) //если кнопка нажата
{
do
{
if(handOn)
{
delay(50);
continue;
}
Serial.println("TURNED ON");
digitalWrite(RelayPin, LOW); //то включаем реле
flag = true;
handOn = true;
delay(100); //и немного удерживаем
}while (digitalRead(button)==HIGH);
CurrentMillis = millis(); //узнаем и записываем когда это окончилось
PreviousMillis = CurrentMillis; //обновляем время последних действий
delay(20);
}
}
//-------------------------------------преобразование секунд в миллисекунды---------------------------
unsigned long SecToMillis(unsigned long Temp)
{
return Temp*1000;
}
//-------------------------------------время до переключения----------------------------------------------
void ResidueTime()
{
if(CurrentMillis<PreviousMillis && tempo > iter)
{
if(flag)
{
TimeLeft = timeNextSwich/1000+1;
Serial.print(" Time to ON: ");
Serial.print(TimeLeft);
Serial.print("sec");
Serial.println("");
}
else
{
TimeLeft = timeNextSwich/1000+1;
Serial.print(" Time to OFF: ");
Serial.print(TimeLeft);
Serial.print("sec");
Serial.println("");
}
tempo = 0;
}
if(tempo > iter) //вывод каждую нную итерацию
{
if(flag)
{
TimeLeft = (PreviousMillis+SleepTime-CurrentMillis)/1000+1;
Serial.print(" Time to ON: ");
Serial.print(TimeLeft);
Serial.print("sec");
Serial.println("");
}
else
{
TimeLeft = (PreviousMillis+WorkTime-CurrentMillis)/1000+1;
Serial.print(" Time to OFF: ");
Serial.print(TimeLeft);
Serial.print("sec");
Serial.println("");
}
tempo = 0;
}
}
//-------------------------------------переходная функция вовремя переполнения milis();
void ResetTimeToWork()
{
while(CurrentMillis<PreviousMillis) //если текущее время меньше последней записи
{
if(flag) //и реле выключено
{
timeNextSwich = SleepTime-(4294967295-PreviousMillis); //то находим время следующего переключения
while(timeNextSwich>=CurrentMillis) //пока время следующего переключения больше текущего
{
CurrentMillis = millis();
ResidueTime();
Button(); // если кнопка нажата, перезаписывается время последнего действа и выходим из функции ResetTimeToWork()!
if(CurrentMillis>PreviousMillis)
return;
tempo++; //для корректной работы ResidueTime();
}
flag = false;
PreviousMillis = CurrentMillis; //обновляем время изменения
CurrentMillis = millis();
return;
}
if(!flag)
{
timeNextSwich = WorkTime-(4294967295-PreviousMillis);
while(timeNextSwich>=CurrentMillis) //пока время следующего переключения больше текущего
{
CurrentMillis = millis();
ResidueTime();
Button();
if(CurrentMillis>PreviousMillis)
return;
tempo++;
}
flag = true;
PreviousMillis = CurrentMillis;
CurrentMillis = millis();
return;
}
}
}
//--------------------------------------переключалка реле--------------------------------------------------
void SwichRelay()
{
if(!flag)
{
digitalWrite(RelayPin, flag); // включаем реле
}
else
{
digitalWrite(RelayPin, flag); // выключаем реле
}
}
Касаемо кода. Программа писалась в несколько подходов, модифицируясь по ходу выявления недочетов. Выглядит довольно запутанно, но постараюсь разъяснить.
Работает следующим образом:
0) Архитектура программы разработана так, чтобы опросить любое внешнее устройство(кнопку, датчик давления, таймер т.п.) и установить флаг на включение, либо выключение реле, а после, отдельной функцией проверить состояние флага и переключить в соответствующее положение.
1) Код программы упирается на таймер функции millis(), функция ResidueTime() вычисляет время следующего переключения реле, SwichRelay() проверяет статус флага и дает команду переключения, если необходимо.
2) Реле включается при подаче низкого уровня сигнала с ноги PB7. При включении устройства, после инициализации МК, реле переходит в положение ВКЛ, подавая напряжение на катушку пускателя, а тот в свою очередь подает напряжение на насос.
3) Время работы устройства — 2 минуты, после чего оно переходит в режим ожидания на 20 мин.
4) Включение выключателя обрабатывается незамедлительно, а после выключения программа выдерживает интервал простоя в 20 минут. Это сделано для того, чтобы скважина восполнила откачанную воду, и исключить случай работы насоса насухую.
5) Так же в коде присутствует функция ResetTimeToWork(), которая срабатывает при переполнении функции millis(), которая
Возвращает количество миллисекунд с момента начала выполнения текущей программы на плате Arduino. Это количество сбрасывается на ноль, в следствие переполнения значения, приблизительно через 50 дней.
(с сайта Arduino.ru)
Следовательно, дабы устройство не «упало» после этого срока непрерывной работы, разработана упомянутая функция, обеспечивающая стабильную работу устройства без дополнительного перезапуска.
Приступаем к сбору схемы.
Схема сборки:
Сигнал с ноги PB4 необходимо прижать к земле резистором 4,7КОм, в противном случае, реле работает неверно.
В коробке устанавливаем динрею для пускателя:
И монтируем остальные запчасти, закрепляя их положение с помощью горячих соплей, как на первом фото.
В крышке необходимо прорезать отверстие для пускателя, он выше, чем глубина коробки.
Не забываем установить блок питания для платы, можно спрятать его внутрь коробки, в ней еще достаточно места, либо вынести во вне и воткнуть его в близжайшую розетку.
Готовое устройство, осталось только посадить на клеммы пускателя кабель 230V и подключить нагрузку.
Выключатель использовал старый, он же стоял на включении насоса. Снаружи имеет неустранимые загрязнения цементом и прочие потертости, однако имеет герметичный корпус, внутри совершенно цел и в саду будет еще долго исправно работать. Учитывая мизерный коммутируемый ток — практически вечно, пока не сломается механически.
Спасибо HWman 'у за представленную статью по обеспечению работы stm32 во фреймворке ARDUINO.
Архив со скетчем прилагаю.
Комментарии (48)
Dmitry_7
19.10.2017 14:29Чем это отличается от реле времени?
Ну и неплохо бы контролировать сухой насос, обрыв цепи, температуру за бортом. Куда зимой воду сливать-то?Ksiw Автор
19.10.2017 20:34Отличие в том, что хоть после ручного включения, хоть после автоматического, выдерживает время простоя, дабы скважина восстановила уровень воды. Обычное реле времени этого учитывать не будет.
По поводу обрыва цепи нагрузки.
Ваша идея хороша, думаю, ее можно решить с помощью амперметра. Неплохой получится контроль!arheops
19.10.2017 23:43Думаю, этот вопрос непринципиальный. Кроме варианта когда у вас фактически нет скважины. Достаточно просто отбирать 5% от дебета, это в скважине будет почти всегда.
sneka
19.10.2017 14:33Я купил реле времени за 300р. на динрейку. (китайский омрон). Поставил 5 минут раз в час.
Ksiw Автор
19.10.2017 20:40Я тоже сначала купил электромеханическое реле. В течении дня оно работало нормально, а ночью, когда уехал, заклинило в положении «ВКЛ». Насос стоял вибрационный, выкачал воду, и работал насухую. Гайка с оси открутилась и насос перемолол свои внутренности, сломал ось.
Самое интересное — обмотка электромагнита так и не перегорела, хотя и порядком поджарился.sneka
19.10.2017 21:09все так. Электромеханическое брать нельзя. Тоже заклинило 100-рублевое включенным. Это электронное с 2014 пашет на киловаттном насосе. Не знаю как тут относятся к ссылкам так что если нужно — в личку кину.
Ksiw Автор
19.10.2017 22:29Благодарю, уже скрафтил. Так даже интереснее.
На используемый пускатель нагрузку можно повесить куда больше киловатта. Не залипнет, надежно.
unwrecker
19.10.2017 15:28Соглашусь с предыдущими ораторами, что цель не оправдывает средства.
Раз уж привлекать микроконтроллер, то можно реализовать плавный пуск, защиту от сухого хода и (чего мне на даче больше всего не хватает) поддержание стабильного давления
Плавный пуск я делал на микросхеме фазового регулятора и варисторе, но он только ухудшил ситуацию со стабильностью давления из-за более глубокого провала при старте. Нужно чтоб он управлялся аналоговым датчиком давления а не реле. В общем, если кто видел готовое решение — милости прошу.Jmann
19.10.2017 15:48Для поддержания стабильного давления без девиации в системе, поможет только частотное регулирование. Если просто по заданному давлению и прочим дельтам дергать насос, все равно не получите линейного поддержания давления.
sneka
19.10.2017 15:53Готовое решение лежит в другой плоскости. Накопительный бак + релейный датчик давления с защитой от сухого хода.
А так кроме как латром или частотой насос по регулировать не удастся.unwrecker
19.10.2017 16:59Как раз такая схема и была реализована изначально. Проблема в том, что накопительный бак не поддерживает постоянное давление — оно падает по мере его исчерпания. Давление холодной воды постепенно ослабевает, при этом напор горячей воды ослабевает меньше за счёт подпора давлением воздуха в верхней части водонагревателя. Потом срабатывает реле и резко включается насос, напор холодной воды скачкообразно возрастает, а горячей наоборот плавно из-за воздуха в водонагревателе опять же. В итоге имеем халявный контрастный душ :)
Решением может являться более слабый насос или более ёмкий гидроаккумулятор. Или то решение, которым я в итоге воспользовался — водяной редуктор на входе в санузел. Но, КМК, правильней будет плавно регулировать скорость насоса чем постоянно включать и выключать его.
Кстати, фазой насос вполне нормально регулируется (не считая постороннего звука). Или ему это вредно?sneka
19.10.2017 17:57ну во первых редуктор + избыточное давление в магистрали — вообще идеальное решение.
А так надо искать баланс давления воздуха в расширительном бачке и настройки реле насоса. Я бы начал с того что заставил его включаться раньше, то есть при бОльшем давлении.
А «по фазе» не специалист, но говорят вредно.
arheops
19.10.2017 23:46У вас видимо неправильно настроенно давление в баке. В пустом баке должно быть давление незначительно больше уровня нижнего(стартового) в магистрали. Тогда пуск будет происходить ровно при заканчивающемся баке, не будет провала.
Ну и потом ставится редуктор выставленный на нижнее(стартовое) давление.
hssergey
19.10.2017 16:08В насосных станциях постоянство давления поддерживается расширительным бачком и датчиком, отключающим насос при достижении заданного давления. Если насос погружной, то в принципе никто не мешает поставить эти компоненты отдельно…
Jmann
19.10.2017 15:42STM32??? Да тут Attiny например 44 с головой хватит, с несколькими каналами для измерения уровня кондуктометрическим способом, опорник, для регулировки чуйки и тд. Как тут уже правильно говорят, можно поставить датчик давления релейный или аналоговый(тут можно посчитать косинус Фи), так же в скважину можно опускать датчики и питать их переменкой или хотя бы меандром, что бы не обростали. Это надежный способ защитить насос от работы на сухую. Можно также повесить датчик тока, и контролировать параллельно номинальный ток электродвигателя насоса.
Ksiw Автор
19.10.2017 20:46Вы совершенно правы, это действительно оверинжиниринг.
Однако, когда есть потребность, делается из того, что есть сейчас, а не из того, что можно купить и ждать, когда приедут запчасти.
Датчик давления не требовался. Требовалась только переодическое включение и выдержка после выключения ручным способом.Jmann
19.10.2017 21:12В вашем случае можно будет в принципе в дальнейшем расширять, и проект не будет легаси. Все описанное + контроль и управление удаленное.
Ksiw Автор
19.10.2017 21:30Да, благодаря комментариям, уже решено добавить амперметр, датчик температуры, и экранчик для вывода информации пользователю.
По поводу удаленного управления — сомнительно. Тогда устройство в общем обзоре станет значительно сложнее и дороже, а явной потребности в этом нет.Jmann
19.10.2017 21:39В таком случае тут и экранчик не нужен… Даже в некоторых моделях насосных станций Willo индикация светодиодная или на семисегментых индикаторах. Экран в вашем случае будет необходим, если вам придется настраивать например ток двигателя, температуру, какие-то функции, и пр… Конечно же все стоит от поставленной задачи. Ставить сюда к примеру LCD 16x2 так же затратно.
Ksiw Автор
19.10.2017 22:38Ну, разве что контролер по совместительству будет показывать температуру окружающего воздуха, и обратный отсчет времени до следующего переключения.
И ток двигателя выводить. И статус, типа: «ОК» — рабочий режим. Или «Уснул до весны» — если слишком холодно, и имеется опасность промерзания.
Вообщем, появились новые идеи для реализации.
hssergey
19.10.2017 16:07Я так понимаю, смысл всего этого — чтобы уехать с дачи на зиму, но при этом насос периодически включался. Поэтому больше интересуют фотки «с полей». Куда уходит вода? Как реализована защита от промерзания?
Ksiw Автор
19.10.2017 21:02Да.
Ничего интересного, воду из шланга напрямую от насоса сливаю в канавку в огороде.
Живу в Краснодарском крае, зима как бы есть, и её как бы и нет. И все-таки, последую Вашей идее, и добавлю DS18B20.
Спасибо за коммент!Alexeyslav
20.10.2017 21:26Я бы посоветовал датчик LM335 он аналоговый, при отсутствии повышенных требований к точности и дискретности измерения температуры с ним работать гораздо легче. Вклинить общение с датчиком 18B20 в ваш алгоритм будет несколько неочевидно и запутанно — либо ждать конца измерения температуры прямо в основном цикле, или разносить команды начала измерения и считывания результата во времени. То ли дело LM335 — одна команда на старт АЦП, подождать несколько десятков микросекунд, умножить результат на число вычесть магическую константу 273 и получить температуру в градусах цельсия. Всё это можно сделать в главном цикле, не задерживая его и не размазывая код работы с датчиком по нескольким местам.
И ещё сразу добавлю что в случае хоть цифрового хоть аналогового датчика к пороговым уровням надо будет добавить гистерезис чтобы исключить неустойчивые состояния.
alexhott
19.10.2017 19:20делал чуть по интереснее с датчиками в скважине и накопительной ёмкости, чтобы часто не включалось и держало ёмкость полной
Jmann
19.10.2017 21:17Ну это классический подход. Делается на парочке реле уровня воды. Я например делал такое на обычных 74HCT123. Единственный минус, очень чувствительны цифровые схемы к помехам (особенно если рядом работает частотный привод мощностью более 5 кВт). Лучше делать вход на биполярных транзисторах, или все устройство на компараторе.
Samoglas
19.10.2017 22:12Контактор IEK — возможная точка отказа.
Уж очень репутация у российских производителей специфическая. Российский выключатель Шнейдер отработал 3 месяца, его предшественник no brand работал годами.
Даже автоматы ABB бывают поломанным уже на складе дистрибьютора, что уж говорить про IEK и прочих.
Помню, на каком-то семинаре представитель IEK c гордостью рассказывал о новом логистическом центре и первый вопрос из зала ему был: «А неужели вы своё в строительстве использовали?»Ksiw Автор
19.10.2017 22:53Тьфу-тьфу, работает. Нагрузка для него невелика, с хорошим запасом.
Будь коммутируемый ток больше, поставил бы ПМЕ-211, но тут уже будет перебор, и в распредкоробку не впихнешь.
Полагаю, самое слабое место — китайская релюшка. Да и она практически вхолостую работает.Jmann
20.10.2017 08:29По поводу контакторов IEK, делали огромное количество щитков для скважинных насосов до 2,2 кВт на IEK или Chint, процент выхода из строя не большой. Но качество хромает, особенно у автоматов, узо и клемм.
Jmann
20.10.2017 09:07ТС я вам скину видео прототипа своего контроллера, он позволяет управлять 4-мя насосами с ПЧ INVT GD10. Также возможно подключать до 8 DS18B20. Датчик 4-20мА, там же реле уровня со встроенным генератором для питания кондуктометрических датчиков, защита по сухому ходу. Я как раз применил дисплей 16x2 и древовидное меню. Может что-то полезное найдете.
Garbus
По моему к устройству был бы полезен датчик давления воды, чтобы схема среагировала на «неправильную» ситуацию, и отключила насос до выхода из строя.
Ksiw Автор
В следующей ревизии обязательно добавлю, когда скважина появится необходимость обеспечивать дом водой.
Т.к. насос используется для отбора воды в строительных нуждах без всякой накопительной емкости(небольшой расход воды), датчик давления собственно и ставить некуда, и без нужды.
blot88
в этом случае нужен датчик протока, а не датчик давления т.к. насос охлаждается водой и не должен работать вхолостую. Датчик давления здесь будет бесполезен.
Garbus
Ну можно поставить клапан и «буферную» емкость. Тогда по достижению максимального давления насос просто отключается. Зато открывая кран сразу получаем нормальный напор, а не бегаем каждый раз включать насос как только нужна вода.
P.S. Датчик расхода тоже неплох, но терзают сомнения, сколько будет стоить что-то приличное?
blot88
датчик давления будет бесполезен только в данном случае т.к. автор обзора решает вопрос автоматической прокачки скражины и вода просто в канаву сливается.
Если же хотите накапливать воду в открытую (не герметичную ) ёмкость, то лучше использовать поплавковый клапан для включения/отключения насоса в скважине по уровню воды в ёмкости.
Примерно так:
ссылка 1
ссылка 2
Jmann
Нужно в логику добавлять регулируемую задержку включения/отключения. Я обычно делаю в своих девайсах по две минуты в обе стороны.
blot88
Вы предлагаете вместо той программы, которую автор обзора предлагает или в дополнение ?
Jmann
У него же микроконтроллер, может дополнять функционал своей программы как хочет и сколь угодно.