Секундомер есть в каждом сматрфоне, подоединяешь насос, через кнопку подаешь напряжение строго от внешнего источника которым будеш его питать, делаешь 10-20 замеров, высчитываешь среднее арифметическое. Насос 385 при питании 5В потребляет 150мА, 50 мЛ наливает в среднем за 5,5 сек.(5550 мсек)
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал "Ну начали" перед наливом , можно засунуть в процедуру oled_naliv.
"Ну начали" надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал "Ну начали" перед наливом , можно засунуть в процедуру oled_naliv.
"Ну начали" надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
Ну если один раз при включении, можно засунуть в setup
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Если речь о моем скетче то калибровка в процедуре pump_timer
delay(map(Drink, 2, 50, 300, 4000));
Здесь задается соотношение милилитров и задержки.
Т.е. в процедуру передается количество наливаемых милилитров , и с помощью команды map, пропорционально переноситься значение из милилитров в требуемую задержку.
Если устраивает диапазон от 2 до 50 мл, меняй значения 300 ( подразумевает 2 мл. ) и 4000 ( 50 мл) , остальное расчитается само .
На каждом установлен инвертирующий триггер Шмидта 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;
}
}
Теперь вообще все понятно! Вставлю пятак скетче для проверки/калибровки датчиков А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);
}
Вот простой секундомер для калибровки, насос через силоврй ключ/реле к 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
}
}
}
Добрый день всем.... У кого есть рабочий скетч с озвучкой тостов, схема подключения и список комплектующих. Хочу тоже попробовать собрать эту чудо машину ... Кто может помочь ....
А не могли бы вы помочь со схемой подключения и списком комплектующих... Я в этом не селен... Соответственно за вознаграждение.... Моя почта den260484@gmail.com Заранее спасибо
А не могли бы вы помочь со схемой подключения и списком комплектующих... Я в этом не селен... Соответственно за вознаграждение.... Моя почта den260484@gmail.com Заранее спасибо
Последняя библиотека от 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;
}
}
den-a2rh ! В скетче предоставленного stpavel все подробно описано:
-Arduino pro mini 328 5v или аналогичный;
-дисплей OLED 0,96 I2C 128x64, подключается к А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мА), через силовой ключ или реле,
подключается к 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, представить сюда, а результат обсудим.
#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
}
}
}
Да, тоже давно об этом думал. Ломать глаза на мизерном олед дисплейчике как то не айс
Заказал сегодня , жду когда придет, буду переделывать под него.
Вобще много идей , как должен будет выглядить мой будущий наливатор. Идею с поворачивающимся кранчиком отбросил, не нравиться мне она. Будет вращаться стол. Обязательно будет сосуд сверху, в который будет предварительно заливаться алкоголь. Никаких там трубочек торчащих и засунутых в бутылку. Вдохновил меня этот видос, который я выкладывал несколько сообщений назад.
это понятно, но в скетч вносятся коррективы . я пока жду комплектующие по этому ничего попробовать не могу.вот и спрашиваю может кто уже воплотил идею целиком . интересен результат
Парни, а подскажите как откалибровать насос?
Секундомер есть в каждом сматрфоне, подоединяешь насос, через кнопку подаешь напряжение строго от внешнего источника которым будеш его питать, делаешь 10-20 замеров, высчитываешь среднее арифметическое. Насос 385 при питании 5В потребляет 150мА, 50 мЛ наливает в среднем за 5,5 сек.(5550 мсек)
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал "Ну начали" перед наливом , можно засунуть в процедуру oled_naliv.
"Ну начали" надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
У меня к сожалению нет mp3 модуля, что бы проверить. Нужно что бы наливатор говорил тосты после каждого налива ? Тогда засовывать надо в процедуру Tost()
Что бы писал "Ну начали" перед наливом , можно засунуть в процедуру oled_naliv.
"Ну начали" надо програть всего один раз, после включения и подсоединения ёмкости, можно даже на дисплей не выводить.
Ну если один раз при включении, можно засунуть в setup
Ну если один раз при включении, можно засунуть в 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 байт.
Может кто в железе проверит?
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Не видел такого в скетче
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Если речь о моем скетче то калибровка в процедуре pump_timer
Здесь задается соотношение милилитров и задержки.
Т.е. в процедуру передается количество наливаемых милилитров , и с помощью команды map, пропорционально переноситься значение из милилитров в требуемую задержку.
Если устраивает диапазон от 2 до 50 мл, меняй значения 300 ( подразумевает 2 мл. ) и 4000 ( 50 мл) , остальное расчитается само .
вот и я не увидел.
да,про твой.спс. Задержка в милисекундах?
да,про твой.спс. Задержка в милисекундах?
конечно.
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 милисекунд.
в этом то и прикол.в магазине был только 360 и на 12 вольт.буду питать от 8в.я о том где в скетче прописывать калибровку.
Вот тут насос заказывал
https://amperkot.ru/msk/catalog/miniatyurnyiy_membrannyiy_nasos_385_612v-24139016.html
да я бы и с китая заказал,просто мне срочно нужен был
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
схема датчика на второй странице
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 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; } }Теперь вообще все понятно! Вставлю пятак скетче для проверки/калибровки датчиков А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); }Вот идеальная машина для разлива )
https://youtu.be/BOQM5fZi3Wg
Автор красава, просто произведение искусства ))
У Афанасьева В. много поделок в стиле стимпанк, есть подробные ворклоги на технари.ру, в эту тему видел "насТРОение", на Ютубе есть.
Парни, а подскажите как откалибровать насос?
Вот простой секундомер для калибровки, насос через силоврй ключ/реле к 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 } } }спасибо. на днях выложу систему как я расположил трубку!
короче,по человечески загрузить не получилось.кидаю ссылки на картинки реализации поворота наливной головки.
Добрый день всем.... У кого есть рабочий скетч с озвучкой тостов, схема подключения и список комплектующих. Хочу тоже попробовать собрать эту чудо машину ... Кто может помочь ....
короче,по человечески загрузить не получилось.кидаю ссылки на картинки реализации поворота наливной головки.
Нe не писающий мальчик, а так не плохо.
den-a2rh, прочитайте две последних страницы там все разъяснено. "Говорилка" пока в железе не опробована. Скетч с МП3 в 105 сообщении.
да боюсь писающего мальчика мужики не оценят
Может кто нибудь подсказать как шрифт в кейсе тост побольше сделать?
Спасибо большое за подсказку...
А не могли бы вы помочь со схемой подключения и списком комплектующих... Я в этом не селен... Соответственно за вознаграждение.... Моя почта den260484@gmail.com Заранее спасибо
Схема подключения :
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 которая просто проигрывает рандомный тост с сд карты.
В настройках нужно поправить
Код не тестировал, не на чем. тут ничего сложного , должен работать, если не будет , поправим.
#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; } }Спасибо вам большое.... Буду пробовать
Небольшая поправочка
В процедуре tost вместо
должно быть
den-a2rh ! В скетче предоставленного stpavel все подробно описано:
-Arduino pro mini 328 5v или аналогичный;
-дисплей OLED 0,96 I2C 128x64, подключается к А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мА), через силовой ключ или реле,
https://umnyjdomik.ru/silovoj-kljuch-5-a-24-v-na-polevom-tranzistore-irf520-mosfet-dlya-arduino.html
подключается к 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, представить сюда, а результат обсудим.
Спасибо большое.... Всё доступно обьяснили... Буду пробовать
а плейер есть?
На днях должен прийти с алиэкспресс... Ещё не все комплектующие пришли
den-a2rh, отправил вам на почту нарезку тостов, если кому еще понадобиться, почта моя forthomo@yandex.ru пишите.
Спасибо большое за нарезку тостов
Вот такая ерунда происходит:
// задаю на самом деле так должно быть 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серва самая дешевая. У кого какие мысли?
Поправил скетч для калибровки насоса
#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 } } }Схема под скетч с первой страницы http://arduino.ru/sites/default/files/u49308/skhema-1.jpg
может кому пригодится
Коллеги есть предложение использовать LCD 1602 I2C, на OLED шрифт мелкий, а "дедушка старенький, глазки слабенькие". Русский шрифт есть, вчера пытал.
Да, тоже давно об этом думал. Ломать глаза на мизерном олед дисплейчике как то не айс
Заказал сегодня , жду когда придет, буду переделывать под него.
Вобще много идей , как должен будет выглядить мой будущий наливатор. Идею с поворачивающимся кранчиком отбросил, не нравиться мне она. Будет вращаться стол. Обязательно будет сосуд сверху, в который будет предварительно заливаться алкоголь. Никаких там трубочек торчащих и засунутых в бутылку. Вдохновил меня этот видос, который я выкладывал несколько сообщений назад.
Да, тоже давно об этом думал. Ломать глаза на мизерном олед дисплейчике как то не айс
Помоги менюху написать для 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 байт. */Помоги менюху написать для 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; } }Павел, спасибо! Выкладываю скетч где можно посмотреть Экраны LCD:
блок с тостами
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(); }что то тема заглохла..... Может схемы хватает? кто нибудь полностью привязал скетч к железу?
что то тема заглохла..... Может схемы хватает? кто нибудь полностью привязал скетч к железу?
А какие проблемы привязки скетча к железу ? Там же все расписано к какому пину что соеденять.
это понятно, но в скетч вносятся коррективы . я пока жду комплектующие по этому ничего попробовать не могу.вот и спрашиваю может кто уже воплотил идею целиком . интересен результат
День добрый. А не перерабатывали скетч под Вашу схему?
что то тема заглохла..... Может схемы хватает? кто нибудь полностью привязал скетч к железу?
Замечания по предоставленной схеме:
питания от внутреннего стабилизатора не хватит для запитки DFPlayer и ленты.
DFPlayer - подкдючение динамика SPK1(6) SPK2 (8) (земля не используется).
паралельно конденсатору помпа включить диод (чтобы не палить контакты реле и если используется силовой ключ не спалить мосфет).
Описание в 182 сообщении.
То же жду посылку с Али с МП3, все остальное работает, осталось в культурный корпус запихнуть.
Сейчас буду собирать с ЛСД1602 дисплеем, внутренней ёмкостью на 500мЛ и тонким поворачивающимся краником.