Проект двухступенчатого водоснабжения загородного дома

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Всем привет.

Делаю водоснабжение для своего дома в деревне. Добрался до автоматики, ну и остановился на ардуинке. Никогда с ней раньше не имел дела. Заказал на алиэкспрессе, помигал дидиком :)

Вот добрался до описания проекта, и надеюсь на ваши коментарии.

Проще всего объяснить на видео.

https://vimeo.com/143684102

Вода забирается из скважины погружным насосом (дебет скважины неограничен) и подается в накопительную кубовую емкость. Из накопителя насосная станция раздает воду по дому. В емкости 3 горизонтальных датчика уровня. Нижний - включение аварийной сигнализации (ай-яй че-то не работает, вода из скважины не качается). В принципе, в насосной станции есть датчик сухого хода, по-этому никакой автоматики на срабатывания нижнего датчика, кроме оповещения делать не планирую.

Скваженый насос накачивает воду, замыкается верхний датчик. Насос отключатся. На всякий случай наверху поставлю два вертикальных датчика (два - чтоб наверняка :) ) в случае перелива, ну и перелив физический тоже сделаю.

Открыли кран, насосная станция начала забирать воду из емкости. Когда уровень ушел ниже среднего датчика в емкости, включается скваженый насос.

Теперь самое сложное. Специфика скважины - если часа 3 из скважины не выкачивали воду, то первые минут 15 пойдет мергель. Так что нужно эту воду слить. Перед емкостью стоит трехходовой клапан. Если по таймеру с последнего включения скваженного насоса прошло более 3-х часов, то вода минут 15 будет сливаться на улицу в накопительный пруд в конце участка. Уровень среднего датчика в емкости надо будет так подобрать, чтобы при максимальном расходе  потребителем воды хватило как раз на эти 15 минут слива.

В случае засора (замерзл, засорилось, улитки наползли, танки подъехали) трубы уличного слива поставлю на трубу реле давления, шоб не прорвало где трубу (хотя скорее насос просто сгорит, он простенький в скважине). Но реле, мне кажтся, смысла нет включать в систему - просто провод к насосу пропустить через реле.

Заказал на алиэкспрессе вертикальные, а на eBay горизонтальный датчики, уже в наличии ардуинка леонардо.

Нужно будет задействовать реле для включения скваженного насоса ~220в и трехходового клапана ~12 в, обработать замыкание 5 датчиков...

Достаточно будет платы леонардо или лучше какую-нить платку расширения докупить? Паяльником работать умею, но вот что-то плату рассчитать самостоятельно не смогу. Хотя по готовой схеме и спаяю.

Буду признателен за вопросы и коментарии.

 

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

еще забыл, конечно дисплейчик прикручу, куда без него :), возможность принудительного перехода в режим слива на улицу, регулировки таймеров включения... вроде пока все

с программированием дружил в ввиде долго и увлеченного терзания Delphi под свои мелкие домашние нужды.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Так, с реле вроде вот варианты

http://www.electronshik.ru/item/2-channel-relay-shield-module-for-arduino-1135593

http://www.electronshik.ru/item/4-channel-5v-relay-module-for-arduino-1135591

Понадобятся, наверняка, часы

http://amperka.ru/product/troyka-rtc

Дисплей

http://www.electronshik.ru/item/lcd128x64-shield-for-arduino-1021358 (дороже, но есть джойстик уже)

или http://amperka.ru/product/graphic-lcd-128x64 но тогда нужна еще и клава http://amperka.ru/product/joystick-module

ну и может вот это?

http://amperka.ru/product/arduino-troyka-shield

axill
Offline
Зарегистрирован: 05.09.2011

Все правильно планируете

оствлось не понятно чем будете трехходовой вентиль переключать

купите ещё несколько макетных плат по пайку. Как минимум надо будет собрать защиту входов ардуину, тех входов, которые будут к датчикам подключаться, провода там довольно длинные будут, нужна как минимум защита от ESD. В самом идеальном варианте поставить tvs диоды на 5.1в. 

Реле для включения насоса надо подбирать с большим запасом тока, лучше сделать в две ступени - реле на ардуиновском шилде, этим реле включать электромагнитный пускатель (контактор) который рассчитан на нагрузку AC3 - это высоко ндуктивная нагрузка типа моторов. Важно понимать что реле на ардуино шилде маркированные как 10 ампер, на самом деле 10а они могут коммутировать только неиндуктивная нагрузка типа нагревателей. А индуктивную нагрузку надо считать поделив на 5, а то и 10. 

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Привет, axill

Спасибо за ответ. Трехходовой вентиль покупал у китайцев - он идет со встроенным электро-приводом, плюс к тому есть два концевика - замыкаются при достижении крайних положений, что можно будет использовать для чего-нить :)
У электропривода 1А и 12 вольт переменного тока. В принципе для этого релешки на ардуиновской шилде должно хватить?

Про релешки и защиту понял, в деталях буду продумывать продумать чуть позже, сейчас хочу определиться с основным железом вокруг ардуинки, написать алгорит логики работы. Немного непривычно, так как ООП сильно послабляет (кинул кнопку, написал обработчик событий :) ), и линейное программирование мне непривычно.

Макетка какая-то валяется, думаю ее хватит. Да и текстолит у меня есть и платки я травил, напечатав на принетере, было дело.
Длина проводов где-то метров по 5, навреное будет от емкости с датчиками до блока управления.

Вечером попробую описать алгоритм блоками, выложу на рассмотрение.

axill
Offline
Зарегистрирован: 05.09.2011

На электропривод реле хватит, но с такими параметрами проще мосфетом управлять, дольше прослужит

а контактор я рекомендовал для пуска насоса в скважине

nevkon
Offline
Зарегистрирован: 20.01.2015

5 метров до датчиков довольно далеко, защиту от наводок ставить уже крайне желательно. Самый простой способ - поставить оптопару на каждый датчик. Советую нарисовать хотя бы простенькую электрическую схему. У меня с подобной задачей справилась нана. Правда код проверить не успел - запустил уже осенью. Теперь пока следующий поливной сезон не начнется не проверю. Но у меня дачный домик.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

axill пишет:

На электропривод реле хватит, но с такими параметрами проще мосфетом управлять, дольше прослужит а контактор я рекомендовал для пуска насоса в скважине
про скваженный я так вас и понял. про мосфет тоже учту

nevkon пишет:

5 метров до датчиков довольно далеко, защиту от наводок ставить уже крайне желательно. Самый простой способ - поставить оптопару на каждый датчик. Советую нарисовать хотя бы простенькую электрическую схему. У меня с подобной задачей справилась нана.


не понял про оптопару? типа поплавковый выключатель включает/выключает "лампочку"?

леонардо у меня просто уже куплен :)

nevkon
Offline
Зарегистрирован: 20.01.2015

Да, все верно. Поплавковый выключатель (в вашем случае скорее всего геркон управляемый магнитом) включается в цепь любого разумного напряжения (например у меня 12В) и включает светодиод оптопары (например PC817), не забудьте только токоограничивающий резистор. Светодиод оптопары в свою очередь открывает транзистор и сигнал идет на контроллер.

axill
Offline
Зарегистрирован: 05.09.2011

Angbor пишет:

не понял про оптопару? типа поплавковый выключатель включает/выключает "лампочку"?

при сильных наводках и помехах один из способов борьбы с ними это использование оптопары. Ваш концевой датчик в бочке замыкает не вход ардуины, а вход оптопары, а уже с выхода оптопары сигнал подается на ардуину. В условиях сильных помех и промышленных производств этот способ часто применяется

но в вашем случае я не думаю, что он необходим. Достаточно поставить RC цепочку на входе для "уничтожения" импульсных наводок (против ложных срабатываний) и поставить или два диода (анод на GND и катод на вход ардуино + анод на вход ардуино и катод на +5В) или TVS (между входом и GND) для защиты от ESD

схему и правда стоит нарисовать, частично блочную (ардуино) частично детальную, например используя программу fritzing

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

понял, спасибо

про оптопару мне тоже показалось как-то слишком глобально...

вечером засяду за схемы

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Всем привет :)

Вы будете ржать, но за два часа я только понял, как кнопки подключить, чтобы ногу не спалить.
Теперь вот вроде с реле через мосфет разобрался (в общих чертах)

группа из трех кнопок - поплавковые выключатели уровня.
группа из двух кнопок - верхний выключатель перелива продублированный двумя поплавками на всякий случай :)
сейчас просто набросал первичный прикид без наворотов от наводок

не все в Fritzing мне понятно, в особенности, как на макетку источники питания ставить произвольные и землю, ну и каша на принципиальной схеме и печатной плате меня вообще у шок повергает :)

ну да ладно, утро вечера мудренее, завтра надо продолжать копать траншею, у реальности такая особенность - на картинках пруд, оно конечно красиво, а на ландшафте усе лопатой да лопатой

nevkon
Offline
Зарегистрирован: 20.01.2015

Так, на всякий случай - кнопки аварийного перелива надо не последовательно ставить, а в параллель, вы ведь повышаете, а не понижаете надежность.

По фритзингу. Делайте поиск (значек лупы) элемента "battery". Там их целая куча находится.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

про батарейки спасибо, я вроде поиск нашел, но не додумался так батарейки поискать :)
но это не совсем то, чего хотелось - мне нужно поставить допустим на макетку блок питания +12v, никак не соображу, как это может называться по-англицки

а про кнопки, разве у меня они не так подключены?

nevkon
Offline
Зарегистрирован: 20.01.2015

Вот на этой схеме правильно, а по верхней так одна кнопка для красоты воткнута.

 

axill
Offline
Зарегистрирован: 05.09.2011

Кнопку лучше на землю замыкать, а резистор наоборот на +5в. Будет более устойчиво от помех. Это связанном с ассиметричностью логических уровней относительно шин питания

блру питания по англитски power supply, хотя я не проверял есть он там или нет. Насколько помню в fritzing кроме схематичных в виде рисунка схем есть и классические схемы с символами, там источник питания можно обозначить разъёмом и надписями

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

nevkon пишет:
Вот на этой схеме правильно, а по верхней так одна кнопка для красоты воткнута.

не пойму, почему вы так считаете?
вот я сделал микс на картинке, чтобы нагляднее объяснить

на основной картинке я кликнул на левый контакт, подсветилась вся группа, которая в соединении. т.е., через резистор на +5 (как посоветовал axill). Теперь кликаем на правые контакты (сделал вставку в черном прямоугольнике)- высвечивается линия GND. Обе кнопки стоят правыми контактами на +5, левыми на земле. В блоке "инстпектор" видно, что при нормальном расположении элемента на макетке два левых контакта соеденины, и два правых. Т.е. перемыкание контактов происходит между "право" и "лево", так?
Или я тогда вообще не понимаю, как на этой макетке чего выткается :)

axill пишет:

Кнопку лучше на землю замыкать, а резистор наоборот на +5в. Будет более устойчиво от помех. Это связанном с ассиметричностью логических уровней относительно шин питания
т.е. я ногу тогда подтягиваю к плюсу, так вроде называется? (а не прижимаю к земле)

axill пишет:
блру питания по англитски power supply, хотя я не проверял есть он там или нет. Насколько помню в fritzing кроме схематичных в виде рисунка схем есть и классические схемы с символами, там источник питания можно обозначить разъёмом и надписями
такие я видел, ноих невозможно ни на макетку, ни на печатную плату положить - только на принципиальную схему :(
Но ничего, я разберусь :)

axill, а включение мосфета и реле я правильно сделал?

axill
Offline
Зарегистрирован: 05.09.2011

У вас просто реле или релейный шилд?

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

На схеме в fritzing я пытался разобраться, как увязывать мосфет и реле. А вообще думал шилд использовать.
Например такой http://amperka.ru/product/troyka-relay
Через него я думал включать скваженый насос. У него мощность 1кВт и максимальный ток 4,6А
Стоит ли добавить мосфет перед этим шилдом или в принципе имеющейся на шилде обвязки хватит?

А вот через это http://amperka.ru/product/troyka-mosfet думал уже включать электро-привод трехходового клапана. У него 1А и 12 постоянного тока. При подаче напряжения вентиль открывается, заряжаются кондеры. Когда напряжение снимается, за счет кондеров вентиль закрывается обратно.

Кстати, если есть другие шилды для таких задач, буду признателен ссылке
У меня в физической наличности пока только леонардо (ну и насосы с вентилем :)

Остальное буду заказывать, как определюсь со схемой.

bwn
Offline
Зарегистрирован: 25.08.2014

Максимальный ток = ток.рабочий/cos фи так что максимальный у вас скорее 7,7А. А включать через шилдовые реле киловаттные реактивные нагрузки, искать себе неприятностей. Быстрее уж управлять контактором, а с него насосом.

axill
Offline
Зарегистрирован: 05.09.2011

Релейный модуль по вашей ссылке имеет транзистор, поэтому его можно напрямую к ардуино цеплять. Правда стоит что то дорого, посмотрите для альтернативы chipster.ru

Выше уже писал, скважинный насос лучше через цепочку реле-шилд -> контактор запускать. 

Мосфет я вам рекомендовал вместо реле для трехходового вентиля, но и реле нормально

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

axill пишет:
Релейный модуль по вашей ссылке имеет транзистор, поэтому его можно напрямую к ардуино цеплять. Правда стоит что то дорого, посмотрите для альтернативы chipster.ru
спасибо за ссылку.

axill пишет:
Выше уже писал, скважинный насос лучше через цепочку реле-шилд -> контактор запускать.
т.е. простенький реле шилд типа http://chipster.ru/catalog/arduino-and-modules/relay-modules/3650.html на него уже 220 вольтный  контактор типа такого цеплять и с него уже насос. так?

axill пишет:
Мосфет я вам рекомендовал вместо реле для трехходового вентиля, но и реле нормально
ваш аргумент был, что у мосфета будет срок службы повыше... в принципе, почему бы и нет, не так уж и сложно его на платку будет приделать :)

кажется немного проясняется, пойду писать блок-схему логики управления

 

nevkon
Offline
Зарегистрирован: 20.01.2015

Даа, за плату размером 2*2см просят аж целых 250р :) остальное как раз 40р оставшиеся в рознице стоит.

А по сути вопроса - контактор можно и такой использовать, а шилд релейный возьмите лучше на 2 реле - меньше проводов будет. Или на 2 симистора.

И я бы не советовал все-таки пренебрегать опторазвязкой. Вы ведь не машинку на радиоуправлении делаете. Тем более PC817 + резистор на 1к будет стоить не намного дороже того что предлагают наворотить из диода + резистора + конденсатора.

зы. сравните 2 позиции - одна с опторазвязкой, другая чисто релейная, разница в цене 8р:

http://chipster.ru/catalog/arduino-and-modules/relay-modules/2289.html

http://chipster.ru/catalog/arduino-and-modules/relay-modules/3800.html

 

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

да я, честно говоря, начитавшись описания траблов при подключении силовой нагрузки, тоже склоняюсь к опторазвязке. У меня все равно будет блок питания для трехходового вентиля вкелючен постоянно. Он на 12,5в и 1А, за глаза.

И я так понимаю, землю ардуинки ни в коем случае не соединять с землей остальных плат? (я не имею ввиду шилды)

nevkon
Offline
Зарегистрирован: 20.01.2015

Почему нельзя? Из-за того что опторазвязка будет нарушена? Может я и не прав, но у меня все питает один БП, соответственно земля общая.

axill
Offline
Зарегистрирован: 05.09.2011

По контакторам смотрите какой ток они обеспечивают для нагрузки типа AC3 - это индуктивная нагрузка типа моторов. На сайте ИЭК для каждой серии контакторов есть таблички. Вот эти компактные как у вас на фото AC3 тянут с большим дисконтом, насколько помню. Могу ошибаться, смотрел несколько месяцев назад

мосфет больше прослужит, но не хочется вам советовать пайку на начальной стадии освоения ардуины. Выше вы его не правильно подключили, но это сейчас и не важно, начните с релейного шилда

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

ОК, axill, начну с шилда. Возьму шилд на две релюшки. Одно на контактор 220в, другое на вентиль 12в
про контактор тоже понял, посмотрю детали

nevkon пишет:
Почему нельзя? Из-за того что опторазвязка будет нарушена? Может я и не прав, но у меня все питает один БП, соответственно земля общая.
ну мне кажется, что через землю вполне можно помехами ардуинку уложить... нет?

nevkon
Offline
Зарегистрирован: 20.01.2015

RC фильтр на питании должен быть, а лучше еще диодами двумя защитить до стабилизатора.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

nevkon пишет:
а лучше еще диодами двумя защитить до стабилизатора.
до какого стабилизатора?

nevkon
Offline
Зарегистрирован: 20.01.2015

Вы ведь не 12В будете в контроллер подавать, а 5В я так думаю. Зачем грузить встроенный стабилизатор?

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

nevkon пишет:
Вы ведь не 12В будете в контроллер подавать, а 5В я так думаю. Зачем грузить встроенный стабилизатор?
nevkon, пожалуйста, делайте скидку на то, что я новичок. И то, что для вас очевидно или подразумевается, для меня - нет. Так что не пропускайте слов в предложении, пожалуйста :)

Да, конечно, я буду подавать 5в. Речь шла о помехах и наводках. И если я правильно понял рекбус, то вы имеете ввиду, что от блока питания 5в на провод перед тем, как втыкать его в ардуинку, надо поставить RC фильтр. И вы сказали еще про два диода... Куда? Как? Вместе с RC? Если это отдельный блок питания, зачем на него такие навороты?

nevkon
Offline
Зарегистрирован: 20.01.2015

Диоды ставятся до преобразователя 12В -> 5В. Один защищает от переполюсовки, другой от импульсов. Можно поставить еще элемент замыкающий цепь при высоком напряжении (варистор кажется). Меня схема защиты уже раз спасла. Пришлось только поменять один конденсатор который стоял до защиты.

Диоды ставятся так: один в разрыв цепи на плюсе. Второй ставится перед первым от минуса к плюсу (так чтобы цепь замыкалась при обратном импульсе, правда в этом случае при переполюсовке можно перегрузить БП на 12В).

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

может глупость спрошу - а почему не использовать блок питания для ардуинки сразу на 5в? отдельный

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Так, ну вот я сделал первый прикид по логике. Посмотрите, пожалуйста, может где что не увидел. Картинка (на облаке мыл.ру) + файлик в Pencil (там же).

И вот описалово текстовое.

ОПИСАНИЕ ЛОГИКИ

Существует 6 состояний системы, исходя из состояния датчиков.

1.	Замкнут верхний датчик (TOP) перелива. Аварийное состояние.
2.	Замкнуты все три датчика уровня (A1, A2, A3). Полная емкость.
3.	Замкнуты два датчика (A2, A3). Емкость неполная, включение насоса не требуется (идет расход воды после максимума).
4.	Замкнуты два датчика (A2, A3). Емкость неполная, насос включен. Идет закачка воды после выключения второго датчика.
5.	Замкнут только нижний датчик (A3). Включение насоса (если не включен). Идет закачка воды.
6.	Разомкнут нижний датчик A3. Аварийная состояние (исключение режим FORCE).

Предполагается, что система может начать работу в любом из 6 состояний, при этом насос не включен: замкнут датчик перелива, замкнуты все три датчика, только два, только один, ни один. 
При первичном включении и пустом баке предусмотреть пропуск анализа нижнего датчика А3 в течении 5 минут. 

Последовательность
•	Проверка на переполнение. Если да – аварийный режим.
•	Нет – диодик ОК
•	Проверяем не нажата ли кнопка форсажа (первичное включение). Да – запускаем обратный таймер FORCE.
•	Проверяем включен ли таймер простоя. Если нет – то это первое включение и принудительно прокачиваем на улицу 15 минут. Если включен, то проверяем А1.
•	А1 замкнут. Диодик. Таймер включен? Нет – включаем.
•	Выключаем насос (если был включен)
•	Дальше цикл проверки оставшихся датчиков. Если кто-то не работает при рабочем верхнем, значит это глюк (за исключением режима «форсаж» для нижнего датчика). Переходим в аварийный режим. Поскольку это может быть первым включением, то зажигаем зеленые диодики в случае ОК по остальным датчикам.
•	Если А1 разомкнут. Красный диодик.
•	А2 замкнут? Если да, зажигаем зеленый диодик.
•	Насос включен? Если да, то мы в режиме наполнения. Проверим нижний датчик. Если ОК (или «форсаж») на начало.
•	Если выключен – проверяем включен ли был таймер простоя. Нет – включаем. Проверка А3 и т.д.
•	А2 разомкнут. Красный диодик.
•	Если таймер простоя > 3 часов, то слив. Таймер простоя останавливаем и сбрасываем. Включаем вентиль, задержка на перекрытие, включаем насос. 15 минут сливаем, переключаем вентиль.
•	Если А2 не успел включиться к следующему циклу, то таймер еще будет остановлен. Проверяем работает ли насос.
•	Если насос работает, то значит перед этим мы только что делали слив и находимся в режиме заполнения. Идем в начало цикла.
•	Если насос выключен, значит это первое включение системы. Тогда идем в цикл слива. И т.д.

Предусмотреть после включения режим паузы в ожидании нажатии кнопки СТАРТ. В это время можно установить режимы СЛИВ и/или FORCE, просмотреть состояние датчиков, войти в режим настройки параметров и т.д.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

похоже, схема сильно сложная, чтобы вникать?

или все так плохо, что даже и сказать нечего?

nevkon
Offline
Зарегистрирован: 20.01.2015

Состояния 2 и 3 можно объединить. Налив воды инициируется по замкнутому только нижнему датчику (состояние 5) и анализ среднего датчика нужно только для определения полемкости, непосредственно в чистом виде средний датчик не анализируется. Соответственно 4 состояние анализируется по замыканию верхнего датчика (нижний и средний не обязательно анализировать - а вдруг они отвалились и спровоцируется аварийная ситуация на ровном месте).

И не нужно при включении нажимать форс. Убегаетесь к пульту. Система должна сработать по событию. Включение и нет замкнутых/замкнут А1 и не авария - запускаем дренаж, наливаем емкость до А3. Кстати А3 советую перелить секунд 10 хотяб чтобы можно было определить точно работоспособность датчиков.

Схему если честно не осилил - глаза от нее в кучку. Слишком много пересекающихся линий. По описанию.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

спасибо огромное, вечером внимательнее прочитаю ваше предложение

про схему - да, она действительно сложная к просмотру. А какие варианты (в смысле в чем и как планирвоать такую схему)?

Для удобства я достал Lazarus сделал эмулятор систмы, чтобы проверить работоспособность и правльность логики.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Снова всем добрый день. Как говорится, скоро сказка сказывается.

Потихоньку приходят мои посылочки с Китаю. Правда основная посылка с макетками, дисплейчиком и еще некоторыми мелочами где-то зависло у веселых мадьяр.

Пока суть да дело - запустил вчера водоснабжение в "ручном" режиме. Иду в котельную, ручками включаю трех-ходовой, жду, потом отключаю его, наполняю бочку. Практически все работает (немного подтекает резьба фильтра, но надеюсь сегодня пофиксю).

Разобрался со сдвиговым регистром и оптроном. Вроде запускаются, диодики мигают. Стал дальше продвигаться в моделировании схемы - и застрял. Короче вопрос такой:

#define TOP_SWITCH 2    
#define TOP_LED    3       
#define MIDDLE_SWITCH 4   
#define MIDDLE_LED    5      
#define BOTTOM_SWITCH 6   
#define BOTTOM_LED    7      


int buttonState[] = {0, 0, 0};
int lastButtonState[] = {0, 0, 0};
int flagS [] = {0, 0, 0};

void setup() {

  pinMode(TOP_SWITCH, INPUT);
  pinMode(MIDDLE_SWITCH, INPUT);
  pinMode(BOTTOM_SWITCH, INPUT);

  pinMode(TOP_LED, OUTPUT);
  pinMode(MIDDLE_LED, OUTPUT);
  pinMode(BOTTOM_LED, OUTPUT);

  Serial.begin(9600); //чисто для удовольствия
}

void loop() {
  buttonState[0] = digitalRead(TOP_SWITCH);
  buttonState[1] = digitalRead(MIDDLE_SWITCH);
  buttonState[2] = digitalRead(BOTTOM_SWITCH);
//------------------------------------------------------------------
  if (buttonState[0] != lastButtonState[0]) {
    if (buttonState[0] == HIGH && flagS[0] == 0) {
      Serial.println("TOP button ON");
      flagS[0] = 1;
      digitalWrite(TOP_LED, HIGH);
    }
    else {
      if (buttonState[0] == HIGH && flagS[0] == 1) {
        Serial.println("TOP button OFF");
        flagS[0] = 0;
        digitalWrite(TOP_LED, LOW);
      }
    }
    delay(100);
  }
  lastButtonState[0] = buttonState[0];
//------------------------------------------------------------------
  if (buttonState[1] != lastButtonState[1]) {
    if (buttonState[1] == HIGH && flagS[1] == 0) {
      Serial.println("MIDDLE button ON");
      flagS[1] = 1;
      digitalWrite(MIDDLE_LED, HIGH);
    }
    else {
      if (buttonState[1] == HIGH && flagS[1] == 1) {
        Serial.println("MIDDLE button OFF");
        flagS[1];
        digitalWrite(MIDDLE_LED, LOW);
      }
    }
    delay(100);
  }
  lastButtonState[1] = buttonState[1];
//------------------------------------------------------------------
  if (buttonState[2] != lastButtonState[2]) {
    if (buttonState[2] == HIGH && flagS[2] == 0) {
      Serial.println("BOTTOM button ON");
      flagS[2] = 1;
      digitalWrite(BOTTOM_LED, HIGH);
    }
    else {
      if (buttonState[2] == HIGH && flagS[2] == 1) {
        Serial.println("BOTTOM button OFF");
        flagS[2] = 0;
        digitalWrite(BOTTOM_LED, LOW);
      }
    }
    delay(100);
  }
  lastButtonState[2] = buttonState[2];
}

Вот так все работает. А именно - кнопочку нажал, диодик загорелся и горит, пока второй раз не нажму. Теперь хочу вынести всю кухню в функцию.

#define TOP_SWITCH 2   
#define TOP_LED    3     
#define MIDDLE_SWITCH 4   
#define MIDDLE_LED    5    
#define BOTTOM_SWITCH 6  
#define BOTTOM_LED    7    

int buttonState[] = {0, 0, 0};
int lastButtonState[] = {0, 0, 0};
int flagS [] = {0, 0, 0};

void setup() {

  pinMode(TOP_SWITCH, INPUT);
  pinMode(MIDDLE_SWITCH, INPUT);
  pinMode(BOTTOM_SWITCH, INPUT);

  pinMode(TOP_LED, OUTPUT);
  pinMode(MIDDLE_LED, OUTPUT);
  pinMode(BOTTOM_LED, OUTPUT);

  Serial.begin(9600);
}

void led_switching (int switchNumber){

     if (buttonState[switchNumber] == HIGH && flagS[switchNumber] == 0) {
      Serial.println(switchNumber);
      flagS[switchNumber] = 1;
      digitalWrite(TOP_LED, HIGH);
    }
    else {
      if (buttonState[switchNumber] == HIGH && flagS[switchNumber] == 1) {
        Serial.println(switchNumber);
        flagS[switchNumber] = 0;
        digitalWrite(TOP_LED, LOW);
      }
    }
    delay(500);
 }

void loop() {
  buttonState[0] = digitalRead(TOP_SWITCH);
  buttonState[1] = digitalRead(MIDDLE_SWITCH);
  buttonState[2] = digitalRead(BOTTOM_SWITCH);

if (buttonState[0] != lastButtonState[0]) {
 led_switching(0);
 }

 if (buttonState[1] != lastButtonState[1]) {
 led_switching(1);
 }

 if (buttonState[1] != lastButtonState[1]) {
 led_switching(1);
 }
 }

Не работает :(

По выводу в порт вижу, что кнопки неверно распознаются. Первая распознается, вторая определяется, как первая. Третья вообще не определяется.

Я что-то не пойму... ХЕлп.

nevkon
Offline
Зарегистрирован: 20.01.2015

55-57 строка наверно номер 2 должно стоять

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

И не только :)

Действительно, обшибся, как это бывает: смотришь в упор и не видишь. Но кроме этого функция указывала директивно

digitalWrite(TOP_LED, HIGH);

ну и LOW соответственно.

Корче слегка причесал, теперь вот так. Все работает.

#define TOP_SWITCH 2   
#define TOP_LED    3
       
#define MIDDLE_SWITCH 4   
#define MIDDLE_LED    5 
     
#define BOTTOM_SWITCH 6   
#define BOTTOM_LED    7     

int buttonState[] = {0, 0, 0};
int lastButtonState[] = {0, 0, 0};
int flagS[] = {0, 0, 0};
int ledS[] = {TOP_LED, MIDDLE_LED, BOTTOM_LED};
String ledSName[] = {"Top switch","Middle switch","Bottom switch"};

void setup() {

  pinMode(TOP_SWITCH, INPUT);
  pinMode(MIDDLE_SWITCH, INPUT);
  pinMode(BOTTOM_SWITCH, INPUT);

  pinMode(TOP_LED, OUTPUT);
  pinMode(MIDDLE_LED, OUTPUT);
  pinMode(BOTTOM_LED, OUTPUT);

  Serial.begin(9600);
}

void led_switching (int switchNumber){
     if (buttonState[switchNumber] == HIGH && flagS[switchNumber] == 0) {
      Serial.println(ledSName[switchNumber]+ " is ON");
      flagS[switchNumber] = 1;
      digitalWrite(ledS[switchNumber], HIGH);
    }
    else {
      if (buttonState[switchNumber] == HIGH && flagS[switchNumber] == 1) {
        Serial.println(ledSName[switchNumber]+ " is OFF");
        flagS[switchNumber] = 0;
        digitalWrite(ledS[switchNumber], LOW);
      }
    }
    // Delay a little bit to avoid bouncing
    delay(500);
 }

void loop() {
  buttonState[0] = digitalRead(TOP_SWITCH);
  buttonState[1] = digitalRead(MIDDLE_SWITCH);
  buttonState[2] = digitalRead(BOTTOM_SWITCH);

 if (buttonState[0] != lastButtonState[0]) {
 led_switching(0);
 }

 if (buttonState[1] != lastButtonState[1]) {
 led_switching(1);
 }

 if (buttonState[2] != lastButtonState[2]) {
 led_switching(2);
 }
}

Теперь хочу запустить все это хозяйство через сдвиговый регистр 74HC595, чтоб на будущее не париться в добавках +led

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Так, кажется заработало.

// определяем пины для переключателей
#define TOP_SWITCH    2     
#define MIDDLE_SWITCH 3  
#define BOTTOM_SWITCH 4  

// устанавливаем управление сдвиговым регистром
int latchPin  = 8;
int clockPin  = 12;
int dataPin   = 11;
uint8_t ledsBurn = 0; //переменная для передачи в регистр

// остальное
int switchState[] = {0, 0, 0}; // состояние переключателей
int lastSwitchState[] = {0, 0, 0}; // предыдущее состояние
int flagS[] = {0, 0, 0}; // флаги для хранения состояний переключателей
String ledSName[] = {"Top switch","Middle switch","Bottom switch"};// названия для вывода в порт

byte ledS[] = {B00000001, B00000010, B00000100}; //тут храним значения для "зажигания" диодов. Пока их три

void setup() {
  // настройка сдвигового регистра
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
 
  // инициализация кнопок
  pinMode(TOP_SWITCH, INPUT);
  pinMode(MIDDLE_SWITCH, INPUT);
  pinMode(BOTTOM_SWITCH, INPUT);
 
  // инициализируем порт
  Serial.begin(9600);
}


void led_switching (int switchNumber){
     if (switchState[switchNumber] == HIGH && flagS[switchNumber] == 0) {
      // если состояние HIGH и флаг не был установлен
      // включаем
      Serial.println(ledSName[switchNumber]+ " is ON");
      ledsBurn = ledsBurn ^ ledS[switchNumber]; // побитовое XOR
      flagS[switchNumber] = 1;
    }
    else {
      if (switchState[switchNumber] == HIGH && flagS[switchNumber] == 1) {
        // если состояние LOW
        // выключаем
        Serial.println(ledSName[switchNumber]+ " is OFF");
        ledsBurn = ledsBurn ^ ledS[switchNumber];
        flagS[switchNumber] = 0;
      }
    }
    // немного ждем
    delay(100);
    lastSwitchState[switchNumber] = switchState[switchNumber];//обновляем значение последнего состояния переключателя
 }

void loop() {
// читаем состояние переключателей
  switchState[0] = digitalRead(TOP_SWITCH);
  switchState[1] = digitalRead(MIDDLE_SWITCH);
  switchState[2] = digitalRead(BOTTOM_SWITCH);

//в случае изменения состояния переключателей идем в функцию
 if (switchState[0] != lastSwitchState[0]) {
 led_switching(0);
 }
 if (switchState[1] != lastSwitchState[1]) {
 led_switching(1);
 }
 if (switchState[2] != lastSwitchState[2]) {
 led_switching(2);
 }

// работаем со сдвиговым регистром
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, ledsBurn);
  digitalWrite(latchPin, HIGH);
}

Я пробовал обойтись только  switchState, но тогда глючило. Когда добавил проверку и установку flagS - стало работать. Почему - не вижу... Но по ощущению - это избыточно, но как сократить - не понимаю :(

Может еще что-то лишнее или слишком длинно?

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Сам с обой веду беседу :)

Короче немного расширил код

// определяем пины для переключателей
#define TOP_SWITCH      2
#define MIDDLE_SWITCH   3
#define BOTTOM_SWITCH   4
#define OVERFLOW_SWITCH 5

#define BLINK_DELAY   200

// устанавливаем управление сдвиговым регистром
int latchPin  = 8;
int clockPin  = 12;
int dataPin   = 11;
uint8_t ledsBurn = 0; //переменная для передачи в регистр

// остальное
byte switchState[] = {0, 0, 0, 0}; // состояние переключателей
byte lastSwitchState[] = {0, 0, 0, 0}; // предыдущее состояние
byte flagS[] = {0, 0, 0, 0}; // флаги для хранения состояний переключателей
byte blinkF[] = {0, 0, 0, 0}; //флаги для включения blink
bool flagT = false; // временный флаг
String ledSName[] = {"Top switch", "Middle switch", "Bottom switch", "OverFlow switch"}; // названия для вывода в порт

byte ledS[] = {B00000001, B00000010, B00000100, B00001000}; //тут храним значения для "зажигания" диодов. Пока их три

void setup() {
  // настройка сдвигового регистра
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  // инициализация кнопок
  pinMode(TOP_SWITCH, INPUT);
  pinMode(MIDDLE_SWITCH, INPUT);
  pinMode(BOTTOM_SWITCH, INPUT);
  pinMode(OVERFLOW_SWITCH, INPUT);

  // инициализируем порт
  Serial.begin(9600);
}


void led_switching (int switchNumber) {
  if ((switchState[switchNumber] == HIGH) && (flagS[switchNumber] == 0)) {
    // если состояние HIGH и флаг не был установлен
    // включаем
    Serial.println(ledSName[switchNumber] + " is ON");
    ledsBurn = ledsBurn ^ ledS[switchNumber]; // побитовое XOR
    blinkF[switchNumber] = 1; // установка флага для blink на все подряд
    // по-хорошему надо бы как-то по-другому
    flagS[switchNumber] = 1;
  }
  else {
    if (switchState[switchNumber] == HIGH && flagS[switchNumber] == 1) {
      // если состояние LOW
      // выключаем
      Serial.println(ledSName[switchNumber] + " is OFF");
      if (bitRead(ledsBurn, switchNumber) == 1) {
        ledsBurn = ledsBurn ^ ledS[switchNumber];
      }
      blinkF[switchNumber] = 0;
      flagS[switchNumber] = 0;
    }
  }
  // немного ждем
  delay(10);
  lastSwitchState[switchNumber] = switchState[switchNumber];//обновляем значение последнего состояния переключателя
}

void loop() {

  // читаем состояние переключателей
  switchState[0] = digitalRead(TOP_SWITCH);
  switchState[1] = digitalRead(MIDDLE_SWITCH);
  switchState[2] = digitalRead(BOTTOM_SWITCH);
  switchState[3] = digitalRead(OVERFLOW_SWITCH);

  //в случае изменения состояния переключателей идем в функцию
  if (switchState[0] != lastSwitchState[0]) {
    led_switching(0);
  }
  if (switchState[1] != lastSwitchState[1]) {
    led_switching(1);
  }
  if (switchState[2] != lastSwitchState[2]) {
    led_switching(2);
  }
  if (switchState[3] != lastSwitchState[3]) {
    led_switching(3);
  }
  // мигаем
  if (blinkF[3] == 1) {
    if ((millis() / BLINK_DELAY) % 2 == 1)   {
      if (!flagT) {
        ledsBurn = ledsBurn ^ ledS[3];
        flagT = true;
      }
    }
    else
    {
      flagT = false;
    }
  }

  // работаем со сдвиговым регистром
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, ledsBurn);
  digitalWrite(latchPin, HIGH);
}

Добавил для последнего диода мигание без использования delay. Для унификации решил в led_switching по любому устанавливать флаги "мигания".

Ну и потом уже жестко определяю, что это только для 4 диодика.

Все работает, но от кода ощущение какой-то коряватости...

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Так, вот немного подумал и оптимизировал тему

// определяем пины для переключателей
#define TOP_SWITCH      2
#define MIDDLE_SWITCH   3
#define BOTTOM_SWITCH   4
#define OVERFLOW_SWITCH 5
#define BLINK_DELAY   200

// устанавливаем управление сдвиговым регистром
int latchPin  = 8;
int clockPin  = 12;
int dataPin   = 11;
uint8_t ledsBurn = 0; //переменная для передачи в регистр

// остальное
byte switchState[] = {0, 0, 0, 0}; // состояние переключателей
byte lastSwitchState[] = {0, 0, 0, 0}; // предыдущее состояние
byte flagS[] = {0, 0, 0, 0}; // флаги для хранения состояний переключателей
byte blinkF[] = {0, 0, 0, 1}; /*флаги для включения blink, здесь указываем по умолчанию какие диоды будут мигать (1),
                              а какие гореть постоянно (0)*/
bool flagT[] = {false, false, false, false}; // временный флаг

String ledSName[] = {"Top switch", "Middle switch", "Bottom switch", "OverFlow switch"}; // названия для вывода в порт
byte  ledS[] = {B00000001, B00000010, B00000100, B00001000}; //тут храним значения для "зажигания" диодов. Пока их три

void setup() {
  // настройка сдвигового регистра
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  // инициализация кнопок
  for (int i = 2; i < 6; i++) {
    pinMode(i, INPUT);
  }
  // инициализируем порт
  Serial.begin(9600);
}

void led_switching (int switchNumber) {
  if ((switchState[switchNumber] == HIGH) && (flagS[switchNumber] == 0)) {
    // если состояние HIGH и флаг не был установлен
    // включаем
    Serial.println(ledSName[switchNumber] + " is ON");
    bitWrite(ledsBurn, switchNumber, 1);
    flagS[switchNumber] = 1;
  }
  else {
    if ((switchState[switchNumber] == HIGH) && (flagS[switchNumber] == 1)) {
      // если состояние LOW
      // выключаем
      Serial.println(ledSName[switchNumber] + " is OFF");
      bitWrite(ledsBurn, switchNumber, 0);
      flagS[switchNumber] = 0;
    }
  }
  // немного ждем
  delay(10);
  lastSwitchState[switchNumber] = switchState[switchNumber];//обновляем значение последнего состояния переключателя
}

void loop() {
  // читаем состояние переключателей
  for (int i = 2; i < 6; i++) {
    switchState[i - 2] = digitalRead(i);
  }
  //в случае изменения состояния переключателей идем в функцию
  for (int i = 0; i < 4; i++) {
    if (switchState[i] != lastSwitchState[i]) {
      led_switching(i);
    }
  }
  // мигаем

  for (int i = 0; i < 4 ; i++) {
    if ((blinkF[i] == 1) && (flagS[i]) == 1) {//добавил проверку установки флага flagS и теперь не сбрасываю blinkF
      if ((millis() / BLINK_DELAY) % 2 == 1)   {
        if (!flagT[i]) {
          /* если не устанавливать этот флаг, то диод будет мелко мигать пока
                           значение millis() в допустимом диапазоне значений */
          ledsBurn = ledsBurn ^ ledS[i];
          //попробовать использовать сдвиг влево в байте 00000001 [i-1] вместо хранения всех вариантов в массиве
          flagT[i] = true;
        }
      }
      else
      {
        flagT[i] = false;
      }
    }
  }
  // работаем со сдвиговым регистром
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, ledsBurn);
  digitalWrite(latchPin, HIGH);
}

 

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Возникла странная ситуация - если загружаю скетч из Arduino IDE - то скетч работает криво (диоды не загораются, но в порт все пишется). Если выключить плату из USB и включить снова (или нажать reset) то скетч работает нормально. Шо це такэ?

P.S.

Сейчас вспомнил, после чего это могло произойти. Мне пришел китайский клон Arduino NANO, ну он конечно IDE-шкой не определялся. Закачал дрова специальные для него, установил - все пучком. NANO определяется и все в нее заливается. Но вот видимо что-то эти дрова добавили "необратимого", чего до этого не было...

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

и при этом еще странность заливаю скетч, открываю порт - в порт выводится все правильно (т.е. обработка нажатия кнопок), а вот диоды не загораются после перезагрузки - все ОК и то и другое работает...

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Странно. теперь снова все работает после заливки скетча без перезагрузки :)

короче, вот что сейчас в наличии

Не нашел нормального шилда LCD с кнопками. Так что просто подписал подключение двух пинов шилда. Понятное дело, что эти монстрообразные кнопки представляют собой поплавковые выключатели. Первая кнопка специально инвертирована (по сравнению с остальными 3-мя)

Код написал, работает. Хочу немного причесать и вечерком выложу

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

шшшш.... сссс...пппп..ррррр..ууууу..ыыыыыыыыы короче я не знаю, что случилось - на скетч был непонятным образом удален с компа (понятно что как-то моими собственными руками), причем все архивные варианты тоже... :(

ну, зато лучше узнаю С++

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Angbor пишет:
Все работает, но от кода ощущение какой-то коряватости...

Так и есть.... очень хорошо, что ты его удалил. Так писать нельзя.

Ты в каждом цикле опрашиваешь переключатели и выводишь в сдвиговый регистр. Реализация чтения переключателей это просто жесть: цикл от 2 до 5, что бы прочитать выводы 2-5. Теряюсь в догадках, как бы ты реализовал будь ноги не по порядку. На переключатели нужен антидребезг, опрашивать их достаточно раз в 50 миллисекунд, чаще нет смысла. Назначение сдвигового регистра для светодиодов мне не понятно, ног что ли не хватает? В регистр достаточно выводить только при изменении индикации, иначе у тебя светодиоды моргают с частотой десятки кГц. Есть осциллограф? Посмотри любопытства ради.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

:)

жестко, но хорошо :)

а в чем ужас чтения выводов циклом? абстрактное "если бы" тут не катит, у меня же конкретный случай. если не так, то как?

очень помогло, если бы вы на конкретных примерах советовали. у меня уровень не такой высокий, чтобы намеки понимать

про частоту услышал, и правда что - часто - поправил (как мог)

регистр - да, ног не хватает, если посмотрите на картинку выше - подключил через регистр LCD и релешу - еле еле  вобщем-то

 

ужосный код восстановил (почти) на всяк случай сохраню тут

// определяем пины для переключателей
#define BOTTOM_SWITCH   2
#define MIDDLE_SWITCH   3
#define TOP_SWITCH      4
#define OVERFLOW_SWITCH 5
#define BLINK_DELAY   200

#define PUMP            9
#define PUMP_ON         1
#define PUMP_OFF        0
#define THREE_WAY_VALWE 10
#define TWV_ON          1
#define TWV_OFF         0

// устанавливаем управление сдвиговым регистром
int latchPin  = 8;
int clockPin  = 12;
int dataPin   = 11;
uint8_t ledsBurn = 0; //переменная для передачи в регистр
//long led_reg_millis = 0; // храним значение с последнего

// реле
bool pumpState = false;

// остальное
byte switchState[] = {1, 0, 0, 0}; // состояние переключателей
byte lastSwitchState[] = {0, 0, 0, 0}; // предыдущее состояние
byte blinkF[] = {1, 0, 0, 1}; /*флаги для включения blink, здесь указываем по умолчанию какие диоды будут мигать (1),
                              а какие гореть постоянно (0)*/
bool flagT[] = {false, false, false, false}; // временный флаг для цикла blink

String ledSName[] = {"Bottom switch", "Middle switch", "Top switch", "OverFlow switch"}; // названия для вывода в порт
byte  ledS[] = {B00000001, B00000010, B00000100, B00001000}; //тут храним значения для "зажигания" диодов. Пока их три

void setup() {
  // настройка сдвигового регистра
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  // инициализация реле
  pinMode(PUMP, OUTPUT);
  pinMode(THREE_WAY_VALWE, OUTPUT);

  // инициализация кнопок
  for (int i = 2; i < 6; i++) {
    pinMode(i, INPUT);
  }
  // инициализируем порт
  Serial.begin(9600);
}

void pumpOnOff (int onOrOff) {
  if ((onOrOff == 1) && !pumpState) {
    digitalWrite(PUMP, PUMP_ON);
    pumpState = true;
  }
  if ((onOrOff == 0) && pumpState) {
    digitalWrite(PUMP, PUMP_OFF);
    pumpState = false;
  }
}

void led_switching (int switchNumber) {
  if (switchState[switchNumber] == HIGH) {
    // если состояние HIGH и флаг не был установлен
    // включаем
    Serial.println(ledSName[switchNumber] + " is ON");
    bitWrite(ledsBurn, switchNumber, 1);
  }
  else {
    if (switchState[switchNumber] == LOW) {
      // если состояние LOW
      // выключаем
      Serial.println(ledSName[switchNumber] + " is OFF");
      bitWrite(ledsBurn, switchNumber, 0);
    }
  }
  // немного ждем
  delay(10);
  lastSwitchState[switchNumber] = switchState[switchNumber];//обновляем значение последнего состояния переключателя
}

void blinkS() {
  // мигаем
  for (int i = 0; i < 4 ; i++) {
    if ((blinkF[i] == 1) && (switchState[i]) == 1) {
      if ((millis() / BLINK_DELAY) % 2 == 1)   {
        if (!flagT[i]) {
          /* если не устанавливать этот флаг, то диод будет мелко мигать пока
             значение millis() в допустимом диапазоне значений
             можно использовать переменную и делать типа:
             if ((millis() - lastMillis) <= BLINK_DELAY) THEN ->

          */
          ledsBurn = ledsBurn ^ ledS[i];
          //попробовать использовать сдвиг влево в байте 00000001 [i-1] вместо хранения всех вариантов в массиве
          flagT[i] = true;
        }
      }
      else
      {
        flagT[i] = false;
      }
    }
  }
}

bool checkOverflow() {
  if (switchState[3] == 1) {
    Serial.println("OVERFLOW");
    return false;
  }
  if (switchState[3] == 0) {
    // Serial.println("NOT OVERFLOW");
    return true;
  }
}

bool checkSwitchesCombination() {
  if (checkOverflow()) {// если не переполнение
    if (((switchState[0] == 1) && (switchState[1] == 1) && (switchState[2] == 1)) ||
        ((switchState[0] == 1) && (switchState[1] == 0) && (switchState[2] == 1)) ||
        ((switchState[0] == 1) && (switchState[1] == 1) && (switchState[2] == 0))) {
      Serial.println("WRONG COMBINATION");
      pumpOnOff(0);
      return false;
    }
    else { // если комбинация не ошибочная
      return true;
    }
  }
  else {
    pumpOnOff(0);
    return false; // если checkOverflow вернула ошибку
  }
}

void pump() {
  if (checkSwitchesCombination()) {
    if ((switchState[0] == 1) && (switchState[1] == 0) && (switchState[2] == 0)) {
      Serial.println("1");
      pumpOnOff(1);
    }
    if ((switchState[0] == 0) && (switchState[1] == 1) && (switchState[2] == 0)) {
      Serial.println("2");
      pumpOnOff(1);
    }
    if ((switchState[0] == 0) && (switchState[1] == 1) && (switchState[2] == 1)) {
      Serial.println("3");
      pumpOnOff(0);
    }
  }
}

void loop() {
  // читаем состояние переключателей
  for (int i = 2; i < 6; i++) {
    switchState[i - 2] = digitalRead(i);
  }
  //в случае изменения состояния переключателей идем в функцию
  for (int i = 0; i < 4; i++) {
    if (switchState[i] != lastSwitchState[i]) {
      led_switching(i);
    }
  }
  blinkS();
  pump();//checkSwitchesCombination();

  // работаем со сдвиговым регистром
  if ((millis() - led_reg_millis) <= 100) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, ledsBurn);
  digitalWrite(latchPin, HIGH);
  led_reg_millis = millis();
  }
}

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Angbor пишет:
а в чем ужас чтения выводов циклом? абстрактное "если бы" тут не катит, у меня же конкретный случай. если не так, то как? очень помогло, если бы вы на конкретных примерах советовали. у меня уровень не такой высокий, чтобы намеки понимать

Не знаю чем не устроило просто 4 чтения digitalRead() с каждой ноги. Объяви массив входов и по нему бегай. Например так:

#define NUM 4
#define BOTTOM_SWITCH   2
#define MIDDLE_SWITCH   3
#define TOP_SWITCH   4
#define OVERFLOW_SWITCH  5
int arr[NUM] PROGRAM={BOTTOM_SWITCH, MIDDLE_SWITCH, TOP_SWITCH, OVERFLOW_SWITCH};
#define GET(b) digitalRead(arr[b])

void loop()
{
  for (byte i=0; i<NUM; i++)
  {
    button[i]=GET(i);
  }
}

Angbor пишет:
регистр - да, ног не хватает, если посмотрите на картинку выше - подключил через регистр LCD и релешу - еле еле  вобщем-то
У индикатора есть шина данных, используй лучше её для параллельной записи в регистр.

Angbor
Angbor аватар
Offline
Зарегистрирован: 26.10.2015

Andy пишет:
Не знаю чем не устроило просто 4 чтения digitalRead() с каждой ноги. Объяви массив входов и по нему бегай. Например так:
хм.. интересно, спасибо, выглядит красиво. теперь попробую еще понять, что это и зачем. Не пойму, зачем так:

#define NUM 4
int arr[NUM] PROGRAM={BOTTOM_SWITCH, MIDDLE_SWITCH, TOP_SWITCH, OVERFLOW_SWITCH};

не проще так:

int arr[] PROGRAM={BOTTOM_SWITCH, MIDDLE_SWITCH, TOP_SWITCH, OVERFLOW_SWITCH};

ну и чисто так, для протокола спрошу, а в чем разница по сути?

for (byte i=0; i<NUM; i++)
  {
    button[i]=GET(i);
  }

и

for (int i = 2; i < 6; i++) {
	switchState[i - 2] = digitalRead(i);
  }

в том, что выглядит аккуратнее? ведь в остальном по смыслу это одно и то же действие, только плюс еще один массив, так ведь?

Andy пишет:
У индикатора есть шина данных, используй лучше её для параллельной записи в регистр
а вот это не понял, можно поподробнее. ты имеешь ввиду ICSP?

у меня вот такой шилд