Наливатор - автоматизированная машина, которая будет разливать алкоголь по стопкам.

sha-tosik
Offline
Зарегистрирован: 16.09.2019

То-есть ардуинка подключена к ПК через usb, датчики к ардуино, а как запитываются сами датчики? Отдельно на датчики + и -?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

можно от ардуины + -  5в

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Forthomo пишет:

Поправил код  из 181 сообщения, с МП3 плейером, все работает

запятую вместо ? не получилось победить (по раскладке рус - "," англ - "?"), заменил на !

У меня почему то приветствие отображается как тост после налива. Если только с ардуины снять питание (на всё остальное питание подано) то приветствие озвучивается,но не отображается на экране.тосты"за братство"и"ну вы блин даёте"на экране отображаются одновременно накладываясь друг на друга(фото потом выложу).звучит при этом"за братство". Тосты "за дружбу" и "ну вы блин даёте" имеют одинаковый намер трека. В остальном всё нормально, спасибо.

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Фото

https://yadi.sk/i/gPs-D_7ATuDz2g

Причину пока не знаю

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

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

"ну вы блин даёте" трек 0020 кажется, проглядел сам. кейс 3 и 4 накладываются, причину пока не выяснил.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

RW3 пишет:
Фото https://yadi.sk/i/gPs-D_7ATuDz2g Причину пока не знаю

точно так же.

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Вечером буду изучать....

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Forthomo А с индикатором 1602 разобрались?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Я слаб в программировании, похоже все дело в русифицированной библиотеке. Работает все за исключением менюшек: "наливаю" , "налито" и автоматический розлив (кол-во мл не отображается на LCD, в порт все выводится).

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019
  case 3:
      myOLED.print(F("DS <KBY"), CENTER, 38); //ВЫ БЛИН
      myOLED.print(F("LFTNT!"), CENTER, 55); //ДАЕТЕ!
      mp3_play (20);  // Проигрываем "mp3/0020.mp3"
    delay(100);

вот так надо сделать

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

mp3_play (20); наверно?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

moder пишет:

TCRT5000 . Буду ждать прошивку.

По применению датчиков  TCRT5000 без переделки и добавления инвертора.

Это только предположение, но возможно  в скетче поправить всего две строчки

432           if (analogRead(Optics[y]) > Optics_porog[y] ) {

490          if (val > Optics_porog[i]) {

поменять ">" (больше) на  "<" (меньше).  Это лучше объяснит автор скетча stpavel.
Был бы датчик попробовал бы.

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

RW3 пишет:
mp3_play (20); наверно?

да, конечно. С отпуска вышел , дергают постоянно.

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

mp3_play (20); И switch (random(19))

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

RW3 пишет:
mp3_play (20); И switch (random(19))

это не нужно, кейсов всего 18 (// case 0...17)

mp3_play (20); поправил

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Forthomo пишет:

RW3 пишет:
mp3_play (20); И switch (random(19))

это не нужно, кейсов всего 18 (// case 0...17)

mp3_play (20); поправил

Я просто ещё один тост добавил "за женщин (был "за истинных женщин"), пусть будет.....

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

тогда конечно -  switch (random(19)).

 

Хорошо бы было визуально заряд батареи прикрутить в уголок экрана, жалко одна свободная лапа осталась.

vovan47
Offline
Зарегистрирован: 16.09.2019

Здравствуйте!если не трудно есть полный список чего нужно приобрести для данного проекта?

 

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Смотрите пост 163и 168

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Никак не могу понять, почему при использовании покупного датчика TCRT5000 с триггером Шмидта возникают проблемы? Логика работы одинакова.

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

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

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

RW3 пишет:
Как раз наоборот должно быть. Я в самопал добавлял инвертор и всё хорошо работает.с покупными проблем не должно быть,если только там сигнал два раза не переворачивается. Сейчас жду покупные датчики с инвестором.придут ,посмотрим.

Прикольно, у меня без инверторов работает! Без рюмки низкий уровень на выходе, с рюмкой - высокий.

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Без инвертора тоже будет работать.из левой схемы уберите инвертор и получатся две разные схемы, одна с 1 на выходе другая с 0 .хотя на вид они похожи. Нашли разницу?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Я встречал обе схемы подключения Фототранзистора, у меня Самопал,  сигнал снимается с эмитера.

RW3 какая у тебя схема?

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

У меня сигнал снимается с коллектора , можно было просто перепаять провод, но я залил их со стороны монтажа термо клеем.и с инвертором срабатывание намного чётче из за триггера

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

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

Спасибо. Все встало на свои места. Порог какой у датчика с триггером?

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Не заморачивался с этим, выставил в скетче все по 50. Срабатывают чётко

moder
Offline
Зарегистрирован: 30.08.2019

А кто-нибудь заморачивался с индикаций заряда батареи на этом дисплее, как в оригинальном изделии автора?

vovan47
Offline
Зарегистрирован: 16.09.2019

Поделитесь ссылками на годные комплектующие!

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

void DrinkInfo(byte pos) {
  lcd.setCursor(0, 0); // устанавливаем курсор в 1-ю ячейку верхней строки
  lcd.print(F("HАЛИТЬ ПО")); // пишем "HАЛИТЬ ПО" (с 1 по 9 ячейку)
  lcd.setCursor(10, 0); // устанавливаем курсор в 11-ю ячейку верхней строки
  lcd.print(Drink); // пишем переменную "Drink" в 11 и 12 ячейку (2 знака)
  Serial.println(Drink);  // выводим переменную ""Drink" в монитор порт
  lcd.setCursor(13, 0);// устанавливаем курсор в 14-ю ячейку верхней строки
  lcd.print(F("мЛ?")); // пишем "мЛ?" (с 14 по 16 ячейку)

Вот Drink и не выводиться на LCD.

 Фразы "Ни о чем", "по чуть- чуть", "в самый раз"  и др. -  при прокручивании энкодера изменяются на дисплее в зависимости от количества Drink. Аналогично и с DrinkCount и Drink в ручном режиме.

Я использую библиотеку Liquid_Crystal_i2c и дисплей с зашитой кириллицей. 

Все нормуль  с выводом

 


void oled_auto(int Drink) {


  char myStr[16];
   lcd.clear();
   sprintf(myStr,"Ha\273\270\263. \276o %02d \274\273.",Drink );
   lcd.setCursor(0, 1);
   lcd.print(myStr);
   DrinkInfo();
  }

void DrinkInfo() {
   lcd.setCursor(0, 0);
    if (Drink < 15) {
    lcd.print(F("    H\270 o \300\265\274"));
    } else if (Drink < 28) {
     lcd.print(F("  \250o \300y\277\304-\300y\277\304"));
    } else if (Drink < 38) {
     lcd.print(F("  B ca\274\303\271 pa\267!"));
    } else if (Drink < 48) {
     lcd.print(F("   \250o \276o\273\275o\271!"));
    } else {
     lcd.print(F("    \340o \272pa\265\263"));
    }
  

}

 

stpavel
Offline
Зарегистрирован: 09.10.2018

Forthomo пишет:

moder пишет:

TCRT5000 . Буду ждать прошивку.

По применению датчиков  TCRT5000 без переделки и добавления инвертора.

Это только предположение, но возможно  в скетче поправить всего две строчки

432           if (analogRead(Optics[y]) > Optics_porog[y] ) {

490          if (val > Optics_porog[i]) {

поменять ">" (больше) на  "<" (меньше).  Это лучше объяснит автор скетча stpavel.
Был бы датчик попробовал бы.

 

Совершенно верно. 
​Править нужно именно тут. К сожалению датчиков тоже нет, поэтому что они выдают , не знаю. 

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Я использую библиотеку Liquid_Crystal_i2c и дисплей с зашитой кириллицей. 

Все нормуль  с выводом

 а какая марка дисплея? это похоже отечественный дисплей


stpavel
Offline
Зарегистрирован: 09.10.2018

RW3 пишет:

Я использую библиотеку Liquid_Crystal_i2c и дисплей с зашитой кириллицей. 

Все нормуль  с выводом

 а какая марка дисплея? это похоже отечественный дисплей



MT-16S2H

moder
Offline
Зарегистрирован: 30.08.2019

Могу опробовать тк сейчас через инвертируй работает

sha-tosik
Offline
Зарегистрирован: 16.09.2019

[/quote]

Сообщение 116, короткий скетч для проверки  и калибровки датчиков. Подключаешь датчики, заливаешь скетч, открываешь монитор порта. Смотришь значения без рюмок, ставишь рюмки , снова смотришь значения, вот эти значения и будут порогом срабатывания.

[/quote]

без рюмки-1001, с рюмкой-81. какое значение вставлять в скетч?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

sha-tosik пишет:

Сообщение 116, короткий скетч для проверки  и калибровки датчиков. Подключаешь датчики, заливаешь скетч, открываешь монитор порта. Смотришь значения без рюмок, ставишь рюмки , снова смотришь значения, вот эти значения и будут порогом срабатывания.

[/quote]

без рюмки-1001, с рюмкой-81. какое значение вставлять в скетч?

[/quote]

1. поправить  две строчки

432           if (analogRead(Optics[y]) > Optics_porog[y] ) {

490          if (val > Optics_porog[i]) {

поменять ">" (больше) на  "<" (меньше).

2. поставвь 500

25          const unsigned int Optics_porog[] = {500,500,500,500,500};

 

sha-tosik
Offline
Зарегистрирован: 16.09.2019

я про скетч с первой страницы. строки 27-31. там нужно выставить порог под каждый датчик

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

sha-tosik пишет:

я про скетч с первой страницы. строки 27-31. там нужно выставить порог под каждый датчик

до вечера подождет? не читал полностью скетч.

sha-tosik
Offline
Зарегистрирован: 16.09.2019

подождет

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

sha-tosik, Вот вкратце процедуру описал для понимания

27    #define tcr1 750//порог ИК датчика 1// выставляй 500, можно оставить как есть 750
28 -31    //аналогично для остальных датчиков

109     //определение наличия стакана
110     int tcrt1 = analogRead(A1); // присваиваем переменной tcrt1 значение считанного с порта А1
111      if( tcrt1<tcr1) // сравниваем - если полученное с А1 значение меньше порога срабатывания датчика 1

374    {  //проверка наличия стакана и включение лампочки под присутсвующим

375      if( analogRead(A1)<tcr1) strip[14] = CRGB::Indigo; // тут уже все прнятно
376        else strip[14] = CRGB::Black; // не зажигать 14 пиксель

sha-tosik
Offline
Зарегистрирован: 16.09.2019

с порогом разобрался. спасибо! подправьте пожалуйста скетч, чтобы светодиоды загорались так:https://www.youtube.com/watch?v=CzqTpZYdGlc скетч с первой страницы. светодиоды ws2812 5 штук

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

А как они сейчас у вас загораются?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

RW3 пишет:
А как они сейчас у вас загораются?

RW3, приветствую!

вот именно: в скетче указано 15 пикселей

#define LED_COUNT 15// Указываем, какое количество пикселей у нашей ленты.

1й стакан - i=14, 2й - 13, 3й- 12, 4й-11, 5-й - 10.

Вывод: что то не так в скетче. Надо досконально разбираться.

sha-tosik, а с энкодером не проще сделать? Скетч есть, повторили несколько раз.

 

 

 

RW3
RW3 аватар
Offline
Зарегистрирован: 07.08.2019

Там изначально была ещё и шкала налива из светодиодной ленты. В зависимости от количества налитого менялся цвет и количество включенных светодиодов.ссылка на видео это уже второй вариант устройства
https://youtu.be/FXt5X5fnGc0
Я бы из первого скетча взял бы во эти строчки

myOLED.print("NS LEHFR?", CENTER, 10);// ты дурак?
239
myOLED.print("GJCNFDM H>VRB B", CENTER, 25);// поставь рюмку!
240
myOLED.print("YF:VB RYJGRE -JR-", CENTER, 40); //нажми ОК
241
myOLED.update();

Если во время налива убрать рюмку

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Forthomo пишет:

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

"ну вы блин даёте" трек 0020 кажется, проглядел сам. кейс 3 и 4 накладываются, причину пока не выяснил.

вся проблема в рандоме, накладывается кейс 4 накладывается на 3й, на ЛСД1602 накладываются 3,4 и 7й.

aleks_raichel
Offline
Зарегистрирован: 27.08.2019

В программировании не силен, но с диодами вроде справился по изначальному скетчу

 

#include <OLED_I2C.h>
#include <Servo.h>
#include <FastLED.h> 
 
#define pot A0//пин потенциометра
#define button 3//пин кнопки 
#define relPin 2// реле на 2 пин
#define LED_COUNT 15// Указываем, какое количество пикселей у нашей ленты.
#define LED_PIN 5// Указываем, к какому порту подключен вход ленты DIN.
#define BRIGHTNESS 180 //яркость ленты 0-255
 
CRGB strip[LED_COUNT];//подключаем ленту
OLED  myOLED(SDA, SCL, 8);// подключаем дисплей
Servo myservo;
 
extern uint8_t RusFont[];//русский шрифт 
extern uint8_t MediumNumbers[];//шрифт средних чисел
 
 
byte pos = 9; // Переменная,в которой хранится позиция сервы
#define pos0 50 //Позиция парковки , здесь нужно подбирать значения в зависимости от шага расположения рюмок 
#define pos1 56 //Позиция 1 стакана
#define pos2 88 //Позиция 2 стакана
#define pos3 120 //Позиция 3 стакана
#define pos4 148 //Позиция 4 стакана
#define pos5 179 //Позиция 5 стакана
#define tcr1 50//порог ИК датчика 1 //здесь настраивается порог сработки датчиков под рюмками
#define tcr2 50//порог ИК датчика 2 //при отладке смотрим как меняются значения с датчика 
#define tcr3 50//порог ИК датчика 3 //когда рюмка установлена и когда снята
#define tcr4 50//порог ИК датчика 4
#define tcr5 50//порог ИК датчика 5
bool flag=0;   // флаг кнопки
int ml=0;//переменная для отображения милилитров
int doza = 1000;      // объем для налива в микросек (не более 40 мл=2920 при испыт. напряжен) нужно подбирать при калибровке
int led_num = 0; //переменная с номером пикселя ленты
int previous_led_num = 0;//переменная с номером предыдущего пикселя ленты
int i=0;//переменная адрес пикселя
byte rum=0; //количечтво рюмок(по умолчанию 0 - чтобы случайно не налить без рюмки)
 
void setup()
{
pinMode(pot, INPUT);//пин потенциометра
pinMode(button ,INPUT); // кнопка 
digitalWrite(button ,HIGH); // подключаем встроенный подтягивающий резистор кнопки
pinMode(relPin, OUTPUT); //реле на выход
myOLED.begin();//инициализация дисплея
FastLED.addLeds<NEOPIXEL, LED_PIN >(strip, LED_COUNT);//инициализация ленты(тип, пин(лента, кол-во пикселей)
FastLED.setBrightness( BRIGHTNESS );//устанавливаем яркость ленты
 Serial.begin(9600);
}
 
void loop()
{
 
     while(1)
     {
      vol();
      lightLed();
      check();
        if (digitalRead(button)==LOW&&flag==0)
        {
          flag=1;
          break;
        }
      }
   
   /*  for (i = 9; i >=0; i--)//потушим пиксели 
    {
      strip[i] = CRGB::Black; // черный цвет после налива
      FastLED.show();
      delay(100);
    }
    */
// выводим выбранный объем перед наливом
    myOLED.clrScr();  
    myOLED.setFont(RusFont);
    myOLED.print("YFKBDF>", CENTER, 17);//здесь и далее в кавычках пишем русский текст для отображения на дисплее в английской раскладке 
   Serial.print("ml=");
   Serial.print(ml);
   Serial.print("\n");
   if(ml < 10)                          // "YFKBDF>" - "НАЛИВАЮ"
   {
    myOLED.print("YB J XTV", CENTER, 30);
   } else if(ml < 25)
   {
    myOLED.print("GJ XENM-XENM", CENTER, 30);
   }
   else if(ml < 36)
   {
    myOLED.print("D CFVSQ HFP", CENTER, 30);
   }
    else if(ml < 40)
   {
    myOLED.print("GJ GJKYJQ", CENTER, 30);
   }
   else if(ml <= 40)
   {
    myOLED.print("LJ RHFTD", CENTER, 30);
   }
myOLED.update(); 
myservo.attach(9);// подключаем серву на 9 пин.
myservo.write(pos0);
 
    //1 стакан
 for (pos = pos0; pos <= pos1; pos += 1) 
 { 
    myservo.write(pos);          
    delay(12);                     
  }
  delay(10);
  myservo.detach();//отключаем серву.если этого не сделать, то серва будет дергаться или гудеть когда не двигается.
  //определение наличия стакана
  int tcrt1 = analogRead(A1); 
  if( tcrt1<tcr1)//проверяем установлен ли стакан
  {
  i=4;//адрес пикселя под 1 стаканом
  pump();//запускаем функцию налива если стакан установлен.
  }
 
//2 стакан
myservo.attach(9);
  for (pos = pos1; pos <= pos2; pos += 1)
  { 
    myservo.write(pos);             
    delay(12);                       
  }
  delay(10);
 myservo.detach();
  int tcrt2 = analogRead(A2);
  if( tcrt2<tcr2)
  {
  i=3;//адрес пикселя под 2 стаканом
  pump();
  }
 
 
//3 стакан
myservo.attach(9);
 for (pos = pos2; pos <= pos3; pos += 1)
 { 
    myservo.write(pos);              
    delay(12);                  
  }
  delay(10);
  myservo.detach();
  int tcrt3 = analogRead(A3);
  //Serial.println(tcrt3);
  if( tcrt3<tcr3)
  {
  i=2;//адрес пикселя под 3 стаканом
  pump();
  }
 
//4 стакан
myservo.attach(9);
  for (pos = pos3; pos <= pos4; pos += 1)
  { 
    myservo.write(pos);            
    delay(12);                      
  }
  delay(10);
  myservo.detach();
  int tcrt4 = analogRead(A6);
  if( tcrt4<tcr4)
  {
  i=1;//адрес пикселя под  стаканом
  pump();
  }
 
//5 стакан
myservo.attach(9);
 for (pos = pos4; pos <= pos5; pos += 1)
 { 
    myservo.write(pos);             
    delay(12);                     
  }
  delay(10);
  myservo.detach();
  int tcrt5 = analogRead(A7);
  if( tcrt5<tcr5)
  {
  i=0;//адрес пикселя под  стаканом
  pump();
  }
 
 //парковка - переводим серву в нулевое положение после налива
  myservo.attach(9);
  for (pos = pos5; pos >= pos0; pos -= 1)
  { 
    myservo.write(pos);              
    delay(7);                      
  }
  delay(200);
  myservo.detach();
 
     // выводим текст по окончании и ожидаем нажатия кнопки для повтора налива
 
   while(1)
   {
     if (digitalRead(button)==LOW&&flag==1)
        {
          flag=0;
          rum=0;
          break;
       }
        if( rum!=0)
      {
      myOLED.clrScr();  
      myOLED.setFont(RusFont);
      myOLED.print("<SKJ YFKBNJ GJ", 0, 5); //было налито по ml в rum рюмок
      myOLED.print("D", 0, 28); //в
      myOLED.print("Vk", RIGHT, 5); //в
      myOLED.print("YF:VBNT RYJGRE -JR-", 0, 50); //нажми кнопку ОК
    
       if(rum==1)
       {
         myOLED.setFont(RusFont);
          myOLED.print("H>VRE",24, 28);
        }
        else if( rum==5)
        {
          myOLED.setFont(RusFont);
           myOLED.print("H>VJR", 24, 28);
        }
       else if(rum==2 || rum==3 || rum==4 )
        {
          myOLED.setFont(RusFont);
          myOLED.print("H>VRB", 24, 28);
         }
   
       myOLED.setFont(MediumNumbers);
       myOLED.printNumI(ml,87,0);
       myOLED.printNumI(rum,10,23);
       myOLED.update();
       }
   else
   {
     myOLED.clrScr();  
     myOLED.setFont(RusFont);
     myOLED.setFont(RusFont);
     myOLED.print("EDF:FTVSQ", CENTER, 6);// Уважаемый
     myOLED.print("GJCNFDM H>VRB B", CENTER, 22);// поставь рюмку!
     myOLED.print("YF:VB RYJGRE -JR-", CENTER, 40); //нажми ОК
     myOLED.update();
   }
 }
   //блок светоанимации после налива и нажатия кнопки
      for (int k = 0; k <2; k++)
      {
      for (i = 0; i <=8; i++)
      {
      strip[i] = CRGB::Blue; 
   
      strip[i+1] = CRGB::Red;
    
      FastLED.show();
       delay(30);
      }
  
      for (i = 8; i >=0; i--)
      {
      strip[i] = CRGB::Red; 
     
      strip[i+1] = CRGB::Blue;
  
      FastLED.show();
       delay(30);
      }
     }
     for (i = 0; i <=8; i++)
      {
      strip[i] = CRGB::Blue; 
   
      strip[i+1] = CRGB::Red;
    
      FastLED.show();
       delay(30);
      }
     for (i = 9; i >=0; i--)//потушим пиксели 
      {
      strip[i] = CRGB::Black; // черный цвет после налива
      delay(30);
      FastLED.show();
      }
      
}
 
void vol()// ф-я выбора объема на дисплее
{
 
    ml = analogRead(pot);
    ml = map(ml, 0, 1000, 1, 40);// считываем напряж с потенц 0-1000 и переводим в интервал 1-40 мл
    myOLED.clrScr();  
    myOLED.setFont(MediumNumbers);
    myOLED.printNumI(ml,40,25);
    myOLED.setFont(RusFont);
    myOLED.print("DS<THBNT J<}TV", CENTER, 0);// Выберите объем
    myOLED.print("YFGBNRF",CENTER,16);// от 1 до 40 мл
    myOLED.print("Vk",66,33);// 
    
   if(ml < 10) myOLED.print("YB J XTV", CENTER, 50);// ни о чем
   else if(ml < 21) myOLED.print("GJ XENM-XENM", CENTER, 50);// по чуть-чуть
   else if(ml < 32) myOLED.print("D CFVSQ HFP", CENTER, 50);// в самый раз
   else if(ml < 40) myOLED.print("GJ GJKYJQ", CENTER, 50);// по полной
   else if(ml <= 40) myOLED.print("LJ RHFTD", CENTER, 50);// до краев
   myOLED.update();  
}
void lightLed()//ф-я зажигающая шкалу
{
  led_num = map(analogRead(pot), 0, 1000, 5, 14);// считываем напряж с потенц 0-1000 и переводим в интервал 5-14
  if(led_num > previous_led_num)
  {
     setLed();
  } else if(led_num < previous_led_num)
  {
     // Выключаем лишние светодиоды.
     for (int i = (previous_led_num - 1); i >= led_num; i--)
     {
       strip[i] = CRGB::Black; // Черный цвет, т.е. выключено.
     }
     FastLED.show();
     delay(10);
     setLed();
  }
  FastLED.show();
  delay(10);
  previous_led_num = led_num;
}
 
void setLed()
{
   if(led_num < 5)
   {
      chooseColour(CRGB::Orange);
   } else if(led_num < 8)
   {
      chooseColour(CRGB::Green);
   }else if(led_num < 11)
   {
      chooseColour(CRGB::Red);
   }
}
 
void chooseColour(CRGB colour)
{
  if(led_num == 5 || led_num == 8 || led_num < previous_led_num)
  {
    for (int j = 0; j < led_num; j++)
    {
      strip[j] = colour;
    }
  } else
  {
    for (int j = previous_led_num; j < led_num; j++)
    {
      strip[j] = colour;
    }
  }
}
 
 
void pump() //ф-я, включающая насос
{
  doza = map(ml, 1, 40, 125, 4700);// переводим знач перем ml интервала 1-40 в doza 125-4700 в милисекунды, в течение которых работает насос.диапазон подбирается при калибровке
  delay(300); //ждем 0.3 секунды
  digitalWrite(relPin, HIGH);//вкл реле
  strip[i] = CRGB::Red; // красный пиксель на i адресе
  FastLED.show();
  delay(doza);// 2920=40мл
  digitalWrite(relPin, LOW);//выкл реле
  strip[i] = CRGB::Green; // зеленый пиксель на i адресе
  FastLED.show();
  rum+=1;
  delay(1500);
}
void check()
{  //проверка наличия стакана и включение лампочки под присутсвующим
  if( analogRead(A1)<tcr1) strip[4] = CRGB::Indigo;
   else strip[4] = CRGB::Black;
  if( analogRead(A2)<tcr2) strip[3] = CRGB::Indigo;
   else strip[3] = CRGB::Black;
  if( analogRead(A3)<tcr3) strip[2] = CRGB::Indigo;
   else strip[2] = CRGB::Black;
  if( analogRead(A6)<tcr4) strip[1] = CRGB::Indigo;
   else strip[1] = CRGB::Black;
  if( analogRead(A7)<tcr5) strip[0] = CRGB::Indigo;
   else strip[0] = CRGB::Black;
  FastLED.show();
 /* 
  myOLED.setFont(MediumNumbers);//раскомментировать при подборе значений переменных tcr - с датчиков под рюмками.
    myOLED.printNumI(analogRead(A1),0,0);
    myOLED.printNumI(analogRead(A2),45,0);
    myOLED.printNumI(analogRead(A3),90,0);
    myOLED.printNumI(analogRead(A6),0,20);
    myOLED.printNumI(analogRead(A7),45,20);
    myOLED.update();  
  */
}
vovan47
Offline
Зарегистрирован: 16.09.2019

Добрый вечер!есть у кого фото уже законченного наливатора?

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

aleks_raichel пишет:

В программировании не силен, но с диодами вроде справился по изначальному скетчу

#define LED_COUNT 15// Указываем, какое количество пикселей у нашей ленты.

#define LED_COUNT 5// Указываем, какое количество пикселей у нашей ленты -5.

aleks_raichel
Offline
Зарегистрирован: 27.08.2019

Пробовал ставить 5, глючит, поэтому пошел от противного, поменял везде пиксели местами, чтобы первые пять диодов для подсветки работали, а остальные 10 как говориться в уме....

Forthomo
Forthomo аватар
Offline
Зарегистрирован: 10.04.2019

Вот скетч для 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(0x3F, 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 = 20; // По умолчанию в рюмку наливаем  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(byte Menu) {
  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print(F("НАЛИВАТОР+"));
  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;
  }
}

//  выводит строчку по чуть чуть, в самый раз и тд. Передается номер строки, на которой выводить сообщение
void DrinkInfo(byte pos) {
  Serial.println(F("INFO_DRINK"));

	lcd.setCursor(0, 1);
  if (Drink < 15) {
//    lcd.setCursor(0, 1);
    lcd.print(F("    НИ О ЧЕМ    "));
  } else if (Drink < 28) {
//    lcd.setCursor(0, 1);
    lcd.print(F(" ПО ЧУТЬ - ЧУТЬ "));
  } else if (Drink < 38) {
//    lcd.setCursor(0, 1);
    lcd.print(F("  В САМЫЙ  РАЗ  "));
  } else if (Drink < 48) {
//    lcd.setCursor(0, 1);
    lcd.print(F("   ПО  ПОЛНОЙ  "));
  } else {
//    lcd.setCursor(0, 1);
    lcd.print(F("    ДО КРАЕВ    "));
  }
}
// Меню Авто режим
void oled_auto(int Drink) {
    Serial.println(F("MENU_AUTO"));
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(F("HАЛИТЬ ПО"));
    lcd.setCursor(10, 0);
    lcd.print(Drink);
  Serial.println(Drink);
    lcd.setCursor(13, 0);
    lcd.print(F("мЛ?"));
    DrinkInfo(57);

}

// Меню Ручной режим
void oled_manual(int DrinkCount, int Drink) {
    Serial.println(F("MENU_RUCHN"));
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(F("HАЛИТЬ ПО"));
    lcd.setCursor(10, 0);
    lcd.print(Drink);
    lcd.setCursor(13, 0);
    lcd.print(F("мЛ?"));  
  Serial.println(Drink);  
  lcd.setCursor(0, 1);
    lcd.print(F("   В   РЮМ"));
    lcd.setCursor(5, 1);
    lcd.print(DrinkCount);
    Serial.println(DrinkCount); 
  if (DrinkCount == 1) {
    lcd.setCursor(10, 1);
    lcd.print(F("КУ     "));
  } else if (DrinkCount <= 4 ) {
    lcd.setCursor(10, 1);
    lcd.print(F("КИ     "));
  } else {
    lcd.setCursor(10, 1);
    lcd.print(F("ОК     "));
  }
  
}
// Меню налива
void oled_naliv(int MenuFlag, int Drink, int DrinkCount) {
  Serial.println(F("NALIVAIU"));
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(F("НАЛИВАЮ ПО"));
    lcd.setCursor(11, 0);
    lcd.print(Drink);
  Serial.println(Drink);
    lcd.setCursor(14, 0);
    lcd.print(F("мЛ"));
    lcd.setCursor(0, 1);
    lcd.print(F("   В"));
    lcd.setCursor(5, 1);
    lcd.print(DrinkCount);
  Serial.println(DrinkCount); 
    lcd.setCursor(7, 1);
    lcd.print(F("РЮМ"));

  if (DrinkCount == 1) {
    lcd.setCursor(10, 1);
    lcd.print(F("КУ     "));
  } else if (DrinkCount <= 4 ) {
    lcd.setCursor(10, 1);
    lcd.print(F("КИ     "));
  } else {
    lcd.setCursor(10, 1);
    lcd.print(F("ОК     "));
  }
}
// Меню налито
void oled_nalito(int MenuFlag, int Nalito, int Drink) {
    Serial.println(F("NALITO"));
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(F("HАЛИТО ПО"));
    lcd.setCursor(11, 0);
    lcd.print(Drink);
    Serial.println(Drink); 
    lcd.setCursor(14, 0);
    lcd.print(F("мЛ"));
    lcd.setCursor(0, 1);
    lcd.print(F("   В"));
    lcd.setCursor(5, 1);
    lcd.print(Nalito);
    lcd.setCursor(7, 1);
    lcd.print(F("РЮМ")); 
  Serial.println(Nalito);
  if (Nalito == 1) {
    lcd.setCursor(10, 1);
    lcd.print(F("КУ     "));
  } else if (Nalito <= 4 ) {
    lcd.setCursor(10, 1);
    lcd.print(F("КИ     "));
  } else {
    lcd.setCursor(10, 1);
    lcd.print(F("ОК     "));
  }

}
  void Tost() {
  randomSeed(currentTime);
//Рандом - 1
    lcd.clear();
  switch (random(20)) { // 0...19
	case 0: //ЗА ВСТРЕЧУ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА ВСТРЕЧУ!"));
		mp3_play (2);  // Проигрываем "mp3/0002.mp3"
		delay(100);
    case 1: //ЗА КРАСОТУ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА КРАСОТУ!"));   
		mp3_play (3);  // Проигрываем "mp3/0003.mp3"
		delay(100);
	case 2: //"ЗА ДРУЖБУ!"
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));//
		lcd.setCursor(3, 1);
		lcd.print(F("ЗА ДРУЖБУ!"));  
		mp3_play (4);  // Проигрываем "mp3/0004.mp3"
		delay(100);
	case 3: //"ЗА БРАТСТВО!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА БРАТСТВО!"));   
		mp3_play (5);  // Проигрываем "mp3/0005.mp3"
		delay(100);
	case 4: //ЗА СПРАВЕДЛИВОСТЬ!
		lcd.setCursor(5, 0);
		lcd.print(F("НУ, ЗА"));
		lcd.setCursor(1, 1);
		lcd.print(F("СПРАВЕДЛИВОСТЬ!"));
		mp3_play (6);  // Проигрываем "mp3/0006.mp3"11
		delay(100);
    case 5: //ЗА РЫБАЛКУ!
	lcd.setCursor(7, 0);
	lcd.print(F("НУ,"));
	lcd.setCursor(3, 1);
	lcd.print(F("ЗА РЫБАЛКУ!"));
		mp3_play (7);  // Проигрываем "mp3/0007.mp3"
		delay(100);
	case 6: //ЗА ИСКУССТВО!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА ИСКУССТВО!"));
		mp3_play (8);  // Проигрываем "mp3/0008.mp3"
		delay(100);
	case 7: //ЗА РАЗУМ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(3, 1);
		lcd.print(F("ЗА РАЗУМ!"));
		mp3_play (9);  // Проигрываем "mp3/0009.mp3"
		delay(100);
    break; 
	case 8: //ЗА ИСТИННЫХ ЖЕНЩИН!
		lcd.setCursor(5, 0);
		lcd.print(F("НУ, ЗА"));
		lcd.setCursor(0, 1);
		lcd.print(F("ИСТИННЫХ ЖЕНЩИН!!"));
		mp3_play (10);  // Проигрываем "mp3/0010.mp3"
		delay(100);
    break;
	case 9: //ЗА ПОНИМАНИЕ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА ПОНИМАНИЕ!"));
		mp3_play (11);  // Проигрываем "mp3/0011.mp3"
		delay(100);
    break;
	case 10: //ЗА ЕДИНЕНИЕ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(2, 1);
		lcd.print(F("ЗА ЕДИНЕНИЕ!"));
		mp3_play (13);  // Проигрываем "mp3/0013.mp3"
		delay(100);
    break;
	case 11: //ЗА ПОБЕДУ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(3, 1);
		lcd.print(F("ЗА ПОБЕДУ!"));
		mp3_play (16);  // Проигрываем "mp3/0016.mp3"
		delay(100);
    break;
	case 12: //ЗА РОДИНУ!
		lcd.setCursor(7, 0);
		lcd.print(F("НУ,"));
		lcd.setCursor(3, 1);
		lcd.print(F("ЗА РОДИНУ!"));
		mp3_play (21);  // Проигрываем "mp3/0021.mp3"
		delay(100);
    break;
	case 13: //ЧТОБ ГОЛОВА НЕ ТРЕЩАЛА!
		lcd.setCursor(0, 0);
		lcd.print(F("НУ, ЧТОБ ГОЛОВА"));
		lcd.setCursor(2, 1);
		lcd.print(F("НЕ ТРЕЩАЛА!"));
		mp3_play (17);  // Проигрываем "mp3/0017.mp3"
		delay(100);
    break;
	case 14: //ЗА СОЛИДНОЕ МУЖСКОЕ МОЛЧАНИЕ
		lcd.setCursor(0, 0);
		lcd.print(F("НУ, ЗА  СОЛИДНОЕ"));//НУ,
		lcd.setCursor(0, 1);
		lcd.print(F("МУЖСКОЕ МОЛЧАНИЕ!"));
		mp3_play (12);  // Проигрываем "mp3/0012.mp3"
		delay(100);
    break;
	case 15: //ЧТОБ МОРЩИЛО НАС МЕНЬШЕ!
		lcd.setCursor(0, 0);
		lcd.print(F("НУ,ЧТОБЫ МОРЩИЛО"));
		lcd.setCursor(2, 1);
		lcd.print(F("НАС МЕНЬШЕ ЧЕМ"));
		mp3_play (18);  // Проигрываем "mp3/0018.mp3"
		delay(100);
    break;
	case 16: //ЧТОБ В СТОРОНУ НЕ ВИЛЬНУЛО!
		lcd.setCursor(0, 0);
		lcd.print(F("НУ,ЧТОБ В СТОРО-"));
		lcd.setCursor(0, 1);
		lcd.print(F("НУ НЕ  ВИЛЬНУЛО!"));
		mp3_play (19);  // Проигрываем "mp3/0019.mp3"
		delay(100);
    break; 
	case 17: //НУ ВЫ БЛИН ДАЁТЕ!
		lcd.setCursor(2, 0);
		lcd.print(F("НУ ВЫ БЛИН"));
		lcd.setCursor(5, 1);
		lcd.print(F("ДАЁТЕ!"));
		mp3_play (20);  // Проигрываем "mp3/0020.mp3"
		delay(100);	
    break; 		
	case 18: //ЗА МИР ВО ВСЕМ МИРЕ
		lcd.setCursor(5, 0);
		lcd.print(F("ЗА МИР"));
		lcd.setCursor(2, 1);
		lcd.print(F("ВО ВСЕМ МИРЕ"));  
		delay(2000);
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print(F("И БОЛЬШИЕ СИСЬКИ"));
		lcd.setCursor(5, 1);
		lcd.print("!!!!");  
    break;
	case 19: //ЗА НАС С ВАМИ
		lcd.setCursor(1, 0);
		lcd.print(F("ЗА НАС С ВАМИ"));
		lcd.setCursor(1, 1);
		lcd.print(F("И ХРЕН С НИМИ"));
		delay(100);	
    break; 	
		
  }

  //mp3_stop();
  delay(3000);
  //lcd.clear();

}


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);
  
  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.clear();   
		  lcd.setCursor(0, 0);
          lcd.print(F("П Р О М Ы В К А"));
          lcd.setCursor(2, 1);
          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("AUTO"); //Начало автоматического разлива
          oled_naliv(MenuFlag, Drink, DrinkCount); // Выводим на экран наливаем ...
          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, Drink );
            ServoParking();
            delay(1000);
            Tost();
            CvetoMuzik();
            oled_auto(Drink);
          } else {
            lcd.setCursor(7, 1);
            lcd.print(F("НЕТ РЮМОК!"));
            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("RUCHNOY" + String(DrinkCount));
          oled_naliv(MenuFlag, Drink, DrinkCount); // Выводим на экран наливаем ...
          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, Drink ); // Выводим на экран налито ...
          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;

  }
}