-
#1
Здравствуйте!
Решил опубликовать свой вариант аппарата который активно используется в жизни.
Эту часть текста я уже публиковал, но придётся повторится.
По-порядку.
Наливатор.
Немного о моём наливаторе.
В феврале 2022 года решил построить свой вариант аппарата.
Очень понравился РВСН-8 и Железный капут. Золотые руки мастера. Но т.к. живу в отдалении от всяких-разных фабрик-заводов, на которых можно было-бы реализовать многие узлы и детали пришлось думать, как изготовить «железяки» и самое главное, как написать программу.
Я немного программировал в AVR-Basic. Подойдя к решению проблемы программирования я понял, что шансов мало. Отсутствовали библиотеки которые мне нужны были, а писать алгоритмы из даташитов не хватает умения и терпения. Я, то и «читатель» плохинький, не говоря о «писателе».
Решил так, к двадцать третьему февраля 2023 года я должен изготовить наливатор и написать программу в Arduino IDE (изучив, на сколько можно язык программирования).
В крайнем случае, к Дню красной армии и ВМФ, сделаю механическую часть и сделаю примитивное управление, кнопку нажал – повернул каретку, кнопку нажал – налил.
Упёрся. Начал изучать Си и делать эксперименты с железом. Делал узел, писал алгоритм, проверял, и т.д.
И вот, 23 февраля 2023 года аппарат был торжественно продемонстрирован моим коллегам.
Корпус изготовил из фанеры и обклеил шпоном красного дерева и какого-то там дуба.
Наливатор позволяет налить от одной до шести рюмок одним выбранным объёмом от 15 до 50 мл.
Рюмки можно ставить как угодно, подряд, через одну, или вообще не ставить. В пустые места напиток не нальётся. Прокутит все шесть позиций и перейдёт в готовность снова налить.
Говорит тосты. Проигрывает музыку как из основного DF плеера, так и из второго MP3 плеера.
Показывать температуру напитка. И предупреждать, что напиток сильно согрелся. Так же от температуры зависит цвет подсветки под бутылкой, от синего до красного.
В «ручную» можно прокачивать напиток, как для заполнения трубочек, так и для их опорожнения.
Напиток качает перистальтический насос. Этот не пропускает напиток самотёком.
Аппарат состоит из:
Blue Pill (STM32F103C8T6) 128 КБ
Arduino Nano
HW134 (драйвер шагового мотора поворота каретки)
Шаговый мотор со старого дисковода типа NEMA.
DFPlayer (здесь тосты и несколько любимых песен)
BA6219(драйвер коллекторного мотора перистальтического насоса)
Перистальтический насос – это такой какими качают кровь.
ST7735 (дисплей)
LV53LOX (модуль лазерного дальномера)
DS18B20 (датчик температуры)
Оптрон с внешним каналом (снял со старой ККМ Samsung ER-250RF).
Ещё один «оптрон» изготовил из фотодиода и лазерного модуля от лазерной указки.
Модуль встраиваемого MP3, BT, FM, AUX плеера с ПДУ купленного на Aliexpress.
Модуль УНЧ 2х15 класса F(так написано) купленного там же.
74HC4053 (аналоговый коммутатор для озвучивания от DFPlayer или от встроенного)
WS2812 16 светодиодов для «умной» подсветки.
Кнопки, энкодер, готовый блок питания 12 Вольт 3 Ампера в корпусе с дырочками от китайцев.
Стабилизатор на 5 Вольт сделал сам.
Динамик, чтобы встроить во внутрь.
Два сдвоенных пружинных клеммных зажима для подключения внешней акустики.
Ещё, для реализации задуманного потребовался 3D-принтер. Но он уже был у меня.
Изначально, разрабатывая печатную плату, я в основном разместил модули и основные соединения. В процессе «допиливания» некоторые соединения менялись, некоторые создавались. ПП похожа на монтажку с проволочными соединениями.
Сейчас решил «закультурить» ПП и все соединения с нею.
Ещё предстоит довести до ума трубопровод.
Продолжение следует…
-
53.4 KB
Просмотры: 209
-
#2
Выкладываю несколько фотографий.
-
111.4 KB
Просмотры: 185 -
50.8 KB
Просмотры: 191 -
135.8 KB
Просмотры: 185 -
112.3 KB
Просмотры: 147
-
#3
Ещё три.
-
111.7 KB
Просмотры: 83 -
130.9 KB
Просмотры: 90 -
117.8 KB
Просмотры: 79
-
#4
И ещё.
-
132.6 KB
Просмотры: 63 -
44.1 KB
Просмотры: 76 -
48.6 KB
Просмотры: 72
-
#5
Это файл схемы .spl7
Пришлось упаковать.
Схема почти полная. Не показаны некоторые разъёмы. Также не показаны объединённые в плату узлы. (ОУ, коммутатор, подстроечные резисторы).
-
34.1 KB
Просмотры: 87
-
#6
Почему два процессора!?
Потому что не смог реализовать одновременное отслеживание за рюмками и управление ШД. (не хватило таланта в программировании. Изготавливал наливатор и изучал программирование одновременно).
Хочу отметить, что в упомянутом выше РВСН-8 и Железном капуте использовалось, по крайней мере, 11 реле. И программа одна и та же. По моим данным программу на тот момент написал школьник из СПб. В моём аппарате реле нет.
Arduino Nano отвечает за шаговый мотор, измерение температуры в бутылке, наличие-отсутствие рюмок с помощью лазерного дальномера.
STM32 отвечает за всё остальное. За энкодер, дисплей, кнопки, оптроны, DFPlayer(тосты и музыка) , коммутатор звуков, управление помпой, «пылающей» подсветкой WS2812. Так же выдаёт что нужно на Nano (управление ШД), и получает оттуда что можно(температуру, наличие рюмки).
На одной плате по размерам как УНЧ разместил 2 ОУ, коммутатор 74HC4053, подстроечные резисторы, преобразователь +5 в -5 Вольт для питания коммутатора.
Я установил ещё один плеер который воспроизводит независимо от DF плеера. Для удобства.
Изменено:
-
#7
Динамик DF Плеера установил в крышке в дне наливатора. На боковую стенку прикрутил два разъёма с пружинными зажимами для подключения проводов внешней акустики.
Ещё на боковую сторону прикрепил держатель ПДУ плеера. В этом держателе можно хранить штуцер для наливания при транспортировке.
-
#8
Работа наливатора, как обычно, начинается с включения тумблера.
Каретка поворачивается и так называемое исходное положение. Для этого в каретке имеется отверстие для «лазерного» оптрона. Каретка будет вращаться пока не лазер не засветит фотодиод.
Не знаю, может это лишнее, но мне нравится.
После этого на дисплее мелькнёт, на одну секунду, предупреждение о вреде алкоголя, после чего появится сообщение с предложением налить три рюмки по 20 мл. Предполагается, что соберутся три человека.
Энкодером, вращая в одну сторону, можно выбрать по кругу количество рюмок, от одной до шести. А при вращении в противоположную сторону – объём напитка в рюмке, от 15 до 50 мл с шагом 5 мл. Коротким нажатием энкодера подтверждаем свои намерения.
После этого долгим нажатием заставляем аппарат наполнить указанное количество рюмок указанным количеством напитка.
Рюмки могут быть из любых материалов, стекло, металл, пластик, керамика. Наличие рюмки на позиции определяет лазерный дальномер.
Если стоят не все «заявленные» рюмки, то аппарат прокрутит все шесть позиций, наливая в имеющиеся рюмки, и перейдёт в режим ожидания, простив отсутствующие рюмки.
После наливания последней рюмки прозвучит тост, который воспроизведёт DF плеер.
После очередного наливания прозвучит следующий тост. Не понравился формат представления MP3 файлов этом плеере. Ну да куда деваться.
При включении аппарата сразу начинает «звучать» второй MP3 плеер. На время тоста или воспроизведения музыки из DF плеера коммутатор переключается на DF плеер. Этим занимается вывод BUSY DF плеера.
Постоянно происходит контроль за температурой напитка. Значение температуры отображается на дисплее, а также происходит визуализация в виде «полыхающего» огня от синего до красного цвета в подставке под бутылку реализованной на светодиодах WS2812 в виде трёх лучей.
При достижении температуры 23° С подсветка начинает полыхать пурпурным цветом и каждые три минуты звучит предупреждающий звук и на дисплее отображается предупреждение.
Изменено:
-
#9
Конструкция.
Корпус из фанеры. Каретка, шестерни, рычаги, держатель лазерного дальномера, штуцерный узел (громко сказано), лазерный оптрон исходной позиции, опоры, держатель насоса, передняя панель, держатель наливного штуцера и ПДУ, ножки, погружаемый в бутылку цилиндр со всасывающим штуцером и датчиком температуры, подставка под бутылку вместе со светодиодной подсветкой создал во FreeCAD и напечатал на 3D принтере.
-
#10
О насосе.
Изначально я купил такой насос с моторчиком, который применяется в термопотах. Но оказалось, что в случае, если бутылка стоит так, что уровень жидкости выше уровня наливного штуцера, происходит самотёк. Капелька в несколько секунд на каретку. Пришлось покупать перистальтический насос. В нём отсутствует самотёк. Но и цена была раз в пять-шесть больше.
В качестве трубопроводов использовал силиконовые трубочки от капельницы и латунные трубки от телескопических антенн. Латунь паял чистым оловом.
-
#11
Доброго времени суток. А скетчи будут ?
Пт, 09/08/2019 — 11:32
#101
Forthomo
Offline
Зарегистрирован: 10.04.2019
atom23rus пишет:
Парни, а подскажите как откалибровать насос?
Секундомер есть в каждом сматрфоне, подоединяешь насос, через кнопку подаешь напряжение строго от внешнего источника которым будеш его питать, делаешь 10-20 замеров, высчитываешь среднее арифметическое. Насос 385 при питании 5В потребляет 150мА, 50 мЛ наливает в среднем за 5,5 сек.(5550 мсек)
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 11:45
#102
Forthomo
Offline
Зарегистрирован: 10.04.2019
stpavel пишет:
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал «Ну начали» перед наливом , можно засунуть в процедуру oled_naliv.
«Ну начали» надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:31
#103
atom23rus
Offline
Зарегистрирован: 06.08.2019
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:49
#104
stpavel
Offline
Зарегистрирован: 09.10.2018
Forthomo пишет:
stpavel пишет:
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал «Ну начали» перед наливом , можно засунуть в процедуру oled_naliv.
«Ну начали» надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
Ну если один раз при включении, можно засунуть в setup
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:53
#105
Forthomo
Offline
Зарегистрирован: 10.04.2019
stpavel пишет:
Ну если один раз при включении, можно засунуть в setup
#include <OLED_I2C.h> #include <Servo.h> #include "Adafruit_NeoPixel.h" #include <SoftwareSerial.h>//добавляем библиотеки #include <DFPlayer_Mini_Mp3.h>//добавляем библиотеку МП3 плейера // при необходимости создаем програмный порт для управдения МП3 плейером, если вывод в монитор TX(D0) RX(D1) необходим //SoftwareSerial mySoftwareSerial(10, 11); // RX, TX обозначаем програмный порт как mySoftwareSerial //плейер подключаем D10 D11 OLED myOLED(SDA, SCL, 8); //Подключение экрана А4, А5 extern uint8_t MegaNumbers[]; extern uint8_t RusFont[]; extern uint8_t SmallFont[]; unsigned long currentTime; unsigned long loopTime; unsigned long ledTime; // Переменные для энкодера ----------- const int pin_A = 2; // Подключение вывода A (CLK) энкодера const int pin_B = 3; // Подключение вывода B (DT) энкодера const int pin_SW = 4; // Подключение вывода кнопки (SW) энкодера unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev = 0; unsigned char encoder_sw_prew = 1; //Массив , обозначаем подключенные оптопары по выводам . Оптопары подключены, A0,A1,A2,A3,A6 const byte Optics[] = {0, 1, 2, 3, 6}; //Серво const int PIN_SERVO = 9; Servo servo; //Позиция каждой рюмки const byte Rumka_pos[] = {0,40,75,105,140}; //------------------------- byte Menu = 0; byte MenuFlag = 0; // Здесь храниться уровень меню. 0 находимся в Главном меню. 1 Вошли в меню Авто, 2 вошли в Ручное управление byte Drink = 25; // По умолчанию в рюмку наливаем 20 мл. const byte max_Drink = 50; // Максимум в рюмку - 50 мл. byte DrinkCount = 1; //По умолчанию, для ручного режима - 1 рюмка const byte max_DrinkCount = 5; //Максимальное кол-во рюмок - 5 // Насосик const byte PIN_PUMP = 12; // Светодиоды const int PIN_LED = 5;// Сюда подключаются светодиоды const int LED_COUNT = max_DrinkCount; Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN_LED, NEO_GRB + NEO_KHZ800); //------- void pump_enable() { digitalWrite(PIN_PUMP, 1); } void pump_disable() { digitalWrite(PIN_PUMP, 0); } void pump_timer(byte Drink) { digitalWrite(PIN_PUMP, 1); delay(map(Drink, 2, 50, 300, 4000)); digitalWrite(PIN_PUMP, 0); } void oled_menu(int Menu) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Y F K B D F N J H"), CENTER, 0);//Н А Л И В А Т О Р myOLED.print(F("F D N J"), CENTER, 15);//А В Т О myOLED.print(F("H E X Y J Q "), CENTER, 30);//Р У Ч Н О Й myOLED.print(F("G H J V S D R F"), CENTER, 45);//П Р О М Ы В К А myOLED.setFont(SmallFont); myOLED.print(F(">"), LEFT, (Menu * 15) + 15); myOLED.print(F("<"), RIGHT, (Menu * 15) + 15); myOLED.update(); } // выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение void DrinkInfo(byte pos) { if (Drink < 15) { myOLED.print(F("YB J XTV"), CENTER, pos);//НИ О ЧЕМ } else if (Drink < 28) { myOLED.print(F("GJ XENM - XENM"), CENTER, pos);//ПО ЧУТЬ - ЧУТЬ } else if (Drink < 38) { myOLED.print(F("D CFVSQ HFP"), CENTER, pos);//В САМЫЙ РАЗ } else if (Drink < 48) { myOLED.print(F("GJ GJKYJQ"), CENTER, pos);//ПО ПОЛНОЙ } else { myOLED.print(F("LJ RHFTD"), CENTER, pos);//ДО КРАЕВ } } void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Ye?"), CENTER, 20); //Ну, // Рандом - 1 switch (random(18)) { case 0: myOLED.print(F("pf dcnhtxe!"), CENTER, 40); //за встречу! mp3_play (2); // Проигрываем "mp3/0002.mp3" delay(100); mp3_stop(); break; case 1: myOLED.print(F("pf rhfcjne!"), CENTER, 40); //за красоту! mp3_play (3); // Проигрываем "mp3/0003.mp3" delay(100); mp3_stop(); break; case 2: myOLED.print(F("pf lhe;,e!"), CENTER, 40); //за дружбу! mp3_play (4); // Проигрываем "mp3/0004.mp3" delay(100); mp3_stop(); break; case 4: myOLED.print(F("pf ,hfncndj!"), CENTER, 40); //за братство! mp3_play (5); // Проигрываем "mp3/0005.mp3" delay(100); mp3_stop(); break; case 5: myOLED.print(F("pf"), CENTER, 38); //за myOLED.print(F("cghfdtlkbdjcnm!"), CENTER, 55); //справедливость! mp3_play (6); // Проигрываем "mp3/0006.mp3" delay(100); mp3_stop(); break; case 6: myOLED.print(F("pf hs,fkre!"), CENTER, 40); //за рыбалку! mp3_play (7); // Проигрываем "mp3/0007.mp3" delay(100); mp3_stop(); break; case 7: myOLED.print(F("pf bcreccndj!"), CENTER, 40); //за искусство! mp3_play (8); // Проигрываем "mp3/0008.mp3" delay(100); mp3_stop(); break; case 8: myOLED.print(F("pf hfpev!"), CENTER, 40); //за разум! mp3_play (9); // Проигрываем "mp3/0009.mp3" delay(100); mp3_stop(); break; case 9: myOLED.print(F("pf bcnbyys["), CENTER, 38); //за истинных myOLED.print(F(";tyoby!"), CENTER, 55); //женщин! mp3_play (10); // Проигрываем "mp3/0010.mp3" delay(100); mp3_stop(); break; case 10: myOLED.print(F("pf gjybvfybt!"), CENTER, 40); //за понимание! mp3_play (11); // Проигрываем "mp3/0011.mp3" delay(100); mp3_stop(); break; case 11: myOLED.print(F("pf tlbytybt!"), CENTER, 40); //за единение! mp3_play (13); // Проигрываем "mp3/0013.mp3" delay(100); mp3_stop(); break; case 12: myOLED.print(F("pf Gj,tle!"), CENTER, 40); //за Победу! mp3_play (16); // Проигрываем "mp3/0016.mp3" delay(100); mp3_stop(); break; case 13: myOLED.print(F("pf Hjlbye!"), CENTER, 40); //за Родину! mp3_play (20); // Проигрываем "mp3/0020.mp3" delay(100); mp3_stop(); break; case 14: myOLED.print(F("xnj, ujkjdf"), CENTER, 38); //чтоб голова myOLED.print(F("yt nhtofkf!"), CENTER, 55); //не трещала! mp3_play (17); // Проигрываем "mp3/0017.mp3" delay(100); mp3_stop(); break; case 15: myOLED.print(F("pf cjkblyjt"), CENTER, 38); //за солидное myOLED.print(F("ve;crjt vjkxfybt"), CENTER, 55); //мужское молчание mp3_play (12); // Проигрываем "mp3/0012.mp3" delay(100); mp3_stop(); break; case 16: myOLED.print(F("xnj, vjhobkj"), CENTER, 38); //чтоб морщило myOLED.print(F("vtymit!"), CENTER, 55); //меньше! mp3_play (18); // Проигрываем "mp3/0018.mp3" delay(100); mp3_stop(); break; case 17: myOLED.print(F("xnj, d cnjhjye"), CENTER, 38); //чтоб в сторону myOLED.print(F("yt dbkmyekj!"), CENTER, 55); //не вильнуло! mp3_play (19); // Проигрываем "mp3/0019.mp3" delay(100); mp3_stop(); break; } myOLED.update(); } /* void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("DSGMTV"), CENTER, 20); //Выпьем // Рандом - 1 switch (random(11)) { case 0: myOLED.print(F("PF LHEPTQ!"), CENTER, 40); //За друзей break; case 1: myOLED.print(F("PF VBKS{ LFV!"), CENTER, 40); //За милых дам break; case 2: myOLED.print(F("PF PLJHJDMT!"), CENTER, 40); //За здоровье break; case 3: myOLED.print(F("PF ELFXE!"), CENTER, 40); //За удачу break; case 4: myOLED.print(F("PF VBH DJ DCTV VBHT!"), CENTER, 40); //За мир во всем мире break; case 5: myOLED.print(F("PF NT{ RNJ D VJHT!"), CENTER, 40); //За тех кто в море break; case 6: myOLED.print(F("PF K><JDM !"), CENTER, 40); //За любовь ! break; case 7: myOLED.print(F("PF RHFCJNE !"), CENTER, 40); //За красоту ! break; case 8: myOLED.print(F("PF DTPTYBT !"), CENTER, 40); //За везение ! break; case 9: myOLED.print(F("PF HJLBYE !"), CENTER, 40); //За родину ! break; case 10: myOLED.print(F("PF YFC C DFVB"), CENTER, 38); //За нас с вами myOLED.print(F("B {HTY C YBVB !"), CENTER, 55); //И хрен с ними break; } myOLED.update(); } */ // Меню Авто режим void oled_auto(int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("F D N J"), CENTER, 0); myOLED.print(F("VK "), RIGHT, 27); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.setFont(MegaNumbers); myOLED.print(String(Drink), CENTER, 13); myOLED.update(); } // Меню Ручной режим void oled_manual(int DrinkCount, int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("H E X Y J Q"), CENTER, 0); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.print(F("H>V"), 24, 27); myOLED.print(F("VK "), RIGHT, 27); myOLED.setFont(MegaNumbers); myOLED.print(String(DrinkCount), LEFT, 13); myOLED.print(String(Drink), (Drink < 10) ? 80 : 57, 13); myOLED.update(); } void oled_naliv(int MenuFlag) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B D F > "), CENTER, 27); DrinkInfo(47); myOLED.update(); } void oled_nalito(int MenuFlag, int Nalito) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B N J"), CENTER, 20); if (Nalito == 1) { myOLED.print(F("H > V R F"), CENTER, 55); } else if (Nalito <= 4 ) { myOLED.print(F("H > V R B"), CENTER, 55); } else { myOLED.print(F("H > V J R"), CENTER, 55); } myOLED.setFont(SmallFont); myOLED.print(String(Nalito), CENTER, 36); myOLED.update(); } void ServoNaliv(byte rumka) { servo.attach(PIN_SERVO); for (int pos = servo.read(); pos <= Rumka_pos[rumka]; pos += 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию } servo.detach(); } void ServoParking () { //Serial.println(servo.read()); servo.attach(PIN_SERVO); for (int pos = servo.read(); pos >= 0; pos -= 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию } servo.detach(); } void CvetoMuzik() { for (int i = 0; i <= 7; i++) { for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 255, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 0, 255)); strip.show(); delay(30); } } } void setup() { //Serial.begin(9600); // servo.attach(PIN_SERVO); pinMode(pin_SW, INPUT); // устанавливаем pin pin_SW как вход digitalWrite(pin_SW, HIGH); // Поддяжка вывода к 1 pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); pinMode(PIN_PUMP, OUTPUT); digitalWrite(PIN_PUMP, 0); currentTime = millis(); loopTime = currentTime; //--------------- Serial.begin(9600);// //устанавливаем Serial порт МП3 плейера если вывод в монитор TX(D0) и RX(D1)не нужен mp3_set_serial (Serial);//инициализируем Serial порт МП3 плейера /* mySoftwareSerial.begin(9600);//инициализируем програмный Serial порт mp3_set_serial (mySoftwareSerial);// указываем програмный порт для МП3 плейера (см. 8) //инициализируем Serial с скоростью 115200, если вывод в монитор TX(D0) RX(D1) необходим Serial.begin(115200); */ delay (100);//Между двумя командами необходимо делать задержку 100 миллисекунд, в противном случае некоторые команды могут работать не стабильно. mp3_set_volume (25);// устанвливаем громкость 25 delay (100); mp3_play (1); // Проигрываем "mp3/0001.mp3"(0001_get started!.mp3) delay (100); //------------------ // Volume=EEPROM.read(0); myOLED.begin(); // выводим привествие после включения перед наливом myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Ye? yfxfkb!"), CENTER, 50);// Ну, начали! myOLED.update(); // oled_menu(0); strip.begin(); for (int i = 0; i < 5; i++) { pinMode(Optics[i], INPUT); } ServoParking(); } /*//--------------- // выводим привествие после включения перед наливом myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Ye? yfxfkb!"), CENTER, 50);// Ну, начали! myOLED.update(); // и озвучиваем mp3_set_volume (28);// устанвливаем громкость 28 (0_30) delay (100); mp3_play (1); // Проигрываем "mp3/0001.mp3"(0001_get started!.mp3) mp3_stop (1); // остановить воспроизведение mp3_set_volume (20);// устанвливаем громкость 20 (0_30) // delay (2000); //ждем 2 секунды //---------------------------- */ void loop() { currentTime = millis(); if (currentTime >= (loopTime + 5)) { // проверяем каждые 5мс // int val = analogRead(0); // считываем значение // Serial.println(val); encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера if ((!encoder_A) && (encoder_A_prev)) { // если состояние изменилось с положительного к нулю //Вращение влево if (encoder_B) { if (MenuFlag == 0) { (Menu <= 0 ) ? Menu = 2 : Menu--; // Перемещение курсора по главному меню назад oled_menu(Menu); } else if (MenuFlag == 1) { (Drink <= 2 ) ? Drink = max_Drink : Drink--; // Уменьшаем кол-во милилитров в рюмку oled_auto(Drink); } else if (MenuFlag == 2) { (DrinkCount >= max_DrinkCount ) ? DrinkCount = 1 : DrinkCount++; // Влево увечичиваем рюмки для ручного режима oled_manual(DrinkCount, Drink); } //Вращение вправо } else { if (MenuFlag == 0) { (Menu >= 2 ) ? Menu = 0 : Menu++; // Перемещение курсора по главному меню вперед. oled_menu(Menu); } else if (MenuFlag == 1) { (Drink >= max_Drink ) ? Drink = 2 : Drink++; oled_auto(Drink); } else if (MenuFlag == 2) { (Drink >= max_Drink ) ? Drink = 2 : Drink++; oled_manual(DrinkCount, Drink); } } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла int encoder_sw = digitalRead(pin_SW); if (encoder_sw == 0 && encoder_sw != encoder_sw_prew) { // Нажата кнопка int pause_sw = 0; boolean promivka = false; while (digitalRead(pin_SW) == 0) { // Держим кнопку. Считаем сколько времени прошло... delay(100); pause_sw++; if (pause_sw > 20 && Menu != 2 ) break; if (pause_sw > 20 && Menu == 2 && promivka == false) { // Если пункт меню промывка и держим кнопку больше 2 секунд. promivka = true; pump_enable(); // Включаем насос myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("G H J V S D R F"), CENTER, 15);//П Р О М Ы В К А myOLED.print(F(". . ."), CENTER, 45); myOLED.update(); } } //После отпускания кнопки , обрабатываем if (promivka == true) { //Отпустили кнопку. Если включена промывка, выключаем насос и возвращаемся в главное меню promivka = false; pump_disable() ; //Выключаем насос oled_menu(2); } else { //Обработка всех нажатий кнопки if (Menu == 0 && MenuFlag == 0 && pause_sw < 10) { //Нажатие кнопки меню авто MenuFlag = 1; oled_auto(Drink); } else if (MenuFlag == 1 && pause_sw > 20) { //Выход из меню авто в главное MenuFlag = 0; oled_menu(0); } else if (MenuFlag == 1 ) { //Начинается автоматический разлив Serial.println("Начало автоматического разлива"); oled_naliv(MenuFlag); // Выводим на экран наливаем ... byte drink_count = 0; for (int y = 0; y < max_DrinkCount; y++) { if (analogRead(Optics[y]) > 1000 ) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); drink_count++; } } if (drink_count > 0) { oled_nalito(MenuFlag, drink_count ); ServoParking(); delay(1000); Tost(); CvetoMuzik(); oled_auto(Drink); } else { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("YTN H>VJR !"), CENTER, 25);//НЕТ РЮМОК ! myOLED.update(); delay(2000); oled_auto(Drink); } } else if (Menu == 1 && MenuFlag == 0 && pause_sw < 10) { // Нажатие меню ручное MenuFlag = 2; oled_manual(DrinkCount, Drink); } else if (MenuFlag == 2 && pause_sw > 20) { //Выход из меню ручное в главное MenuFlag = 0; oled_menu(1); } else if (MenuFlag == 2 ) { //Начинается ручной разлив // Serial.println("Начало ручного разлива " + String(DrinkCount)); oled_naliv(MenuFlag); // Выводим на экран наливаем ... for (int y = 0; y < DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); } oled_nalito(MenuFlag, DrinkCount ); ServoParking(); Tost(); CvetoMuzik(); oled_manual(DrinkCount, Drink); } } } if (currentTime >= (ledTime + 300)) { //Опрашиваем оптопары ... Если рюмка поставлена , светодиод светится синим, нет ничего - не светится for (int i = 0; i < max_DrinkCount; i++) { int val = analogRead(Optics[i]); // считываем значение Serial.println(val); if (val > 1000) { strip.setPixelColor(i, strip.Color(0, 0, 255)); } else { strip.setPixelColor(i, strip.Color(0, 0, 0)); } // delay(20); } strip.show(); ledTime = currentTime; } encoder_sw_prew = encoder_sw; loopTime = currentTime; } }
Скетч использует 16430 байт (53%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1419 байт (69%) динамической памяти, оставляя 629 байт для локальных переменных. Максимум: 2048 байт.
Может кто в железе проверит?
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:55
#106
Forthomo
Offline
Зарегистрирован: 10.04.2019
atom23rus пишет:
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Не видел такого в скетче
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:55
#107
stpavel
Offline
Зарегистрирован: 09.10.2018
atom23rus пишет:
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Если речь о моем скетче то калибровка в процедуре pump_timer
delay(map(Drink, 2, 50, 300, 4000));
Здесь задается соотношение милилитров и задержки.
Т.е. в процедуру передается количество наливаемых милилитров , и с помощью команды map, пропорционально переноситься значение из милилитров в требуемую задержку.
Если устраивает диапазон от 2 до 50 мл, меняй значения 300 ( подразумевает 2 мл. ) и 4000 ( 50 мл) , остальное расчитается само .
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:56
#108
atom23rus
Offline
Зарегистрирован: 06.08.2019
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 12:59
#109
atom23rus
Offline
Зарегистрирован: 06.08.2019
да,про твой.спс. Задержка в милисекундах?
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 13:01
#110
stpavel
Offline
Зарегистрирован: 09.10.2018
atom23rus пишет:
да,про твой.спс. Задержка в милисекундах?
конечно.
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 13:03
#111
Forthomo
Offline
Зарегистрирован: 10.04.2019
void pump_timer(byte Drink) { digitalWrite(PIN_PUMP, 1); delay(map(Drink, 10, 50, 1100, 5550)); digitalWrite(PIN_PUMP, 0); }
У меня так 10 мЛ — 1,1сек (1100 милисекунд), 50 мл- 5500 милисекунд.
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 13:09
#112
Forthomo
Offline
Зарегистрирован: 10.04.2019
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 13:55
#113
atom23rus
Offline
Зарегистрирован: 06.08.2019
да я бы и с китая заказал,просто мне срочно нужен был
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 14:43
#114
Forthomo
Offline
Зарегистрирован: 10.04.2019
stpavel, какие датчики используешь что у тебя на входах порог val > 1000?
Уменя вот так:
A0 70,8 405,8
A1 51 324,4
A2 83 528,8
A3 131 652
A6 281 933,2
Итого: val > 300
схема датчика на второй странице
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 16:12
#115
stpavel
Offline
Зарегистрирован: 09.10.2018
Forthomo пишет:
stpavel, какие датчики используешь что у тебя на входах порог val > 1000?
Уменя вот так:
A0 70,8 405,8
A1 51 324,4
A2 83 528,8
A3 131 652
A6 281 933,2
Итого: val > 300
схема датчика на второй странице
Использую вот такие датчики https://ru.aliexpress.com/item/4000036567119.html?spm=a2g0s.9042311.0.0.528c33ed9tRBaQ
На каждом установлен инвертирующий триггер Шмидта 74HC14D, который поидее должен хорошо подавлять дребезг. У меня нет обычных TCRT5000 что бы проверить как будет работать без этой микросхемы, но думаю с ней однозначно будет лучше.
Чуть поменял код, вынес настройки для калибровки насосика в самый верх.
//----- Минимальные и максимальные значения наполняемой жидкости и задержки для наполнения. const byte min_Drink = 2; // Минимум в рюмку - 2 мл. const byte max_Drink = 50; // Максимум в рюмку - 50 мл. // Калибровка работы насосика. Значения для налива min_Drink и max_Drink соотвественно const unsigned int min_Drink_delay = 300; const unsigned int max_Drink_delay = 4000; //--------
Добавил настройку порога срабатывания оптического датчика для каждой рюмки
// Значения порога срабатывания датчика для каждой рюмки const unsigned int Optics_porog[] = {1000,1000,1000,1000,1000};
#include <OLED_I2C.h> #include <Servo.h> #include "Adafruit_NeoPixel.h" OLED myOLED(SDA, SCL, 8); //Подключение экрана А4, А5 extern uint8_t MegaNumbers[]; extern uint8_t RusFont[]; extern uint8_t SmallFont[]; unsigned long currentTime; unsigned long loopTime; unsigned long ledTime; // Переменные для энкодера ----------- const int pin_A = 2; // Подключение вывода A (CLK) энкодера const int pin_B = 3; // Подключение вывода B (DT) энкодера const int pin_SW = 4; // Подключение вывода кнопки (SW) энкодера unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev = 0; unsigned char encoder_sw_prew = 1; //Массив , обозначаем подключенные оптопары по выводам . Оптопары подключены, A0,A1,A2,A3,A6 const byte Optics[] = {0, 1, 2, 3, 6}; // Значения порога срабатывания датчика для каждой рюмки const unsigned int Optics_porog[] = {1000,1000,1000,1000,1000}; //Серво const int PIN_SERVO = 9; Servo servo; //Позиция каждой рюмки const byte Rumka_pos[] = {0,40,75,105,140}; //------------------------- byte Menu = 0; byte MenuFlag = 0; // Здесь храниться уровень меню. 0 находимся в Главном меню. 1 Вошли в меню Авто, 2 вошли в Ручное управление byte Drink = 25; // По умолчанию в рюмку наливаем 20 мл. //----- Минимальные и максимальные значения наполняемой жидкости и задержки для наполнения. const byte min_Drink = 2; // Минимум в рюмку - 2 мл. const byte max_Drink = 50; // Максимум в рюмку - 50 мл. // Калибровка работы насосика. Значения для налива min_Drink и max_Drink соотвественно const unsigned int min_Drink_delay = 300; const unsigned int max_Drink_delay = 4000; //-------- byte DrinkCount = 1; //По умолчанию, для ручного режима - 1 рюмка const byte max_DrinkCount = 5; //Максимальное кол-во рюмок - 5 // Насосик const byte PIN_PUMP = 12; // Светодиоды const int PIN_LED = 5;// Сюда подключаются светодиоды const int LED_COUNT = max_DrinkCount; Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN_LED, NEO_GRB + NEO_KHZ800); //------- void pump_enable() { digitalWrite(PIN_PUMP, 1); } void pump_disable() { digitalWrite(PIN_PUMP, 0); } void pump_timer(byte Drink) { digitalWrite(PIN_PUMP, 1); delay(map(Drink, min_Drink, max_Drink, min_Drink_delay, max_Drink_delay)); digitalWrite(PIN_PUMP, 0); } void oled_menu(int Menu) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Y F K B D F N J H"), CENTER, 0); myOLED.print(F("F D N J"), CENTER, 15); myOLED.print(F("H E X Y J Q "), CENTER, 30); myOLED.print(F("G H J V S D R F"), CENTER, 45); myOLED.setFont(SmallFont); myOLED.print(F(">"), LEFT, (Menu * 15) + 15); myOLED.print(F("<"), RIGHT, (Menu * 15) + 15); myOLED.update(); } // выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение void DrinkInfo(byte pos) { if (Drink < 15) { myOLED.print(F("YB J XTV"), CENTER, pos); } else if (Drink < 28) { myOLED.print(F("GJ XENM - XENM"), CENTER, pos); } else if (Drink < 38) { myOLED.print(F("D CFVSQ HFP"), CENTER, pos); } else if (Drink < 48) { myOLED.print(F("GJ GJKYJQ"), CENTER, pos); } else { myOLED.print(F("LJ RHFTD"), CENTER, pos); } } void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("DSGMTV"), CENTER, 20); //Выпьем // Рандом - 1 switch (random(11)) { case 0: myOLED.print(F("PF LHEPTQ!"), CENTER, 40); //За друзей break; case 1: myOLED.print(F("PF VBKS{ LFV!"), CENTER, 40); //За милых дам break; case 2: myOLED.print(F("PF PLJHJDMT!"), CENTER, 40); //За здоровье break; case 3: myOLED.print(F("PF ELFXE!"), CENTER, 40); //За удачу break; case 4: myOLED.print(F("PF VBH DJ DCTV VBHT!"), CENTER, 40); //За мир во всем мире break; case 5: myOLED.print(F("PF NT{ RNJ D VJHT!"), CENTER, 40); //За тех кто в море break; case 6: myOLED.print(F("PF K><JDM !"), CENTER, 40); //За любовь ! break; case 7: myOLED.print(F("PF RHFCJNE !"), CENTER, 40); //За красоту ! break; case 8: myOLED.print(F("PF DTPTYBT !"), CENTER, 40); //За везение ! break; case 9: myOLED.print(F("PF HJLBYE !"), CENTER, 40); //За родину ! break; case 10: myOLED.print(F("PF YFC C DFVB"), CENTER, 38); //За нас с вами myOLED.print(F("B {HTY C YBVB !"), CENTER, 55); //И хрен с ними break; } myOLED.update(); } // Меню Авто режим void oled_auto(int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("F D N J"), CENTER, 0); myOLED.print(F("VK "), RIGHT, 27); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.setFont(MegaNumbers); myOLED.print(String(Drink), CENTER, 13); myOLED.update(); } // Меню Ручной режим void oled_manual(int DrinkCount, int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("H E X Y J Q"), CENTER, 0); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.print(F("H>V"), 24, 27); myOLED.print(F("VK "), RIGHT, 27); myOLED.setFont(MegaNumbers); myOLED.print(String(DrinkCount), LEFT, 13); myOLED.print(String(Drink), (Drink < 10) ? 80 : 57, 13); myOLED.update(); } void oled_naliv(int MenuFlag) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B D F > "), CENTER, 27); DrinkInfo(47); myOLED.update(); } void oled_nalito(int MenuFlag, int Nalito) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B N J"), CENTER, 20); if (Nalito == 1) { myOLED.print(F("H > V R F"), CENTER, 55); } else if (Nalito <= 4 ) { myOLED.print(F("H > V R B"), CENTER, 55); } else { myOLED.print(F("H > V J R"), CENTER, 55); } myOLED.setFont(SmallFont); myOLED.print(String(Nalito), CENTER, 36); myOLED.update(); } void ServoNaliv(byte rumka) { servo.attach(PIN_SERVO); for (int pos = servo.read(); pos <= Rumka_pos[rumka]; pos += 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию } servo.detach(); } void ServoParking () { //Serial.println(servo.read()); servo.attach(PIN_SERVO); for (int pos = servo.read(); pos >= 0; pos -= 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(10); // ждем 15 миллисекунд, пока ротор сервы выйдет в заданную позицию } servo.detach(); } void CvetoMuzik() { for (int i = 0; i <= 7; i++) { for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 255, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 0, 255)); strip.show(); delay(30); } } } void setup() { //Serial.begin(9600); // servo.attach(PIN_SERVO); pinMode(pin_SW, INPUT); // устанавливаем pin pin_SW как вход digitalWrite(pin_SW, HIGH); // Поддяжка вывода к 1 pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); pinMode(PIN_PUMP, OUTPUT); digitalWrite(PIN_PUMP, 0); currentTime = millis(); loopTime = currentTime; // Volume=EEPROM.read(0); myOLED.begin(); oled_menu(0); strip.begin(); for (int i = 0; i < 5; i++) { pinMode(Optics[i], INPUT); } ServoParking(); } void loop() { currentTime = millis(); if (currentTime >= (loopTime + 5)) { // проверяем каждые 5мс // int val = analogRead(0); // считываем значение // Serial.println(val); encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера if ((!encoder_A) && (encoder_A_prev)) { // если состояние изменилось с положительного к нулю //Вращение влево if (encoder_B) { if (MenuFlag == 0) { (Menu <= 0 ) ? Menu = 2 : Menu--; // Перемещение курсора по главному меню назад oled_menu(Menu); } else if (MenuFlag == 1) { (Drink <= min_Drink ) ? Drink = max_Drink : Drink--; // Уменьшаем кол-во милилитров в рюмку oled_auto(Drink); } else if (MenuFlag == 2) { (DrinkCount >= max_DrinkCount ) ? DrinkCount = 1 : DrinkCount++; // Влево увечичиваем рюмки для ручного режима oled_manual(DrinkCount, Drink); } //Вращение вправо } else { if (MenuFlag == 0) { (Menu >= 2 ) ? Menu = 0 : Menu++; // Перемещение курсора по главному меню вперед. oled_menu(Menu); } else if (MenuFlag == 1) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_auto(Drink); } else if (MenuFlag == 2) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_manual(DrinkCount, Drink); } } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла int encoder_sw = digitalRead(pin_SW); if (encoder_sw == 0 && encoder_sw != encoder_sw_prew) { // Нажата кнопка int pause_sw = 0; boolean promivka = false; while (digitalRead(pin_SW) == 0) { // Держим кнопку. Считаем сколько времени прошло... delay(100); pause_sw++; if (pause_sw > 20 && Menu != 2 ) break; if (pause_sw > 20 && Menu == 2 && promivka == false) { // Если пункт меню промывка и держим кнопку больше 2 секунд. promivka = true; pump_enable(); // Включаем насос myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("G H J V S D R F"), CENTER, 15); myOLED.print(F(". . ."), CENTER, 45); myOLED.update(); } } //После отпускания кнопки , обрабатываем if (promivka == true) { //Отпустили кнопку. Если включена промывка, выключаем насос и возвращаемся в главное меню promivka = false; pump_disable() ; //Выключаем насос oled_menu(2); } else { //Обработка всех нажатий кнопки if (Menu == 0 && MenuFlag == 0 && pause_sw < 10) { //Нажатие кнопки меню авто MenuFlag = 1; oled_auto(Drink); } else if (MenuFlag == 1 && pause_sw > 20) { //Выход из меню авто в главное MenuFlag = 0; oled_menu(0); } else if (MenuFlag == 1 ) { //Начинается автоматический разлив Serial.println("Начало автоматического разлива"); oled_naliv(MenuFlag); // Выводим на экран наливаем ... byte drink_count = 0; for (int y = 0; y < max_DrinkCount; y++) { if (analogRead(Optics[y]) > Optics_porog[y] ) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); drink_count++; } } if (drink_count > 0) { oled_nalito(MenuFlag, drink_count ); ServoParking(); delay(1000); Tost(); CvetoMuzik(); oled_auto(Drink); } else { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("YTN H>VJR !"), CENTER, 25); myOLED.update(); delay(2000); oled_auto(Drink); } } else if (Menu == 1 && MenuFlag == 0 && pause_sw < 10) { // Нажатие меню ручное MenuFlag = 2; oled_manual(DrinkCount, Drink); } else if (MenuFlag == 2 && pause_sw > 20) { //Выход из меню ручное в главное MenuFlag = 0; oled_menu(1); } else if (MenuFlag == 2 ) { //Начинается ручной разлив // Serial.println("Начало ручного разлива " + String(DrinkCount)); oled_naliv(MenuFlag); // Выводим на экран наливаем ... for (int y = 0; y < DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); } oled_nalito(MenuFlag, DrinkCount ); ServoParking(); Tost(); CvetoMuzik(); oled_manual(DrinkCount, Drink); } } } if (currentTime >= (ledTime + 300)) { //Опрашиваем оптопары ... Если рюмка поставлена , светодиод светится синим, нет ничего - не светится for (int i = 0; i < max_DrinkCount; i++) { int val = analogRead(Optics[i]); // считываем значение Serial.println(val); if (val > Optics_porog[i]) { strip.setPixelColor(i, strip.Color(0, 0, 255)); } else { strip.setPixelColor(i, strip.Color(0, 0, 0)); } // delay(20); } strip.show(); ledTime = currentTime; } encoder_sw_prew = encoder_sw; loopTime = currentTime; } }
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 18:55
#116
Forthomo
Offline
Зарегистрирован: 10.04.2019
Теперь вообще все понятно! Вставлю пятак скетче для проверки/калибровки датчиков А0, А1, А2, А3, А6, А7. Все выводится в монитор порта.
void setup() { // Объявляем работу с последоватлеьным портом в самом начале Serial.begin(9600); // Теперь мы можем писать сообщения Serial.println ("Hello, Arduino Master"); } void loop() {// Выводим таблицу с информацией о текущих значениях портов Serial.print("Port #\t\t"); Serial.println("Value"); Serial.print("A0\t\t"); Serial.println(analogRead(A0)); Serial.print("A1\t\t"); Serial.println(analogRead(A1)); Serial.print("A2\t\t"); Serial.println(analogRead(A2)); Serial.print("A3\t\t"); Serial.println(analogRead(A3)); Serial.print("A6\t\t"); Serial.println(analogRead(A6)); Serial.print("A7\t\t"); Serial.println(analogRead(A7)); Serial.println("--------"); delay(5000); }
- Войдите на сайт для отправки комментариев
Пт, 09/08/2019 — 22:13
#117
stpavel
Offline
Зарегистрирован: 09.10.2018
- Войдите на сайт для отправки комментариев
Сб, 10/08/2019 — 14:35
#118
Forthomo
Offline
Зарегистрирован: 10.04.2019
У Афанасьева В. много поделок в стиле стимпанк, есть подробные ворклоги на технари.ру, в эту тему видел «насТРОение», на Ютубе есть.
- Войдите на сайт для отправки комментариев
Втр, 13/08/2019 — 13:31
#119
Forthomo
Offline
Зарегистрирован: 10.04.2019
atom23rus пишет:
Парни, а подскажите как откалибровать насос?
Вот простой секундомер для калибровки, насос через силоврй ключ/реле к 12 пину, вывовд в монитор порта. Считает милисекунды. Нажал кнопку секундомер запустился, насос включился, отмерил сколько надо, нажал второй раз насос отключился — в мониторе время, оч удобно.
/* StopWatch * Paul Badger 2008 * Demonstrates using millis(), pullup resistors, * making two things happen at once, printing fractions * * Physical setup: momentary switch connected to pin 4, other side connected to ground * LED with series resistor between pin 13 and ground */ #define ledPin 13 // LED connected to digital pin 13 #define buttonPin 4 // button on pin 4 #define pumpPin 12 // pump on pin 12 int value = LOW; // previous value of the LED int buttonState; // variable to store button state int lastButtonState; // variable to store last button state int blinking; // condition for blinking - timer is timing long interval = 100; // blink interval - change to suit long previousMillis = 0; // variable to store last time LED was updated long startTime ; // start time for stop watch long elapsedTime ; // elapsed time for stop watch int fractional; // variable used to store fractional part of time void setup() { Serial.begin(9600); pinMode(ledPin, OUTPUT); // sets the digital pin as output pinMode(buttonPin, INPUT); // not really necessary, pins default to INPUT anyway digitalWrite(buttonPin, HIGH); // turn on pullup resistors. Wire button so that press shorts pin to ground. } void loop() { // check for button press buttonState = digitalRead(buttonPin); // read the button state and store if (buttonState == LOW && lastButtonState == HIGH && blinking == false){ // check for a high to low transition // if true then found a new button press while clock is not running - start the clock startTime = millis(); // store the start time blinking = true; // turn on blinking while timing delay(5); // short delay to debounce switch digitalWrite(pumpPin, HIGH); //pump ON lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time } else if (buttonState == LOW && lastButtonState == HIGH && blinking == true){ // check for a high to low transition // if true then found a new button press while clock is running - stop the clock and report elapsedTime = millis() - startTime; // store elapsed time blinking = false; // turn off blinking, all done timing digitalWrite(pumpPin, LOW); // pump OFF lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time // routine to report elapsed time Serial.print( (int)(elapsedTime / 1000L)); // divide by 1000 to convert to seconds - then cast to an int to print Serial.print("."); // print decimal point // use modulo operator to get fractional part of time fractional = (int)(elapsedTime % 1000L); // pad in leading zeros - wouldn't it be nice if // Arduino language had a flag for this? :) if (fractional == 0) Serial.print("000"); // add three zero's else if (fractional < 10) // if fractional < 10 the 0 is ignored giving a wrong time, so add the zeros Serial.print("00"); // add two zeros else if (fractional < 100) Serial.print("0"); // add one zero Serial.println(fractional); // print fractional part of time } else{ lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time } // blink routine - blink the LED while timing // check to see if it's time to blink the LED; that is, the difference // between the current time and last time we blinked the LED is larger than // the interval at which we want to blink the LED. if ( (millis() - previousMillis > interval) ) { if (blinking == true){ previousMillis = millis(); // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } else{ digitalWrite(ledPin, LOW); // turn off LED when not blinking } } }
- Войдите на сайт для отправки комментариев
Втр, 13/08/2019 — 16:44
#120
atom23rus
Offline
Зарегистрирован: 06.08.2019
спасибо. на днях выложу систему как я расположил трубку!
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 12:14
#121
atom23rus
Offline
Зарегистрирован: 06.08.2019
короче,по человечески загрузить не получилось.кидаю ссылки на картинки реализации поворота наливной головки.
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 15:43
#122
den-a2rh
Offline
Зарегистрирован: 07.01.2018
Добрый день всем…. У кого есть рабочий скетч с озвучкой тостов, схема подключения и список комплектующих. Хочу тоже попробовать собрать эту чудо машину … Кто может помочь ….
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 17:51
#123
Forthomo
Offline
Зарегистрирован: 10.04.2019
atom23rus пишет:
короче,по человечески загрузить не получилось.кидаю ссылки на картинки реализации поворота наливной головки.
Нe не писающий мальчик, а так не плохо.
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 17:55
#124
Forthomo
Offline
Зарегистрирован: 10.04.2019
den-a2rh, прочитайте две последних страницы там все разъяснено. «Говорилка» пока в железе не опробована. Скетч с МП3 в 105 сообщении.
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 18:01
#125
atom23rus
Offline
Зарегистрирован: 06.08.2019
да боюсь писающего мальчика мужики не оценят
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 18:11
#126
Forthomo
Offline
Зарегистрирован: 10.04.2019
Может кто нибудь подсказать как шрифт в кейсе тост побольше сделать?
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 18:16
#127
den-a2rh
Offline
Зарегистрирован: 07.01.2018
Спасибо большое за подсказку…
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 18:42
#128
den-a2rh
Offline
Зарегистрирован: 07.01.2018
А не могли бы вы помочь со схемой подключения и списком комплектующих… Я в этом не селен… Соответственно за вознаграждение…. Моя почта [email protected] Заранее спасибо
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 21:58
#129
stpavel
Offline
Зарегистрирован: 09.10.2018
den-a2rh пишет:
А не могли бы вы помочь со схемой подключения и списком комплектующих… Я в этом не селен… Соответственно за вознаграждение…. Моя почта [email protected] Заранее спасибо
Схема подключения :
https://pikabu.ru/story/arduino_i_mp3_modul_uchim_arduino_govorit_3939974
Где купить
https://ru.aliexpress.com/item/32659645208.html?spm=a2g0o.productlist.0.0.2d3b259fcpKTyq&algo_pvid=36ea7e3b-d25c-4ec1-a354-661eba1c9a7d&algo_expid=36ea7e3b-d25c-4ec1-a354-661eba1c9a7d-0&btsid=c29baa8c-f371-4e11-aa8f-2a3b5a9c2dd9&ws_ab_test=searchweb0_0,searchweb201602_1,searchweb201603_53
Нужна еще sd карточка.
На нее записываем файлы в папку mp3 файлы 0001.mp3 , 0002.mp3 итд
Это файлы с тостами.
Библиотека https://github.com/DFRobot/DFPlayer-Mini-mp3
Последняя библиотека от DFRobot чето жрет памяти не хило. Если эта будет работать , почему бы и нет.
В коде закоментировал процедуру tost которая выводила тосты на экран, и добавил маленькую процедурку tost которая просто проигрывает рандомный тост с сд карты.
В настройках нужно поправить
//mp3 byte mp3_count=11; //Количество голосовых файлов на SD карте
Код не тестировал, не на чем. тут ничего сложного , должен работать, если не будет , поправим.
#include <OLED_I2C.h> #include <Servo.h> #include "Adafruit_NeoPixel.h" #include <SoftwareSerial.h> #include <DFPlayer_Mini_Mp3.h> OLED myOLED(SDA, SCL, 8); //Подключение экрана А4, А5 extern uint8_t MegaNumbers[]; extern uint8_t RusFont[]; extern uint8_t SmallFont[]; unsigned long currentTime; unsigned long loopTime; unsigned long ledTime; // Переменные для энкодера ----------- const int pin_A = 2; // Подключение вывода A (CLK) энкодера const int pin_B = 3; // Подключение вывода B (DT) энкодера const int pin_SW = 4; // Подключение вывода кнопки (SW) энкодера unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev = 0; unsigned char encoder_sw_prew = 1; //Массив , обозначаем подключенные оптопары по выводам . Оптопары подключены, A0,A1,A2,A3,A6 const byte Optics[] = {0, 1, 2, 3, 6}; // Значения порога срабатывания датчика для каждой рюмки const unsigned int Optics_porog[] = {1000,1000,1000,1000,1000}; //Серво const int PIN_SERVO = 9; Servo servo; //Позиция каждой рюмки ( mg995 max 250) const byte Rumka_pos[] = {0,40,75,105,140}; const byte servo_speed=10; // Скорость поворота серво, 10 - норм, 20 медленно, 30 очень медленно //------------------------- byte Menu = 0; byte MenuFlag = 0; // Здесь храниться уровень меню. 0 находимся в Главном меню. 1 Вошли в меню Авто, 2 вошли в Ручное управление byte Drink = 25; // По умолчанию в рюмку наливаем 20 мл. //----- Минимальные и максимальные значения наполняемой жидкости и задержки для наполнения. const byte min_Drink = 2; // Минимум в рюмку - 2 мл. const byte max_Drink = 50; // Максимум в рюмку - 50 мл. // Калибровка работы насосика. Значения для налива min_Drink и max_Drink соотвественно const unsigned int min_Drink_delay = 300; const unsigned int max_Drink_delay = 4000; //-------- byte DrinkCount = 1; //По умолчанию, для ручного режима - 1 рюмка const byte max_DrinkCount = 5; //Максимальное кол-во рюмок - 5 // Насосик const byte PIN_PUMP = 12; // Светодиоды const int PIN_LED = 5;// Сюда подключаются светодиоды const int LED_COUNT = max_DrinkCount; Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN_LED, NEO_GRB + NEO_KHZ800); //mp3 byte mp3_count=11; //Количество голосовых файлов на SD карте void pump_enable() { digitalWrite(PIN_PUMP, 1); } void pump_disable() { digitalWrite(PIN_PUMP, 0); } void pump_timer(byte Drink) { digitalWrite(PIN_PUMP, 1); delay(map(Drink, min_Drink, max_Drink, min_Drink_delay, max_Drink_delay)); digitalWrite(PIN_PUMP, 0); } void oled_menu(int Menu) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Y F K B D F N J H"), CENTER, 0); myOLED.print(F("F D N J"), CENTER, 15); myOLED.print(F("H E X Y J Q "), CENTER, 30); myOLED.print(F("G H J V S D R F"), CENTER, 45); myOLED.setFont(SmallFont); myOLED.print(F(">"), LEFT, (Menu * 15) + 15); myOLED.print(F("<"), RIGHT, (Menu * 15) + 15); myOLED.update(); } // выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение void DrinkInfo(byte pos) { if (Drink < 15) { myOLED.print(F("YB J XTV"), CENTER, pos); } else if (Drink < 28) { myOLED.print(F("GJ XENM - XENM"), CENTER, pos); } else if (Drink < 38) { myOLED.print(F("D CFVSQ HFP"), CENTER, pos); } else if (Drink < 48) { myOLED.print(F("GJ GJKYJQ"), CENTER, pos); } else { myOLED.print(F("LJ RHFTD"), CENTER, pos); } } /* void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("DSGMTV"), CENTER, 20); //Выпьем // Рандом - 1 switch (random(11)) { case 0: myOLED.print(F("PF LHEPTQ!"), CENTER, 40); //За друзей break; case 1: myOLED.print(F("PF VBKS{ LFV!"), CENTER, 40); //За милых дам break; case 2: myOLED.print(F("PF PLJHJDMT!"), CENTER, 40); //За здоровье break; case 3: myOLED.print(F("PF ELFXE!"), CENTER, 40); //За удачу break; case 4: myOLED.print(F("PF VBH DJ DCTV VBHT!"), CENTER, 40); //За мир во всем мире break; case 5: myOLED.print(F("PF NT{ RNJ D VJHT!"), CENTER, 40); //За тех кто в море break; case 6: myOLED.print(F("PF K><JDM !"), CENTER, 40); //За любовь ! break; case 7: myOLED.print(F("PF RHFCJNE !"), CENTER, 40); //За красоту ! break; case 8: myOLED.print(F("PF DTPTYBT !"), CENTER, 40); //За везение ! break; case 9: myOLED.print(F("PF HJLBYE !"), CENTER, 40); //За родину ! break; case 10: myOLED.print(F("PF YFC C DFVB"), CENTER, 38); //За нас с вами myOLED.print(F("B {HTY C YBVB !"), CENTER, 55); //И хрен с ними break; } myOLED.update(); } */ void Tost() { randomSeed(currentTime); mp3_play(random(mp3_count)); delay (5000); } // Меню Авто режим void oled_auto(int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("F D N J"), CENTER, 0); myOLED.print(F("VK "), RIGHT, 27); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.setFont(MegaNumbers); myOLED.print(String(Drink), CENTER, 13); myOLED.update(); } // Меню Ручной режим void oled_manual(int DrinkCount, int Drink) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("H E X Y J Q"), CENTER, 0); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.print(F("H>V"), 24, 27); myOLED.print(F("VK "), RIGHT, 27); myOLED.setFont(MegaNumbers); myOLED.print(String(DrinkCount), LEFT, 13); myOLED.print(String(Drink), (Drink < 10) ? 80 : 57, 13); myOLED.update(); } void oled_naliv(int MenuFlag) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B D F > "), CENTER, 27); DrinkInfo(47); myOLED.update(); } void oled_nalito(int MenuFlag, int Nalito) { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print((MenuFlag == 1) ? F("F D N J") : F("H E X Y J Q") , CENTER, 0); myOLED.print(F("Y F K B N J"), CENTER, 20); if (Nalito == 1) { myOLED.print(F("H > V R F"), CENTER, 55); } else if (Nalito <= 4 ) { myOLED.print(F("H > V R B"), CENTER, 55); } else { myOLED.print(F("H > V J R"), CENTER, 55); } myOLED.setFont(SmallFont); myOLED.print(String(Nalito), CENTER, 36); myOLED.update(); } void ServoNaliv(byte rumka) { servo.attach(PIN_SERVO); for (int pos = servo.read(); pos <= Rumka_pos[rumka]; pos += 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(servo_speed); // ждем , пока ротор сервы выйдет в заданную позицию } servo.detach(); } void ServoParking () { //Serial.println(servo.read()); servo.attach(PIN_SERVO); for (int pos = servo.read(); pos >= 0; pos -= 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(servo_speed); // ждем , пока ротор сервы выйдет в заданную позицию } servo.detach(); } void CvetoMuzik() { for (int i = 0; i <= 7; i++) { for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 255, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 0, 255)); strip.show(); delay(30); } } } void setup() { Serial.begin(9600); mp3_set_serial (Serial); delay(100); mp3_set_volume (25); delay(100); pinMode(pin_SW, INPUT); // устанавливаем pin pin_SW как вход digitalWrite(pin_SW, HIGH); // Поддяжка вывода к 1 pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); pinMode(PIN_PUMP, OUTPUT); digitalWrite(PIN_PUMP, 0); currentTime = millis(); loopTime = currentTime; // Volume=EEPROM.read(0); myOLED.begin(); oled_menu(0); strip.begin(); for (int i = 0; i < 5; i++) { pinMode(Optics[i], INPUT); } ServoParking(); } void loop() { currentTime = millis(); if (currentTime >= (loopTime + 5)) { // проверяем каждые 5мс // int val = analogRead(0); // считываем значение // Serial.println(val); encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера if ((!encoder_A) && (encoder_A_prev)) { // если состояние изменилось с положительного к нулю //Вращение влево if (encoder_B) { if (MenuFlag == 0) { (Menu <= 0 ) ? Menu = 2 : Menu--; // Перемещение курсора по главному меню назад oled_menu(Menu); } else if (MenuFlag == 1) { (Drink <= min_Drink ) ? Drink = max_Drink : Drink--; // Уменьшаем кол-во милилитров в рюмку oled_auto(Drink); } else if (MenuFlag == 2) { (DrinkCount >= max_DrinkCount ) ? DrinkCount = 1 : DrinkCount++; // Влево увечичиваем рюмки для ручного режима oled_manual(DrinkCount, Drink); } //Вращение вправо } else { if (MenuFlag == 0) { (Menu >= 2 ) ? Menu = 0 : Menu++; // Перемещение курсора по главному меню вперед. oled_menu(Menu); } else if (MenuFlag == 1) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_auto(Drink); } else if (MenuFlag == 2) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_manual(DrinkCount, Drink); } } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла int encoder_sw = digitalRead(pin_SW); if (encoder_sw == 0 && encoder_sw != encoder_sw_prew) { // Нажата кнопка int pause_sw = 0; boolean promivka = false; while (digitalRead(pin_SW) == 0) { // Держим кнопку. Считаем сколько времени прошло... delay(100); pause_sw++; if (pause_sw > 20 && Menu != 2 ) break; if (pause_sw > 20 && Menu == 2 && promivka == false) { // Если пункт меню промывка и держим кнопку больше 2 секунд. promivka = true; pump_enable(); // Включаем насос myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("G H J V S D R F"), CENTER, 15); myOLED.print(F(". . ."), CENTER, 45); myOLED.update(); } } //После отпускания кнопки , обрабатываем if (promivka == true) { //Отпустили кнопку. Если включена промывка, выключаем насос и возвращаемся в главное меню promivka = false; pump_disable() ; //Выключаем насос oled_menu(2); } else { //Обработка всех нажатий кнопки if (Menu == 0 && MenuFlag == 0 && pause_sw < 10) { //Нажатие кнопки меню авто MenuFlag = 1; oled_auto(Drink); } else if (MenuFlag == 1 && pause_sw > 20) { //Выход из меню авто в главное MenuFlag = 0; oled_menu(0); } else if (MenuFlag == 1 ) { //Начинается автоматический разлив // Serial.println("Начало автоматического разлива"); oled_naliv(MenuFlag); // Выводим на экран наливаем ... byte drink_count = 0; for (int y = 0; y < max_DrinkCount; y++) { if (analogRead(Optics[y]) > Optics_porog[y] ) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); drink_count++; } } if (drink_count > 0) { oled_nalito(MenuFlag, drink_count ); ServoParking(); delay(1000); Tost(); CvetoMuzik(); oled_auto(Drink); } else { myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("YTN H>VJR !"), CENTER, 25); myOLED.update(); delay(2000); oled_auto(Drink); } } else if (Menu == 1 && MenuFlag == 0 && pause_sw < 10) { // Нажатие меню ручное MenuFlag = 2; oled_manual(DrinkCount, Drink); } else if (MenuFlag == 2 && pause_sw > 20) { //Выход из меню ручное в главное MenuFlag = 0; oled_menu(1); } else if (MenuFlag == 2 ) { //Начинается ручной разлив // Serial.println("Начало ручного разлива " + String(DrinkCount)); oled_naliv(MenuFlag); // Выводим на экран наливаем ... for (int y = 0; y < DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); } oled_nalito(MenuFlag, DrinkCount ); ServoParking(); Tost(); CvetoMuzik(); oled_manual(DrinkCount, Drink); } } } if (currentTime >= (ledTime + 300)) { //Опрашиваем оптопары ... Если рюмка поставлена , светодиод светится синим, нет ничего - не светится for (int i = 0; i < max_DrinkCount; i++) { int val = analogRead(Optics[i]); // считываем значение // Serial.println("A"+String(Optics[i])+"="+val); if (val > Optics_porog[i]) { strip.setPixelColor(i, strip.Color(0, 0, 255)); } else { strip.setPixelColor(i, strip.Color(0, 0, 0)); } // delay(20); } strip.show(); ledTime = currentTime; } encoder_sw_prew = encoder_sw; loopTime = currentTime; } }
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 22:20
#130
den-a2rh
Offline
Зарегистрирован: 07.01.2018
Спасибо вам большое…. Буду пробовать
- Войдите на сайт для отправки комментариев
Ср, 14/08/2019 — 22:26
#131
stpavel
Offline
Зарегистрирован: 09.10.2018
Небольшая поправочка
В процедуре tost вместо
mp3_play(random(mp3_count));
должно быть
mp3_play(random(mp3_count)+1);
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 11:55
#132
Forthomo
Offline
Зарегистрирован: 10.04.2019
den-a2rh ! В скетче предоставленного stpavel все подробно описано:
-Arduino pro mini 328 5v или аналогичный;
-дисплей OLED 0,96 I2C 128×64, подключается к А4 (SDA), А5 (SCL), VCC, GND;
-энкодер РЕС11 с кнопкой или аналогичный, подключается к D2 (A), D3 (B), D3 (E), C и D (GND),подтягивающие резисторы 2шт. 10кОм к D2, D3 одним концом, другим к VCC;
-лента светодиодная пиксельная WS2812B 5V используется 5 светодиодов, подключается к D5 (Din), GND (GND), +5V и GND к внешнему источнику питания;
-серва (я использую SG90), подключается D9 (желтый), VCC (красный), GND (коричневый);
-насос (386 6-12V, нормально работает от 5 вольт, потребление 150мА), через силовой ключ или реле,
Силовой ключ (5 А; 24 В) на полевом транзисторе (IRF520 MOSFET) для Arduino
подключается к D12 (in), GND и к +5V и GND к внешнему источнику питания ;
-оптодатчики ( см. схему 1) 5 шт, подключаются к аналоговым входам А0, А1,А2,А3,А6 и VCC, GND
соответственно, для датчиков можно использовать пару ИК светодиод + ИК фототранзистор с одинаковоу длинной волны, резистор для светодиода подбирается в зависимости от тока 470Ом, резистор фототранзистора 10кОм, или купить готовую как на рисунке ;
-организация питания: литий 18680 8800ммА (Реально 3300мА), с зарядником ТР4056, и повышающим регулируемым модулем (Преобразователь DC-DC MT3608) настроен на 5 вольт, выход модуля . Если лента и насос запитывается от 12В, то эти 12в подаются на пин RAW Ардуины.
*- DFPlayer mini (MP3-TF-16P) подключается:
VCC DFP (1) к 5v внешнего источника питания,GND DFP (7) c GND Arduino и внешнему источнику питания,RX DFP (2)c TX Arduino (D0) через резистор 1кОм, TX DFP (3) c RX Arduino (D1) через резистор 1кОм, SPK_1 DFP(6) и SPK_2 DFP(8) к динамику.
Рекомендую вам самому попробовать начертить схему наливатора в SPlan70, представить сюда, а результат обсудим.
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 11:57
#133
den-a2rh
Offline
Зарегистрирован: 07.01.2018
Спасибо большое…. Всё доступно обьяснили… Буду пробовать
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 12:10
#134
Forthomo
Offline
Зарегистрирован: 10.04.2019
den-a2rh пишет:
Спасибо большое…. Всё доступно обьяснили… Буду пробовать
а плейер есть?
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 12:21
#135
den-a2rh
Offline
Зарегистрирован: 07.01.2018
На днях должен прийти с алиэкспресс… Ещё не все комплектующие пришли
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 15:06
#136
Forthomo
Offline
Зарегистрирован: 10.04.2019
den-a2rh, отправил вам на почту нарезку тостов, если кому еще понадобиться, почта моя [email protected] пишите.
- Войдите на сайт для отправки комментариев
Чт, 15/08/2019 — 15:43
#137
den-a2rh
Offline
Зарегистрирован: 07.01.2018
Спасибо большое за нарезку тостов
- Войдите на сайт для отправки комментариев
Пт, 16/08/2019 — 09:57
#138
Forthomo
Offline
Зарегистрирован: 10.04.2019
Вот такая ерунда происходит:
// задаю на самом деле так должно быть const byte Rumka_pos[] = {3,50,98,145,179}; // 12 - 48 - 90 - 135 - 174 (8 - 49 - 90 -132 - 173 - по чертежам) // 36 32 45 29 41 41 41 41
серва самая дешевая. У кого какие мысли?
- Войдите на сайт для отправки комментариев
Пт, 16/08/2019 — 12:21
#139
Forthomo
Offline
Зарегистрирован: 10.04.2019
Поправил скетч для калибровки насоса
#define ledPin 13 // LED connected to digital pin 13 #define buttonPin 4 // button on pin 4 #define pumpPin 12 // pump on pin 12 int value = LOW; // previous value of the LED int buttonState; // variable to store button state int lastButtonState; // variable to store last button state int blinking; // condition for blinking - timer is timing long interval = 100; // blink interval - change to suit long previousMillis = 0; // variable to store last time LED was updated long startTime ; // start time for stop watch long elapsedTime ; // elapsed time for stop watch int fractional; // variable used to store fractional part of time void setup() { Serial.begin(9600); pinMode(ledPin, OUTPUT); // sets the digital pin as output pinMode(pumpPin, OUTPUT); pinMode(buttonPin, INPUT); // not really necessary, pins default to INPUT anyway digitalWrite(buttonPin, 1); // turn on pullup resistors. Wire button so that press shorts pin to ground. } void loop() { // check for button press buttonState = digitalRead(buttonPin); // read the button state and store if (buttonState == LOW && lastButtonState == HIGH && blinking == false){ // check for a high to low transition // if true then found a new button press while clock is not running - start the clock startTime = millis(); // store the start time blinking = true; // turn on blinking while timing delay(5); // short delay to debounce switch digitalWrite(pumpPin, 1); //pump ON lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time } else if (buttonState == LOW && lastButtonState == HIGH && blinking == true){ // check for a high to low transition // if true then found a new button press while clock is running - stop the clock and report elapsedTime = millis() - startTime; // store elapsed time blinking = false; // turn off blinking, all done timing digitalWrite(pumpPin, 0); // pump OFF lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time // routine to report elapsed time Serial.print( (int)(elapsedTime / 1000L)); // divide by 1000 to convert to seconds - then cast to an int to print Serial.print("."); // print decimal point // use modulo operator to get fractional part of time fractional = (int)(elapsedTime % 1000L); // pad in leading zeros - wouldn't it be nice if // Arduino language had a flag for this? :) if (fractional == 0) Serial.print("000"); // add three zero's else if (fractional < 10) // if fractional < 10 the 0 is ignored giving a wrong time, so add the zeros Serial.print("00"); // add two zeros else if (fractional < 100) Serial.print("0"); // add one zero Serial.println(fractional); // print fractional part of time } else{ lastButtonState = buttonState; // store buttonState in lastButtonState, to compare next time } // blink routine - blink the LED while timing // check to see if it's time to blink the LED; that is, the difference // between the current time and last time we blinked the LED is larger than // the interval at which we want to blink the LED. if ( (millis() - previousMillis > interval) ) { if (blinking == true){ previousMillis = millis(); // remember the last time we blinked the LED // if the LED is off turn it on and vice-versa. if (value == LOW) value = HIGH; else value = LOW; digitalWrite(ledPin, value); } else{ digitalWrite(ledPin, LOW); // turn off LED when not blinking } } }
- Войдите на сайт для отправки комментариев
Сб, 17/08/2019 — 11:02
#140
RW3
Offline
Зарегистрирован: 07.08.2019
- Войдите на сайт для отправки комментариев
Сб, 17/08/2019 — 20:54
#141
Forthomo
Offline
Зарегистрирован: 10.04.2019
Коллеги есть предложение использовать LCD 1602 I2C, на OLED шрифт мелкий, а «дедушка старенький, глазки слабенькие». Русский шрифт есть, вчера пытал.
- Войдите на сайт для отправки комментариев
Вс, 18/08/2019 — 20:03
#142
stpavel
Offline
Зарегистрирован: 09.10.2018
Да, тоже давно об этом думал. Ломать глаза на мизерном олед дисплейчике как то не айс
Заказал сегодня , жду когда придет, буду переделывать под него.
Вобще много идей , как должен будет выглядить мой будущий наливатор. Идею с поворачивающимся кранчиком отбросил, не нравиться мне она. Будет вращаться стол. Обязательно будет сосуд сверху, в который будет предварительно заливаться алкоголь. Никаких там трубочек торчащих и засунутых в бутылку. Вдохновил меня этот видос, который я выкладывал несколько сообщений назад.
- Войдите на сайт для отправки комментариев
Пнд, 19/08/2019 — 17:33
#143
Forthomo
Offline
Зарегистрирован: 10.04.2019
stpavel пишет:
Да, тоже давно об этом думал. Ломать глаза на мизерном олед дисплейчике как то не айс
Помоги менюху написать для LCD1602 заготовку прилагаю , блок ТОСТ еще не готов.
#include <LCD_1602_RUS.h> #include <Servo.h> #include "Adafruit_NeoPixel.h" #include <SoftwareSerial.h>//добавляем библиотеки #include <DFPlayer_Mini_Mp3.h>//добавляем библиотеку МП3 плейера LCD_1602_RUS lcd(0x27, 16, 2); //Подключение экрана А4-SDA-зеленый, А5-SCL-желтый unsigned long currentTime; unsigned long loopTime; unsigned long ledTime; // Переменные для энкодера ----------- const int pin_A = 2; // Подключение вывода A (CLK) энкодера const int pin_B = 3; // Подключение вывода B (DT) энкодера const int pin_SW = 4; // Подключение вывода кнопки (SW) энкодера unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev = 0; unsigned char encoder_sw_prew = 1; //Массив , обозначаем подключенные оптопары по выводам . Оптопары подключены, A0,A1,A2,A3,A6 const byte Optics[] = {0, 1, 2, 3, 6}; // Значения порога срабатывания датчика для каждой рюмки const unsigned int Optics_porog[] = {100,200,200,200,100}; //Серво const int PIN_SERVO = 9; Servo servo; //Позиция каждой рюмки const byte Rumka_pos[] = {3,50,98,145,179}; //12 - 48 - 90 - 135 - 174 const byte servo_speed=20; // Скорость поворота серво, 10 - норм, 20 медленно, 30 очень медленно byte Menu = 0; byte MenuFlag = 0; // Здесь храниться уровень меню. 0 находимся в Главном меню. 1 Вошли в меню Авто, 2 вошли в Ручное управление byte Drink = 25; // По умолчанию в рюмку наливаем 20 мл. //----- Минимальные и максимальные значения наполняемой жидкости и задержки для наполнения. const byte min_Drink = 2; // Минимум в рюмку - 2 мл. const byte max_Drink = 50; // Максимум в рюмку - 50 мл. // Калибровка работы насосика. Значения для налива min_Drink и max_Drink соотвественно const unsigned int min_Drink_delay = 222; const unsigned int max_Drink_delay = 5500; //-------- byte DrinkCount = 1; //По умолчанию, для ручного режима - 1 рюмка const byte max_DrinkCount = 5; //Максимальное кол-во рюмок - 5 // Насосик const byte PIN_PUMP = 12; // Светодиоды const int PIN_LED = 5;// Сюда подключаются светодиоды const int LED_COUNT = max_DrinkCount; Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, PIN_LED, NEO_GRB + NEO_KHZ800); //------- void pump_enable() { digitalWrite(PIN_PUMP, 1); //вкл реле } void pump_disable() { digitalWrite(PIN_PUMP, 0); //выкл реле } void pump_timer(byte Drink) { digitalWrite(PIN_PUMP, 1); //вкл реле delay(map(Drink, min_Drink, max_Drink, min_Drink_delay, max_Drink_delay)); digitalWrite(PIN_PUMP, 0); //выкл реле } void oled_menu(int Menu) { lcd.setCursor(3, 0); lcd.print("HАЛИВАТОР"); lcd.setCursor(2, 0); lcd.print("< АВТО >"); //lcd.print("< РУЧНОЙ >"); //lcd.print("< ПРОМЫВКА >"); } // выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение void DrinkInfo(byte pos) { lcd.setCursor(0, 0); lcd.print("HАЛИТЬ ПО"); lcd.setCursor(11, 0); lcd.print(Drink); lcd.setCursor(14, 0); lcd.print("мЛ"); if (Drink < 15) { lcd.setCursor(5, 1); lcd.print("НИ О ЧЕМ"); } else if (Drink < 28) { lcd.setCursor(2, 1); lcd.print("ПО ЧУТЬ - ЧУТЬ"); } else if (Drink < 38) { lcd.setCursor(2, 1); lcd.print("В САМЫЙ РАЗ"); } else if (Drink < 48) { lcd.setCursor(3, 1); lcd.print("ПО ПОЛНОЙ"); } else { lcd.setCursor(4, 1); lcd.print("ДО КРАЕВ"); } } /* void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("DSGMTV"), CENTER, 20); //Выпьем // Рандом - 1 switch (random(11)) { case 0: myOLED.print(F("PF LHEPTQ!"), CENTER, 40); //За друзей break; case 1: myOLED.print(F("PF VBKS{ LFV!"), CENTER, 40); //За милых дам break; case 2: myOLED.print(F("PF PLJHJDMT!"), CENTER, 40); //За здоровье break; case 3: myOLED.print(F("PF ELFXE!"), CENTER, 40); //За удачу break; case 4: myOLED.print(F("PF VBH DJ DCTV VBHT!"), CENTER, 40); //За мир во всем мире break; case 5: myOLED.print(F("PF NT{ RNJ D VJHT!"), CENTER, 40); //За тех кто в море break; case 6: myOLED.print(F("PF K><JDM !"), CENTER, 40); //За любовь ! break; case 7: myOLED.print(F("PF RHFCJNE !"), CENTER, 40); //За красоту ! break; case 8: myOLED.print(F("PF DTPTYBT !"), CENTER, 40); //За везение ! break; case 9: myOLED.print(F("PF HJLBYE !"), CENTER, 40); //За родину ! break; case 10: myOLED.print(F("PF YFC C DFVB"), CENTER, 38); //За нас с вами myOLED.print(F("B {HTY C YBVB !"), CENTER, 55); //И хрен с ними break; } myOLED.update(); } */ /* void Tost() { randomSeed(currentTime); myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("YE?"), CENTER, 20); //НУ, Рандом - 1 switch (random(18)) { // 0...17 case 0: myOLED.print(F("PF DCNHTXE!"), CENTER, 40); //ЗА ВСТРЕЧУ! mp3_play (2); // Проигрываем "mp3/0002.mp3" delay(100); mp3_stop(); break; case 1: myOLED.print(F("PF RHFCJNE!"), CENTER, 40); //ЗА КРАСОТУ! mp3_play (3); // Проигрываем "mp3/0003.mp3" delay(100); mp3_stop(); break; case 2: myOLED.print(F("PF LHE;,E!"), CENTER, 40); //ЗА ДРУЖБУ! mp3_play (4); // Проигрываем "mp3/0004.mp3" delay(100); mp3_stop(); break; case 4: myOLED.print(F("PF ,HFNCNDJ!"), CENTER, 40); //ЗА БРАТСТВО! mp3_play (5); // Проигрываем "mp3/0005.mp3" delay(100); mp3_stop(); break; case 5: myOLED.print(F("PF"), CENTER, 38); //за myOLED.print(F("CGHFDTLKBDJCNM!"), CENTER, 55); //СПРАВЕДЛИВОСТЬ! mp3_play (6); // Проигрываем "mp3/0006.mp3" delay(100); mp3_stop(); break; case 6: myOLED.print(F("PF HS,FKRE!"), CENTER, 40); //ЗА РЫБАЛКУ! mp3_play (7); // Проигрываем "mp3/0007.mp3" delay(100); mp3_stop(); break; case 7: myOLED.print(F("PF BCRECCNDJ!"), CENTER, 40); //ЗА ИСКУССТВО! mp3_play (8); // Проигрываем "mp3/0008.mp3" delay(100); mp3_stop(); break; case 8: myOLED.print(F("PF HFPEV!"), CENTER, 40); //ЗА РАЗУМ! mp3_play (9); // Проигрываем "mp3/0009.mp3" delay(100); mp3_stop(); break; case 9: myOLED.print(F("PF BCNBYYS["), CENTER, 38); //ЗА ИСТИННЫХ myOLED.print(F(";tyoby!"), CENTER, 55); //ЖЕНЩИН! mp3_play (10); // Проигрываем "mp3/0010.mp3" delay(100); mp3_stop(); break; case 10: myOLED.print(F("PF GJYBVFYBT!"), CENTER, 40); //ЗА ПОНИМАНИЕ! mp3_play (11); // Проигрываем "mp3/0011.mp3" delay(100); mp3_stop(); break; case 11: myOLED.print(F("PF TLBYTYBT!"), CENTER, 40); //ЗА ЕДИНЕНИЕ! mp3_play (13); // Проигрываем "mp3/0013.mp3" delay(100); mp3_stop(); break; case 12: myOLED.print(F("PF GJ,TLE!"), CENTER, 40); //ЗА ПОБЕДУ! mp3_play (16); // Проигрываем "mp3/0016.mp3" delay(100); mp3_stop(); break; case 13: myOLED.print(F("PF HJLBYE!"), CENTER, 40); //ЗА РОДИНУ! mp3_play (21); // Проигрываем "mp3/0021.mp3" delay(100); mp3_stop(); break; case 14: myOLED.print(F("XNJ, UJKJDF"), CENTER, 38); //ЧТОБ ГОЛОВА myOLED.print(F("YT NHTOFKF!"), CENTER, 55); //НЕ ТРЕЩАЛА! mp3_play (17); // Проигрываем "mp3/0017.mp3" delay(100); mp3_stop(); break; case 15: myOLED.print(F("PF CJKBLYJT"), CENTER, 38); //ЗА СОЛИДНОЕ myOLED.print(F("VE;CRJT VJKXFYBT"), CENTER, 55); //МУЖСКОЕ МОЛЧАНИЕ mp3_play (12); // Проигрываем "mp3/0012.mp3" delay(100); mp3_stop(); break; case 16: myOLED.print(F("XNJ, VJHOBKJ"), CENTER, 38); //ЧТОБ МОРЩИЛО myOLED.print(F("YFC VTYMIT!"), CENTER, 55); //НАС МЕНЬШЕ! mp3_play (18); // Проигрываем "mp3/0018.mp3" delay(100); mp3_stop(); break; case 17: myOLED.print(F("XNJ, D CNJHJYE"), CENTER, 38); //ЧТОБ В СТОРОНУ myOLED.print(F("YT DBKMYEKJ!"), CENTER, 55); //НЕ ВИЛЬНУЛО! mp3_play (19); // Проигрываем "mp3/0019.mp3" delay(100); mp3_stop(); break; } myOLED.update(); } */ // Меню Авто режим void oled_auto(int Drink) { lcd.setCursor(0, 0); lcd.print("HАЛИТЬ ПО"); lcd.setCursor(11, 0); lcd.print(Drink); lcd.setCursor(14, 0); lcd.print("мЛ"); DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); } // Меню Ручной режим void oled_manual(int DrinkCount, int Drink) { lcd.setCursor(0, 0); lcd.print("HАЛИТЬ ПО"); lcd.setCursor(11, 0); lcd.print(Drink); lcd.setCursor(14, 0); lcd.print("мЛ"); DrinkInfo(57); } /* myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("H E X Y J Q"), CENTER, 0); //Р У Ч Н О Й DrinkInfo(57); // myOLED.print(DrinkInfo[map(Drink, 2, max_Drink, 0, 4)], CENTER, 57); myOLED.print(F("H>V"), 24, 27); myOLED.print(F("VK "), RIGHT, 27); myOLED.setFont(MegaNumbers); myOLED.print(String(DrinkCount), LEFT, 13); myOLED.print(String(Drink), (Drink < 10) ? 80 : 57, 13); myOLED.update(); } */ void oled_naliv(int MenuFlag) { lcd.setCursor(0, 0); lcd.print("HАЛИВАЮ ПО"); lcd.setCursor(11, 0); lcd.print(Drink); lcd.setCursor(14, 0); lcd.print("мЛ"); lcd.setCursor(3, 1); lcd.print("В"); lcd.setCursor(5, 1); lcd.print(DrinkCount); if (DrinkCount == 1) { lcd.setCursor(7, 1); lcd.print("РЮМКУ"); } else if (DrinkCount <= 4 ) { lcd.setCursor(7, 1); lcd.print("РЮМКИ"); } else { lcd.setCursor(7, 1); lcd.print("РЮМКИ"); } } void oled_nalito(int MenuFlag, int Nalito) { lcd.setCursor(0, 0); lcd.print("HАЛИТО ПО"); lcd.setCursor(11, 0); lcd.print(Drink); lcd.setCursor(14, 0); lcd.print("мЛ"); lcd.setCursor(3, 1); lcd.print("В"); lcd.setCursor(5, 1); lcd.print(Nalito); if (Nalito == 1) { lcd.setCursor(7, 1); lcd.print("РЮМКУ"); } else if (Nalito <= 4 ) { lcd.setCursor(7, 1); lcd.print("РЮМКИ"); } else { lcd.setCursor(7, 1); lcd.print("РЮМКИ"); } } void ServoNaliv(byte rumka) { servo.attach(PIN_SERVO); for (int pos = servo.read(); pos <= Rumka_pos[rumka]; pos += 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(servo_speed); // ждем , пока ротор сервы выйдет в заданную позицию } servo.detach(); } void ServoParking () { //Serial.println(servo.read()); servo.attach(PIN_SERVO); for (int pos = servo.read(); pos >= 0; pos -= 1) { // с шагом в 1 градус servo.write(pos); // даем серве команду повернуться в положение, которое задается в переменной 'pos' delay(servo_speed); // ждем , пока ротор сервы выйдет в заданную позицию } servo.detach(); } void CvetoMuzik() { for (int i = 0; i <= 7; i++) { for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 255, 0)); strip.show(); delay(30); } for (int y = 0; y < max_DrinkCount; y++) { strip.setPixelColor(y, strip.Color(0, 0, 255)); strip.show(); delay(30); } } } void setup() { Serial.begin(9600);// //устанавливаем Serial порт МП3 плейера если вывод в монитор TX(D0) и RX(D1)не нужен mp3_set_serial (Serial);//инициализируем Serial порт МП3 плейера /* при необходимости создаем програмный порт для управдения МП3 плейером, если вывод в монитор TX(D0) RX(D1) необходим SoftwareSerial mySoftwareSerial(10, 11); // RX, TX обозначаем програмный порт как mySoftwareSerial //плейер подключаем D10 D11 mySoftwareSerial.begin(9600);//инициализируем програмный Serial порт mp3_set_serial (mySoftwareSerial);// указываем програмный порт для МП3 плейера //инициализируем Serial с скоростью 115200, если вывод в монитор TX(D0) RX(D1) необходим Serial.begin(115200); */ delay (100);//Между двумя командами необходимо делать задержку 100 миллисекунд, в противном случае некоторые команды могут работать не стабильно. mp3_set_volume (25);// устанвливаем громкость 25 delay (100); mp3_play (1); // Проигрываем "mp3/0001.mp3"(0001_get started!.mp3) delay (100); // Volume=EEPROM.read(0); /* myOLED.begin(); // Инициализация дисплея // выводим привествие после включения перед наливом myOLED.clrScr(); myOLED.setFont(RusFont); myOLED.print(F("Ye? yfxfkb!"), CENTER, 50);// Ну, начали! myOLED.update(); */ lcd.init();// initialize the lcd lcd.backlight(); pinMode(pin_SW, INPUT); // устанавливаем pin pin_SW как вход digitalWrite(pin_SW, HIGH); // Поддяжка вывода к 1 pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); pinMode(PIN_PUMP, OUTPUT); digitalWrite(PIN_PUMP, 0); currentTime = millis(); loopTime = currentTime; //--------------- oled_menu(0); strip.begin(); for (int i = 0; i < 5; i++) { pinMode(Optics[i], INPUT); } ServoParking(); } void loop() { currentTime = millis(); if (currentTime >= (loopTime + 5)) { // проверяем каждые 5мс // int val = analogRead(0); // считываем значение // Serial.println(val); encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера if ((!encoder_A) && (encoder_A_prev)) { // если состояние изменилось с положительного к нулю //Вращение влево if (encoder_B) { if (MenuFlag == 0) { (Menu <= 0 ) ? Menu = 2 : Menu--; // Перемещение курсора по главному меню назад oled_menu(Menu); } else if (MenuFlag == 1) { (Drink <= min_Drink ) ? Drink = max_Drink : Drink--; // Уменьшаем кол-во милилитров в рюмку oled_auto(Drink); } else if (MenuFlag == 2) { (DrinkCount >= max_DrinkCount ) ? DrinkCount = 1 : DrinkCount++; // Влево увечичиваем рюмки для ручного режима oled_manual(DrinkCount, Drink); } //Вращение вправо } else { if (MenuFlag == 0) { (Menu >= 2 ) ? Menu = 0 : Menu++; // Перемещение курсора по главному меню вперед. oled_menu(Menu); } else if (MenuFlag == 1) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_auto(Drink); } else if (MenuFlag == 2) { (Drink >= max_Drink ) ? Drink = min_Drink : Drink++; oled_manual(DrinkCount, Drink); } } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла int encoder_sw = digitalRead(pin_SW); if (encoder_sw == 0 && encoder_sw != encoder_sw_prew) { // Нажата кнопка int pause_sw = 0; boolean promivka = false; while (digitalRead(pin_SW) == 0) { // Держим кнопку. Считаем сколько времени прошло... delay(100); pause_sw++; if (pause_sw > 20 && Menu != 2 ) break; if (pause_sw > 20 && Menu == 2 && promivka == false) { // Если пункт меню промывка и держим кнопку больше 2 секунд. promivka = true; pump_enable(); // Включаем насос lcd.setCursor(0, 0); lcd.print("П Р О М Ы В К А"); lcd.setCursor(2, 0); lcd.print(">>>>>>>>>>>>"); } } //После отпускания кнопки , обрабатываем if (promivka == true) { //Отпустили кнопку. Если включена промывка, выключаем насос и возвращаемся в главное меню promivka = false; pump_disable() ; //Выключаем насос oled_menu(2); } else { //Обработка всех нажатий кнопки if (Menu == 0 && MenuFlag == 0 && pause_sw < 10) { //Нажатие кнопки меню авто MenuFlag = 1; oled_auto(Drink); } else if (MenuFlag == 1 && pause_sw > 20) { //Выход из меню авто в главное MenuFlag = 0; oled_menu(0); } else if (MenuFlag == 1 ) { //Начинается автоматический разлив Serial.println("Начало автоматического разлива"); oled_naliv(MenuFlag); // Выводим на экран наливаем ... byte drink_count = 0; for (int y = 0; y < max_DrinkCount; y++) { if (analogRead(Optics[y]) > Optics_porog[y] ) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); drink_count++; } } if (drink_count > 0) { oled_nalito(MenuFlag, drink_count ); ServoParking(); delay(1000); // Tost(); CvetoMuzik(); oled_auto(Drink); } else { lcd.setCursor(7, 1); lcd.print("НЕТ РЮМОК!"); delay(2000); oled_auto(Drink); } } else if (Menu == 1 && MenuFlag == 0 && pause_sw < 10) { // Нажатие меню ручное MenuFlag = 2; oled_manual(DrinkCount, Drink); } else if (MenuFlag == 2 && pause_sw > 20) { //Выход из меню ручное в главное MenuFlag = 0; oled_menu(1); } else if (MenuFlag == 2 ) { //Начинается ручной разлив // Serial.println("Начало ручного разлива " + String(DrinkCount)); oled_naliv(MenuFlag); // Выводим на экран наливаем ... for (int y = 0; y < DrinkCount; y++) { strip.setPixelColor(y, strip.Color(255, 0, 0)); // Подствечиваем красным цветом strip.show(); ServoNaliv(y); // Перемещяемся к рюмке pump_timer(Drink); // Налив. strip.setPixelColor(y, strip.Color(0, 255, 0)); // Подствечиваем зеленым , налито. strip.show(); } oled_nalito(MenuFlag, DrinkCount ); ServoParking(); //Tost(); CvetoMuzik(); oled_manual(DrinkCount, Drink); } } } if (currentTime >= (ledTime + 300)) { //Опрашиваем оптопары ... Если рюмка поставлена , светодиод светится синим, нет ничего - не светится for (int i = 0; i < max_DrinkCount; i++) { int val = analogRead(Optics[i]); // считываем значение Serial.println(val); if (val > Optics_porog[i]) { strip.setPixelColor(i, strip.Color(0, 0, 255)); } else { strip.setPixelColor(i, strip.Color(0, 0, 0)); } // delay(20); } strip.show(); ledTime = currentTime; } encoder_sw_prew = encoder_sw; loopTime = currentTime; } } /* Скетч использует 13484 байт (43%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 974 байт (47%) динамической памяти, оставляя 1074 байт для локальных переменных. Максимум: 2048 байт. */
- Войдите на сайт для отправки комментариев
Втр, 20/08/2019 — 16:08
#144
stpavel
Offline
Зарегистрирован: 09.10.2018
Forthomo пишет:
Помоги менюху написать для LCD1602 заготовку прилагаю , блок ТОСТ еще не готов.
void oled_menu(byte Menu) { lcd.clear(); lcd.setCursor(3, 0); lcd.print("НАЛИВАТОР+"); lcd.setCursor(0, 1); lcd.print(F(">")); lcd.setCursor(15, 1); lcd.print(F("<")); switch (Menu) { case 0: lcd.setCursor(6, 1); lcd.print(F("АВТО")); break; case 1: lcd.setCursor(2, 1); lcd.print(F("РУЧНОЙ РЕЖИМ")); break; case 2: lcd.setCursor(4, 1); lcd.print(F("ПРОМЫВКА")); break; } }
- Войдите на сайт для отправки комментариев
Втр, 20/08/2019 — 16:36
#145
Forthomo
Offline
Зарегистрирован: 10.04.2019
Павел, спасибо! Выкладываю скетч где можно посмотреть Экраны LCD:
#include <LCD_1602_RUS.h> // https://codeload.github.com/ssilver2007/LCD_1602_RUS/zip/master LCD_1602_RUS lcd(0x27, 16, 2); int mll=25; int temp=3; void setup() { lcd.init(); // initialize the lcd lcd.backlight(); } void loop(){ // меню авто lcd.setCursor(3, 0); lcd.print("HАЛИВАТОР"); lcd.setCursor(2, 1); lcd.print("< АВТО >"); delay(3000); lcd.clear(); // меню ручной lcd.setCursor(3, 0); lcd.print("HАЛИВАТОР"); lcd.setCursor(2, 1); lcd.print("< РУЧНОЙ >"); delay(3000); lcd.clear(); // меню промывка lcd.setCursor(3, 0); lcd.print("HАЛИВАТОР"); lcd.setCursor(2, 1); lcd.print("< ПРОМЫВКА >"); delay(3000); lcd.clear(); // промывка lcd.setCursor(3, 0); lcd.print("ПРОМЫВКА"); lcd.setCursor(4, 1); lcd.print(">>>>>>"); delay(3000); lcd.clear(); // lcd.setCursor(0, 0); lcd.print("HАЛИТЬ ПО"); lcd.setCursor(10, 0); lcd.print(mll); //ПЕРЕМЕННАЯ lcd.setCursor(13, 0); lcd.print("мЛ?"); lcd.setCursor(1, 1); lcd.print("ПО ЧУТЬ - ЧУТЬ"); delay(3000); lcd.clear(); // итог //АВТОНАЛИВ lcd.setCursor(3, 0); lcd.print("АВТОНАЛИВ"); lcd.setCursor(0, 1); lcd.print("ПО"); lcd.setCursor(3, 1); lcd.print(mll); //ПЕРЕМЕННАЯ lcd.setCursor(6, 1); lcd.print("мЛ В РЮМКУ"); delay(3000); lcd.clear(); // ручной налив lcd.setCursor(0, 0); lcd.print("HАЛИВАЮ ПО"); lcd.setCursor(11, 0); lcd.print(mll); //ПЕРЕМЕННАЯ lcd.setCursor(14, 0); lcd.print("мЛ"); lcd.setCursor(3, 1); lcd.print("В"); lcd.setCursor(5, 1); lcd.print(temp);//ПЕРЕМЕННАЯ lcd.setCursor(7, 1); lcd.print("РЮМ"); lcd.setCursor(10, 1); lcd.print("КИ");//ПЕРЕМЕННАЯ "ОК" "КУ" delay(3000); lcd.clear(); // итог lcd.setCursor(0, 0); lcd.print("HАЛИТО ПО"); lcd.setCursor(11, 0); lcd.print(mll); //ПЕРЕМЕННАЯ lcd.setCursor(14, 0); lcd.print("мЛ"); lcd.setCursor(3, 1); lcd.print("В"); lcd.setCursor(5, 1); lcd.print(temp);//ПЕРЕМЕННАЯ lcd.setCursor(7, 1); lcd.print("РЮМ"); lcd.setCursor(10, 1); lcd.print("КИ");//ПЕРЕМЕННАЯ 5 - "ОК", 1 - "КУ", 2..4 -"КИ" delay(3000); lcd.clear(); // /* void Tost() { randomSeed(currentTime); Рандом - 1 switch (random(18)) { // 0...17 */ //case 0: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ВСТРЕЧУ!"); delay(3000); lcd.clear(); //case 1: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА КРАСОТУ!"); delay(3000); lcd.clear(); //case 2: lcd.setCursor(7, 0); lcd.print(L"НУ,");// lcd.setCursor(3, 1); lcd.print(L"ЗА ДРУЖБУ!"); delay(3000); lcd.clear(); //case 3: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА БРАТСТВО!"); delay(3000); lcd.clear(); //case 4: lcd.setCursor(5, 0); lcd.print(L"НУ, ЗА"); lcd.setCursor(1, 1); lcd.print(L"СПРАВЕДЛИВОСТЬ!"); delay(3000); lcd.clear(); //case 5: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РЫБАЛКУ!"); delay(3000); lcd.clear(); //case 6: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ИСКУССТВО!"); delay(3000); lcd.clear(); //case 7: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РАЗУМ!"); delay(3000); lcd.clear(); //case 8: lcd.setCursor(5, 0); lcd.print(L"НУ, ЗА"); lcd.setCursor(0, 1); lcd.print(L"ИСТИННЫХ ЖЕНЩИН!!"); delay(3000); lcd.clear(); //case 9: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ПОНИМАНИЕ!"); delay(3000); lcd.clear(); //case 10: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ЕДИНЕНИЕ!"); delay(3000); lcd.clear(); //case 11: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА ПОБЕДУ!"); delay(3000); lcd.clear(); //case 12: lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РОДИНУ!"); delay(3000); lcd.clear(); //case 13: lcd.setCursor(0, 0); lcd.print(L"НУ, ЧТОБ ГОЛОВА"); lcd.setCursor(2, 1); lcd.print(L"НЕ ТРЕЩАЛА!"); delay(3000); lcd.clear(); //case 14: lcd.setCursor(0, 0); lcd.print("НУ, ЗА СОЛИДНОЕ");//НУ, lcd.setCursor(0, 1); lcd.print("МУЖСКОЕ МОЛЧАНИЕ!"); delay(3000); lcd.clear(); //case 15: lcd.setCursor(0, 0); lcd.print(L"НУ, ЧТОБ МОРЩИЛО"); lcd.setCursor(3, 1); lcd.print(L"НАС МЕНЬШЕ"); delay(3000); lcd.clear(); //case 16: lcd.setCursor(0, 0); lcd.print(L"НУ,ЧТОБ В СТОРО-"); lcd.setCursor(0, 1); lcd.print(L"НУ НЕ ВИЛЬНУЛО!"); delay(3000); lcd.clear(); //case 17: lcd.setCursor(2, 0); lcd.print("НУ ВЫ БЛИН"); lcd.setCursor(5, 1); lcd.print("ДАЁТЕ!"); delay(3000); lcd.clear(); } /* Скетч использует 8682 байт (28%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 1171 байт (57%) динамической памяти, оставляя 877 байт для локальных переменных. Максимум: 2048 байт. */
блок с тостами
void Tost() { randomSeed(currentTime); //Рандом - 1 switch (random(18)) { // 0...17 case 0: //ЗА ВСТРЕЧУ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ВСТРЕЧУ!"); mp3_play (2); // Проигрываем "mp3/0002.mp3" delay(100); case 1: //ЗА КРАСОТУ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА КРАСОТУ!"); delay(4000); mp3_play (3); // Проигрываем "mp3/0003.mp3" delay(100); case 2: //"ЗА ДРУЖБУ!" lcd.setCursor(7, 0); lcd.print(L"НУ,");// lcd.setCursor(3, 1); lcd.print(L"ЗА ДРУЖБУ!"); mp3_play (4); // Проигрываем "mp3/0004.mp3" delay(100); case 3: //"ЗА БРАТСТВО! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА БРАТСТВО!"); mp3_play (5); // Проигрываем "mp3/0005.mp3" delay(100); case 4: //ЗА СПРАВЕДЛИВОСТЬ! lcd.setCursor(5, 0); lcd.print(L"НУ, ЗА"); lcd.setCursor(1, 1); lcd.print(L"СПРАВЕДЛИВОСТЬ!"); mp3_play (6); // Проигрываем "mp3/0006.mp3"11 delay(100); case 5: //ЗА РЫБАЛКУ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РЫБАЛКУ!"); mp3_play (7); // Проигрываем "mp3/0007.mp3" delay(100); case 6: //ЗА ИСКУССТВО! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ИСКУССТВО!"); mp3_play (8); // Проигрываем "mp3/0008.mp3" delay(100); case 7: //ЗА РАЗУМ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РАЗУМ!"); mp3_play (9); // Проигрываем "mp3/0009.mp3" delay(100); break; case 8: //ЗА ИСТИННЫХ ЖЕНЩИН! lcd.setCursor(5, 0); lcd.print(L"НУ, ЗА"); lcd.setCursor(0, 1); lcd.print(L"ИСТИННЫХ ЖЕНЩИН!!"); mp3_play (10); // Проигрываем "mp3/0010.mp3" delay(100); break; case 9: //ЗА ПОНИМАНИЕ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ПОНИМАНИЕ!"); mp3_play (11); // Проигрываем "mp3/0011.mp3" delay(100); break; case 10: //ЗА ЕДИНЕНИЕ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(2, 1); lcd.print(L"ЗА ЕДИНЕНИЕ!"); mp3_play (13); // Проигрываем "mp3/0013.mp3" delay(100); break; case 11: //ЗА ПОБЕДУ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА ПОБЕДУ!"); mp3_play (16); // Проигрываем "mp3/0016.mp3" delay(100); break; case 12: //ЗА РОДИНУ! lcd.setCursor(7, 0); lcd.print(L"НУ,"); lcd.setCursor(3, 1); lcd.print(L"ЗА РОДИНУ!"); mp3_play (21); // Проигрываем "mp3/0021.mp3" delay(100); break; case 13: //ЧТОБ ГОЛОВА НЕ ТРЕЩАЛА! lcd.setCursor(0, 0); lcd.print(L"НУ, ЧТОБ ГОЛОВА"); lcd.setCursor(2, 1); lcd.print(L"НЕ ТРЕЩАЛА!"); mp3_play (17); // Проигрываем "mp3/0017.mp3" delay(100); break; case 14: //ЗА СОЛИДНОЕ МУЖСКОЕ МОЛЧАНИЕ lcd.setCursor(0, 0); lcd.print("НУ, ЗА СОЛИДНОЕ");//НУ, lcd.setCursor(0, 1); lcd.print("МУЖСКОЕ МОЛЧАНИЕ!"); mp3_play (12); // Проигрываем "mp3/0012.mp3" delay(100); break; case 15: //ЧТОБ МОРЩИЛО НАС МЕНЬШЕ! lcd.setCursor(0, 0); lcd.print(L"НУ,ЧТОБЫ МОРЩИЛО"); lcd.setCursor(3, 1); lcd.print(L"НАС МЕНЬШЕ ЧЕМ"); mp3_play (18); // Проигрываем "mp3/0018.mp3" delay(100); break; case 16: //ЧТОБ В СТОРОНУ НЕ ВИЛЬНУЛО! lcd.setCursor(0, 0); lcd.print(L"НУ,ЧТОБ В СТОРО-"); lcd.setCursor(0, 1); lcd.print(L"НУ НЕ ВИЛЬНУЛО!"); mp3_play (19); // Проигрываем "mp3/0019.mp3" delay(100); break; case 17: //НУ ВЫ БЛИН ДАЁТЕ! lcd.setCursor(2, 0); lcd.print("НУ ВЫ БЛИН"); lcd.setCursor(5, 1); lcd.print("ДАЁТЕ!"); mp3_play (20); // Проигрываем "mp3/0020.mp3" delay(100); break; } mp3_stop(); lcd.clear(); }
- Войдите на сайт для отправки комментариев
Пнд, 26/08/2019 — 20:44
#146
RW3
Offline
Зарегистрирован: 07.08.2019
что то тема заглохла….. Может схемы хватает? кто нибудь полностью привязал скетч к железу?
- Войдите на сайт для отправки комментариев
Пнд, 26/08/2019 — 20:52
#147
stpavel
Offline
Зарегистрирован: 09.10.2018
RW3 пишет:
что то тема заглохла….. Может схемы хватает? кто нибудь полностью привязал скетч к железу?
А какие проблемы привязки скетча к железу ? Там же все расписано к какому пину что соеденять.
- Войдите на сайт для отправки комментариев
Пнд, 26/08/2019 — 21:05
#148
RW3
Offline
Зарегистрирован: 07.08.2019
это понятно, но в скетч вносятся коррективы . я пока жду комплектующие по этому ничего попробовать не могу.вот и спрашиваю может кто уже воплотил идею целиком . интересен результат
- Войдите на сайт для отправки комментариев
Втр, 27/08/2019 — 11:05
#149
aleks_raichel
Offline
Зарегистрирован: 27.08.2019
День добрый. А не перерабатывали скетч под Вашу схему?
- Войдите на сайт для отправки комментариев
Втр, 27/08/2019 — 12:38
#150
Forthomo
Offline
Зарегистрирован: 10.04.2019
RW3 пишет:
что то тема заглохла….. Может схемы хватает? кто нибудь полностью привязал скетч к железу?
Замечания по предоставленной схеме:
питания от внутреннего стабилизатора не хватит для запитки DFPlayer и ленты.
DFPlayer — подкдючение динамика SPK1(6) SPK2 (8) (земля не используется).
паралельно конденсатору помпа включить диод (чтобы не палить контакты реле и если используется силовой ключ не спалить мосфет).
Описание в 182 сообщении.
То же жду посылку с Али с МП3, все остальное работает, осталось в культурный корпус запихнуть.
Сейчас буду собирать с ЛСД1602 дисплеем, внутренней ёмкостью на 500мЛ и тонким поворачивающимся краником.
- Войдите на сайт для отправки комментариев
- « первая
- ‹ предыдущая
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- …
- следующая ›
- последняя »
Привет всем. Наконец то доделан проект под названием «Наливатор. Сообразим на четверых». В данной статье будет рассказана примерная хронология разработки и изготовления устройства опираясь на те фото, что сохранились. Итак начнем.
Вначале было слово. Нет, это не мой случай. Вначале было видео.
Посмотрев это понял, что нужно сделать что то подобное. На тот момент, когда вышло это видео в сети не было ни гайвера ни подобных, кто бы рассказывал как и из чего делать. Да и повторение проектов-это не мой метод. Перед собой поставил задачу разработать все с нуля и отладить.
Итак начнем. Первым делом было собран макет из 2-х досок и трубки, вырезанной из старой советской коляски. Использованы датчики наличия стакана, собранные на фото+свето диодах с длинной волны 940нм. Ардуино уно. Вспомогательных плат нет, все датчики подключены к макетке. Вспыхивание красного светодиода символизирует налив рюмки.
Фото не осталось, так что прикладываю видос:
Ворох проводов очень сильно мешался. Драйвер шагового двигателя, компараторы для фотодиодов было решено объединить в одну плату и на ней развести коммутацию. Получилось более компактно, чем было.
Выбор объема налива осуществлялся на дисплее 20х4. Управление тактовыми кнопками. Кнопка вверх/вниз/пуск. Подключение дисплея-8 бит данных+управление. Опять ворох проводов и пинов стало не хватать у контроллера.
Далее дисплей заменен на 16х2 с управлением по шине i2c. Особенность данного способа подключения-всего 2 провода данных и 2 провода питания. Крайне удобно и практично.
Для удобства сборки всей электроники изготовлены 3 платы:
1)Плата сенсоров-устанавливается на верхней части и обрабатывает все сигналы управления и индикации.\
2)Плата контроллера-установлен МК+ минимально необходимая обвязка
3)Плата драйверов-Стабилизаторы питания, драйвера шаговых двигателей
Для индикации процесса работы (стайл, конечно тоже, сильно улучшился) были установлены адресные светодиоды ws2812b. Был заказан под этот проект перистальтический насос на 12в. Думал подойдет, но оказалось, что он работает очень громко и поток слабый и неравномерный. Порция жидкости хлюпает сильно, и когда рюмка почти полная разбрызгивается.
Параллельно с поиском нового насоса начал рисовать проект в Компасе 3D.
Многократно переделывалась электроника. первое, что изменил — это на плате драйверов был установлен стабилизатор lm7805, но при токе 500ma и падении напряжения 12 в 5в он очень сильно грелся и пришлось заменить lm7805 на lm2576, хотя на радиатор все равно посадил всю конструкцию. Управление было изменено с такторых кнопок на энкодер-как то приличнее, что-ли, выглядеть стало)
Каждое изменение в проекте сопровождалось переделкой электроники. Сколько я текстолита перевел на это — страшно представить. Хорошо, хотя бы сам печатаю платы, а если заказывать изготовление в Китае или, тем паче, у нас, вообще золотыми выйдут платы.
На фото совмещение верхнего и нижнего слоев двусторонней печатной платы.
Пока я развлекался с электроникой: доделывал прошивку, дорабатывал электронику, в общем отлаживал устройство, друзья напечатали корпус на 3d принтере.
Сборка устройства. В таком виде оно увидело свет.
Крышка. Вся коммутация между платами и блоками устройства осуществляется шлейфами.
Естественно, испытания, испытания.
Заменил перистальтический насос на мембранную помпу. Заменил драйвер l298n на полевик IRF540N для управления мотором налива, так как необходимость шагового драйвера отпала, а лишние 150 рублей платить неинтересно. Очередной раз переделал электронику.
Первые испытания дали понять, что необходимо установка АКБ, так как розетка далеко не всегда рядом. Следом за установкой аккумуляторов выявилась необходимость в индикаторе заряда. Это здесь все легко и красиво, а по факту, вариантов проверено много, и еще больше идей продумано. Остановился на сборке 2х li-ion АКБ с балансиром 2S и повышайкой до 12в. Также с Алиэкспресс пришел индикатор заряда для 2S. Качество, кстати очень хорошее, мне понравилась сама идея индикации сегментами. Чтобы не разряжать аккумуляторы установлена кнопка включения индикации заряда. Тут логика простая — «я художник, я так вижу». Автономная работа от полностью заряженных АКБ составляет долее 15 часов при активном использовании.
При разработке корпуса был изменен принцип работы определения наличия рюмки. На сайтах, где продаются подобные устройства в описании есть ручной режим, который необходим при использовании на ярком солнце, так как оно засвечивает датчик и рюмку аппарат не видит. При данной же компоновке оптических датчиков влияние внешних факторов практически исключено, но появилась необходимость использования специальных рюмок. Они идут комплектом к устройству + блок питания. Данное устройство сейчас в продаже.
Provide feedback
Saved searches
Use saved searches to filter your results more quickly
Sign up
Appearance settings
Всех приветствую. Очень меня затянула тема ARDUINO и 3D печати. Решил вот тоже разработать свою модель. Все метался с датчиками рюмок, остановился на герконах. Распечатал и собрал, каждый. С ИК датчиками сразу возникли проблемы, на улице уходили сразу в засвет, система пригодна только в домашних условиях. Пришли от китайцев микрики, сделал корпус под микрики, всё устраивает, но ! Но после недельной эксплуатации, каждый экземпляр вскрыл и обнаружил на шилде , что там не хило все окислилось ( хотя на работу это ни как не сказалось). Последствия пролива спиртного ( когда «принимающий уже на качерге). Зазоры в светодиодах, ик датчиках и микрухах, дали о себе знать. И тут осенило, надо поставить геркон, на рюмку сделать донышко 2мм с местом под магнит и закрыть стол, или стеклом или пленкой ПВХ ( прозрачной)
Вариант 1 ( ИК датчики) :
Может не те датчики брал, не знаю, но от этого варианта ушел.
Вариант 2 Микрухи:
Вертикальные перемычки на панели поддержки для чистовой печати, т.к. панель съемная, под разные виды дисплеев.
1602
1637
Ну и окончательный вариант, Герконы
На столе выбрано место под стекло или пленку, проливы в таком исполнении не страшны. Герконы отрабатывают на ура ! И к стати, отказался от датчиков с герконами ( от китайцев), поставил только сами герконы, проблем в работе не вижу совсем.
Ну и как продолжение, решил исполнить всё в мобильной версии, пока только в разработке
Ну и набор деталей, используемых в проектах ( меняются только датчики)
Версию в чумадане, хочу упаковать по полной….:)))))))))) .
Очень много почерпнул у Гайвера, Алекс ваще красава, куча благодарностей за его труды !
ЗЫ
До апреля. я вовсе не имел ( слышал вернее) понятия о , ARDUINO и 3D печать, и работу в редакторах объемного моделирования, с вилами кидался. Очень увлекло !