Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Так я и прошу кусочек схемы, как Вы мосфет подключили и дальше помпу.
Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Так я и прошу кусочек схемы, как Вы мосфет подключили и дальше помпу.
Да так. Все сторонние звуки кроме тостов, при активном плеере, не воспроизводятся, иначе будет каша из прыгающих-перескакивающих треков, так спецом задумывалось. Если бы плеер умел запоминать место воспроизведения предыдущего трека, то можно было чего ни будь придумать.
Понятно! А то я вставил звуковое сопровождение наливания и решил включить плеер посмотреть, как согласуется, и да - плеер играет, звуки прочие гаснут, но я ещё не проверял с отсутствием рюмок и плеером. Думал что что-то накосячил - отключил то, что добавил, а звук так и не появился. Ок, значит всё как задумано!
Господа помогите правильно вставить код работы mp3 модуля в скеч Алекса Гайвера, просто чтоб тост озвучивался после наполнения рюмок. У меня собран такой наливатор, хотел добавить туда такую фишку.
// ======== НАСТРОЙКИ ======== #define NUM_SHOTS 4 // количество рюмок (оно же кол-во светодиодов и кнопок!) #define TIMEOUT_OFF 5 // таймаут на выключение (перестаёт дёргать привод), минут #define SWITCH_LEVEL 0 // кнопки 1 - высокий сигнал при замыкании, 0 - низкий #define INVERSE_SERVO 0 // инвертировать направление вращения серво
// положение серво над центрами рюмок const byte shotPos[] = {25, 60, 95, 145, 60, 60};
// время заполнения 50 мл const long time50ml = 5500;
#define KEEP_POWER 1 // 1 - система поддержания питания ПБ, чтобы он не спал
// отладка #define DEBUG_UART 1
// =========== ПИНЫ =========== #define PUMP_POWER 3 #define SERVO_POWER 4 #define SERVO_PIN 5 #define LED_PIN 6 #define BTN_PIN 7 #define ENC_SW 8 #define ENC_DT 9 #define ENC_CLK 10 #define DISP_DIO 11 #define DISP_CLK 12 const byte SW_pins[] = {A0, A1, A2, A3, A4, A5};
// =========== ЛИБЫ =========== #include #include #include #include #include "encUniversalMinim.h" #include "buttonMinim.h" #include "timer2Minim.h"
// =========== ДАТА =========== #define COLOR_DEBTH 2 // цветовая глубина: 1, 2, 3 (в байтах) LEDdata leds[NUM_SHOTS]; // буфер ленты типа LEDdata (размер зависит от COLOR_DEBTH) microLED strip(leds, NUM_SHOTS, LED_PIN); // объект лента
GyverTM1637 disp(DISP_CLK, DISP_DIO);
// пин clk, пин dt, пин sw, направление (0/1), тип (0/1) encMinim enc(ENC_CLK, ENC_DT, ENC_SW, 1, 1);
ServoSmooth servo;
buttonMinim btn(BTN_PIN); buttonMinim encBtn(ENC_SW); timerMinim LEDtimer(100); timerMinim FLOWdebounce(20); timerMinim FLOWtimer(2000); timerMinim WAITtimer(400); timerMinim TIMEOUTtimer(15000); // таймаут дёргания приводом timerMinim POWEROFFtimer(TIMEOUT_OFF * 60000L);
bool LEDchanged = false; bool pumping = false; int8_t curPumping = -1;
enum {NO_GLASS, EMPTY, IN_PROCESS, READY} shotStates[NUM_SHOTS]; enum {SEARCH, MOVING, WAIT, PUMPING} systemState; bool workMode = false; // 0 manual, 1 auto int thisVolume = 50; bool systemON = false; bool timeoutState = false; bool volumeChanged = false; bool parking = false;
// =========== МАКРО =========== #define servoON() digitalWrite(SERVO_POWER, 1) #define servoOFF() digitalWrite(SERVO_POWER, 0) #define pumpON() digitalWrite(PUMP_POWER, 1) #define pumpOFF() digitalWrite(PUMP_POWER, 0)
#if (DEBUG_UART == 1) #define DEBUG(x) Serial.println(x) #else #define DEBUG(x) #endif
__________________________________________________________
//вкладка void setup//
void setup() { #if (DEBUG_UART == 1) Serial.begin(9600); DEBUG("start"); #endif // епром if (EEPROM.read(1000) != 10) { EEPROM.write(1000, 10); EEPROM.put(0, thisVolume); } EEPROM.get(0, thisVolume);
// тыкаем ленту strip.setBrightness(130); strip.clear(); strip.show(); DEBUG("strip init");
// настройка пинов pinMode(PUMP_POWER, 1); pinMode(SERVO_POWER, 1); for (byte i = 0; i < NUM_SHOTS; i++) { if (SWITCH_LEVEL == 0) pinMode(SW_pins[i], INPUT_PULLUP); }
// старт дисплея disp.clear(); disp.brightness(7); DEBUG("disp init");
// настройка серво servoON(); servo.attach(SERVO_PIN, 600, 2400); if (INVERSE_SERVO) servo.setDirection(REVERSE); servo.write(0); delay(800); servo.setTargetDeg(0); servo.setSpeed(60); servo.setAccel(0.3); servoOFF();
serviceMode(); // калибровка dispMode(); // выводим на дисплей стандартные значения timeoutReset(); // сброс таймаута TIMEOUTtimer.start(); }
____________________________________________________
вкладка // луп
// луп
void loop() { encTick(); btnTick(); flowTick(); LEDtick(); timeoutTick(); }
_________________________________________________________ вкладка buttonMinim.h
// мини-класс для работы с кнопкой, версия 1.0
#pragma pack(push,1) typedef struct { bool holdedFlag: 1; bool btnFlag: 1; bool pressF: 1; bool clickF: 1; bool holdF: 1; } buttonMinimFlags; #pragma pack(pop)
class buttonMinim { public: buttonMinim(uint8_t pin); boolean pressed(); boolean clicked(); boolean holding(); boolean holded(); private: buttonMinimFlags flags; void tick(); uint32_t _btnTimer; byte _pin; };
buttonMinim::buttonMinim(uint8_t pin) { pinMode(pin, INPUT_PULLUP); _pin = pin; }
void buttonMinim::tick() { boolean btnState = digitalRead(_pin); if (!btnState && !flags.btnFlag && ((uint32_t)millis() - _btnTimer > 90)) { flags.btnFlag = true; _btnTimer = millis(); flags.pressF = true; flags.holdedFlag = true; } if (btnState && flags.btnFlag && ((uint32_t)millis() - _btnTimer < 350)) { flags.btnFlag = false; _btnTimer = millis(); flags.clickF = true; flags.holdF = false; } if (flags.btnFlag && ((uint32_t)millis() - _btnTimer > 900)) { if (!btnState) { flags.holdF = true; } else { flags.btnFlag = false; flags.holdF = false; _btnTimer = millis(); } } }
boolean buttonMinim::pressed() { buttonMinim::tick(); if (flags.pressF) { flags.pressF = false; return true; } else return false; }
boolean buttonMinim::clicked() { buttonMinim::tick(); if (flags.clickF) { flags.clickF = false; return true; } else return false; }
boolean buttonMinim::holding() { buttonMinim::tick(); if (flags.holdF) { return true; } else return false; }
boolean buttonMinim::holded() { buttonMinim::tick(); if (flags.holdF && flags.holdedFlag) { flags.holdedFlag = false; return true; } else return false; }
____________________________________________________________
вкладка c_func
// различные функции
void serviceMode() { if (!digitalRead(BTN_PIN)) { byte serviceText[] = {_S, _E, _r, _U, _i, _C, _E}; disp.runningString(serviceText, sizeof(serviceText), 150); while (!digitalRead(BTN_PIN)); // ждём отпускания delay(200); servoON(); int servoPos = 0; long pumpTime = 0; timerMinim timer100(100); disp.displayInt(0); bool flag; for (;;) { servo.tick(); enc.tick();
if (timer100.isReady()) { // период 100 мс // работа помпы со счётчиком if (!digitalRead(ENC_SW)) { if (flag) pumpTime += 100; else pumpTime = 0; disp.displayInt(pumpTime); pumpON(); flag = true; } else { pumpOFF(); flag = false; }
// зажигаем светодиоды от кнопок for (byte i = 0; i < NUM_SHOTS; i++) { if (!digitalRead(SW_pins[i])) { strip.setLED(i, mCOLOR(GREEN)); } else { strip.setLED(i, mCOLOR(BLACK)); } strip.show(); } }
if (enc.isTurn()) { // крутим серво от энкодера pumpTime = 0; if (enc.isLeft()) { servoPos += 5; } if (enc.isRight()) { servoPos -= 5; } servoPos = constrain(servoPos, 0, 180); disp.displayInt(servoPos); servo.setTargetDeg(servoPos); }
if (btn.holded()) { servo.setTargetDeg(0); break; } } } disp.clear(); while (!servo.tick()); servoOFF(); }
// выводим объём и режим void dispMode() { disp.displayInt(thisVolume); if (workMode) disp.displayByte(0, _A); else { disp.displayByte(0, _P); pumpOFF(); } }
// наливайка, опрос кнопок void flowTick() { if (FLOWdebounce.isReady()) { for (byte i = 0; i < NUM_SHOTS; i++) { bool swState = !digitalRead(SW_pins[i]) ^ SWITCH_LEVEL; if (swState && shotStates[i] == NO_GLASS) { // поставили пустую рюмку timeoutReset(); // сброс таймаута shotStates[i] = EMPTY; // флаг на заправку strip.setLED(i, mCOLOR(RED)); // подсветили LEDchanged = true; DEBUG("set glass"); DEBUG(i); } if (!swState && shotStates[i] != NO_GLASS) { // убрали пустую/полную рюмку shotStates[i] = NO_GLASS; // статус - нет рюмки strip.setLED(i, mCOLOR(BLACK)); // нигра LEDchanged = true; timeoutReset(); // сброс таймаута if (i == curPumping) { curPumping = -1; // снимаем выбор рюмки systemState = WAIT; // режим работы - ждать WAITtimer.reset(); pumpOFF(); // помпу выкл } DEBUG("take glass"); DEBUG(i); } }
if (workMode) { // авто flowRoutnie(); // крутим отработку кнопок и поиск рюмок } else { // ручной if (btn.clicked()) { // клик! systemON = true; // система активирована timeoutReset(); // таймаут сброшен } if (systemON) flowRoutnie(); // если активны - ищем рюмки и всё такое } } }
// поиск и заливка void flowRoutnie() { if (systemState == SEARCH) { // если поиск рюмки bool noGlass = true; for (byte i = 0; i < NUM_SHOTS; i++) { if (shotStates[i] == EMPTY && i != curPumping) { // поиск noGlass = false; // флаг что нашли хоть одну рюмку parking = false; curPumping = i; // запоминаем выбор systemState = MOVING; // режим - движение shotStates[curPumping] = IN_PROCESS; // стакан в режиме заполнения servoON(); // вкл питание серво servo.attach(); servo.setTargetDeg(shotPos[curPumping]); // задаём цель DEBUG("find glass"); DEBUG(curPumping); break; } } if (noGlass && !parking) { // если не нашли ни одной рюмки servoON(); servo.setTargetDeg(0); // цель серво - 0 if (servo.tick()) { // едем до упора servoOFF(); // выключили серво systemON = false; // выключили систему parking = true; DEBUG("no glass"); } } } else if (systemState == MOVING) { // движение к рюмке if (servo.tick()) { // если приехали systemState = PUMPING; // режим - наливание FLOWtimer.setInterval((long)thisVolume * time50ml / 50); // перенастроили таймер FLOWtimer.reset(); // сброс таймера pumpON(); // НАЛИВАЙ! strip.setLED(curPumping, mCOLOR(YELLOW)); // зажгли цвет strip.show(); DEBUG("fill glass"); DEBUG(curPumping); }
} else if (systemState == PUMPING) { // если качаем if (FLOWtimer.isReady()) { // если налили (таймер) pumpOFF(); // помпа выкл shotStates[curPumping] = READY; // налитая рюмка, статус: готов strip.setLED(curPumping, mCOLOR(LIME)); // подсветили strip.show(); curPumping = -1; // снимаем выбор рюмки systemState = WAIT; // режим работы - ждать WAITtimer.reset(); DEBUG("wait"); } } else if (systemState == WAIT) { if (WAITtimer.isReady()) { // подождали после наливания systemState = SEARCH; timeoutReset(); DEBUG("search"); } } }
// отрисовка светодиодов по флагу (100мс) void LEDtick() { if (LEDchanged && LEDtimer.isReady()) { LEDchanged = false; strip.show(); } }
// сброс таймаута void timeoutReset() { if (!timeoutState) disp.brightness(7); timeoutState = true; TIMEOUTtimer.reset(); TIMEOUTtimer.start(); DEBUG("timeout reset"); }
// сам таймаут void timeoutTick() { if (systemState == SEARCH && timeoutState && TIMEOUTtimer.isReady()) { DEBUG("timeout"); timeoutState = false; disp.brightness(1); POWEROFFtimer.reset(); jerkServo(); if (volumeChanged) { volumeChanged = false; EEPROM.put(0, thisVolume); } }
// дёргаем питание серво, это приводит к скачку тока и powerbank не отключает систему if (!timeoutState && TIMEOUTtimer.isReady()) { if (!POWEROFFtimer.isReady()) { // пока не сработал таймер полного отключения jerkServo(); } else { disp.clear(); } } }
void jerkServo() { if (KEEP_POWER) { disp.brightness(7); servoON(); servo.attach(); servo.write(random(0, 4)); delay(200); servo.detach(); servoOFF(); disp.brightness(1); } }
_____________________________________________________________________
вкладка d_control
// кнопки-крутилки
void encTick() { enc.tick(); if (enc.isTurn()) { volumeChanged = true; timeoutReset(); if (enc.isLeft()) { thisVolume += 5; thisVolume = constrain(thisVolume, 5, 1000); } if (enc.isRight()) { thisVolume -= 5; thisVolume = constrain(thisVolume, 5, 1000); } dispMode(); } }
void btnTick() { if (btn.holded()) { timeoutReset(); workMode = !workMode; dispMode(); } if (encBtn.holded()) { pumpON(); while (!digitalRead(ENC_SW)); timeoutReset(); pumpOFF(); } }
____________________________________________________________________
вкладка encUniversalMinin.h
// мини-класс для работы с энкодером, версия 1.0
class encMinim { public: encMinim(uint8_t clk, uint8_t dt, uint8_t sw, boolean dir, boolean type); void tick(); boolean isClick(); boolean isTurn(); boolean isRight(); boolean isLeft(); boolean isRightH(); boolean isLeftH();
private: byte _clk, _dt, _sw; boolean _type = false; boolean _state, _lastState, _turnFlag, _swState, _swFlag, _turnState; byte _encState; uint32_t _debTimer; // 0 - ничего, 1 - лево, 2 - право, 3 - правоНажат, 4 - левоНажат };
encMinim::encMinim(uint8_t clk, uint8_t dt, uint8_t sw, boolean dir, boolean type) { if (dir) { _clk = clk; _dt = dt; } else { _clk = dt; _dt = clk; } _sw = sw; _type = type; pinMode (_clk, INPUT); pinMode (_dt, INPUT); pinMode (_sw, INPUT_PULLUP); _lastState = digitalRead(_clk); }
void encMinim::tick() { _encState = 0; _state = digitalRead(_clk); _swState = digitalRead(_sw);
if (_state != _lastState) { _turnState = true; _turnFlag = !_turnFlag; if (_turnFlag || !_type) { if (digitalRead(_dt) != _lastState) { if (_swState) _encState = 1; else _encState = 3; } else { if (_swState) _encState = 2; else _encState = 4; } } _lastState = _state; }
if (!_swState && !_swFlag && millis() - _debTimer > 80) { _debTimer = millis(); _swFlag = true; _turnState = false; } if (_swState && _swFlag && millis() - _debTimer > 80) { _debTimer = millis(); _swFlag = false; if (!_turnState) _encState = 5; } } boolean encMinim::isTurn() { if (_encState > 0 && _encState < 5) { return true; } else return false; } boolean encMinim::isRight() { if (_encState == 1) { _encState = 0; return true; } else return false; } boolean encMinim::isLeft() { if (_encState == 2) { _encState = 0; return true; } else return false; } boolean encMinim::isRightH() { if (_encState == 3) { _encState = 0; return true; } else return false; } boolean encMinim::isLeftH() { if (_encState == 4) { _encState = 0; return true; } else return false; } boolean encMinim::isClick() { if (_encState == 5) { _encState = 0; return true; } else return false; }
___________________________________________
вкладка timer2Minim.h
// мини-класс таймера, версия 2.0 // использован улучшенный алгоритм таймера на millis // алгоритм чуть медленнее, но обеспечивает кратные интервалы и защиту от пропусков и переполнений
class timerMinim { public: timerMinim(uint32_t interval); // объявление таймера с указанием интервала void setInterval(uint32_t interval); // установка интервала работы таймера boolean isReady(); // возвращает true, когда пришло время. Сбрасывается в false сам (AUTO) или вручную (MANUAL) void reset(); // ручной сброс таймера на установленный интервал void stop(); void start();
private: uint32_t _timer = 0; uint32_t _interval = 0; bool _status = true; };
timerMinim::timerMinim(uint32_t interval) { _interval = interval; _timer = millis(); }
void timerMinim::setInterval(uint32_t interval) { _interval = (interval == 0) ? 10 : interval; }
void timerMinim::start() { _status = true; _timer = millis(); }
void timerMinim::stop() { _status = false; }
// алгоритм таймера v2.0 boolean timerMinim::isReady() { uint32_t thisMls = millis(); if (_status && thisMls - _timer >= _interval) { do { _timer += _interval; if (_timer < _interval) break; // переполнение uint32_t } while (_timer < thisMls - _interval); // защита от пропуска шага return true; } else { return false; } }
void timerMinim::reset() { _timer = millis(); }
Блин, после включения опции проигрывания звука во время налива, при проверке обнаружилось, что этот звук так же включается в режиме промывки, причём играет только первый раз, но играет без остановки в момент отпускания кнопки - перешибается другим действием (установка стопки, нажатие кнопки). В последующие разы при запуске промывки звук больше не проигрывается.
Добавил воспроизведение трека при розливе. 18 трек добавлен в папку mp3, спасибо Acket. Надо тестить.
Сделал отключение, на этапе компиляции, в скетче всего, что связанно с батареей, некоторые делают без АКБ.
Изменил пункт настроек бармен, теперь бармен-долив. Добавил сохраняемую опцию долив. Если в момент розлива, пока разливной кран не уехал в нулевую позицию, убирать и снова устанавливать стопки на места, то разлив может длиться бесконечно))). Опция долив как раз отключает это и розлив будет идти только в установленные стопки не зависимо от того были ли добавлены стопки в процессе, т.е. максимум 6 стопок.
Косяк с калибровкой серво исправил, перезалил 33 скетч.
Про запись громкости надо подумать, да и в какой момент её записывать, если после каждого изменения в меню плеера, то дыру протрём в eeprom))). Скорее всего сделаю запись после выхода из меню плеера.
Долив можно проверить так, ставим стопку в центре одну, нажимаем налив, кран пошёл к этой стопке, идёт налив, ставим в это время другую стопку на первую позицию, если кран стал наливать и её после, то долив включен, если нет то выключен
Добрый день, Уважаемый! могли бы вы поделиться своим проектом? Как понимаю Вы закрыли ссылки на яндексе. Вот мой email: bereznyak1612@gmail.com , спасибо!
Если управление идёт низким уровнем(так делать правильней), то резисторы не нужны, сделана подтяжка к плюсу в самой ардуино. Высоким уровнем у меня управляется идёт через сенсоры, то резисторы тоже не нужны, если всё же делать так через концевики, то резистор подтягиваем к минусу уже.
Кондёр ставить нужно на всю схему питания по 5 вольтам, от которых запитываем и серву.
raven, я собрал наливатор для 5-ти рюмок и на ик датчиках, так что пришлось по колдовать над твоей прошивкой (я не программист, я только учусь, хотя мне уже 45). Я добавил в меню настройки "настройка ик датчика" для каждой рюмки для изменения порога срабатывания, так как при подключении их на на ноль или единицу нет возможности регулировки. Возле окна срабатывают :(, а после регулировки - нет :). Пришлось использовать всё таки аналоговый пин А6, не знаю как это повлияет на работу плеера - не пробовал. А вообще прошивка супер!!! СПАСИБО :)
Пришлось использовать всё таки аналоговый пин А6, не знаю как это повлияет на работу плеера - не пробовал. А вообще прошивка супер!!! СПАСИБО :)
В принципе ничего критичного, надо посмотреть как будет с рандомом тостов, вероятно стартовать будет всегда с одного и того же .
Обновил мальца скетч, добавил запись громкости плеера в память, как и договаривались))). Чего то мудрил с меню плеера и другими меню, избавлялся от моргания дисплея )))
Во вкладку a_setup добавил во вторую строку параметр для корректировки углов серво, нужно раскомментировать строку
raven78,Роман ты ваще красавчик!Скетч постоянно доводишь,людям все разжевываешь досконально.Спасибо огромное друг.За твою работу и донат не жалко.Выложи реквизиты,думаю те люди кто пользуется твоей прошивкой отблагодарят тебя,ведь работа выполнена великолепно и постоянно обновляется. Если не тут то хотя бы в прошивке оставь данные. Так держать дружище!.
при калибровке помпы все рюмки на местах, но говорит нет рюмок. и при промывке... Уровень датчиков стоит 0
в остальных местах стопки видит, и наливает...
хотя при повторном включении устройства промывка сработала, но потом перешёл на калибровку помпы, рюмку не убирал, соответственно обругалось на это, затем снял и обратно поставил - всё равно, говорит, нет рюмок. затем перевключил устройство, сразу пошёл в калибровку помпы, поставил пустую рюмку - пошла работать помпа.Переставил в другое место - работает. как только повторилась ситуация с отсутствием рюмки, дальше она повторяется независимо от снятия стопок...
Доброго дня! Хочу спросить - для таймера сна можно указать как-то, что активность с установкой стопок - это активность, во время которой засыпать не нужно? Сейчас можно поставить стопку и следом идёт переход в сон
Да, протестировал и оказалось, что все тосты идут в определённой последовательности и после перезагрузки все с начало ;(
Нашел в нете какой то генератор случайных чисел, тем самым освобождаем аналоговый пин от участия в рандоме. Рандом стал более случайным, он нужен для перемешивания тостов в случайном порядке и для мушкетёров. НУЖНО ПРОБОВАТЬ)))).
Acket пишет:
Доброго дня! Хочу спросить - для таймера сна можно указать как-то, что активность с установкой стопок - это активность, во время которой засыпать не нужно? Сейчас можно поставить стопку и следом идёт переход в сон
Приветствую всех, хочу еще раз поднять тему по оптодатчикам, чтобы светодиод излучал свет импульсами с частотой допустим 100 герц, и ардуино срабатывало только если с фотоприемника поступал такой же сигнал, соответственно от солнца не будет ошибочных сработок, но как это программно реализовать я не знаю, так как больше с паяльником дружу, и нигде про это сильно не описано
Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Так я и прошу кусочек схемы, как Вы мосфет подключили и дальше помпу.
Детали для замера напряжения АКБ, если нет батареи, то и не надо. Строчку в начале скетча закомментируйте и не ставьте. Мосфет хорошо работает. У меня на нём.
Так я и прошу кусочек схемы, как Вы мосфет подключили и дальше помпу.
Извиняюсь, несколько раз отправил.
сигнальный мосфета на управляющий контроллера, входы на питание, выходы на помпу... там ничего военного
Во вкладке c_func вставляем в этот блок
Подскажи, флаг такого типа?
bool myFlag = false; if(!imyFlag) { // моя функция myFlag = true; }Да с флагами... Тут бы уточнить как должно быть... Для тех, кто в танке :)) Для меня это просто фраза на другом языке...
Да именно так, объявляем флаг, в начале скетча, где объявлены все переменные
далее в указанном месте
if(!imyFlag) { // старт трека myFlag = true; }после остановки трека приводим этот флаг в
чтобы при следующем цикле розлива, опять начал играть трек
Так я и прошу кусочек схемы, как Вы мосфет подключили и дальше помпу.
Вот так правильно помпу подключать. В мосфете вроде стрелочка не туды, но не суть, принцип понятен.
Raven спасибо огромное! Нам бы только пальцем показать :))
про мосфет, я имел в виду тот, что модулем продают:
Заметил, что при работающем плеере, не проигрывается звук отсутствующих рюмок.
Да так. Все сторонние звуки кроме тостов, при активном плеере, не воспроизводятся, иначе будет каша из прыгающих-перескакивающих треков, так спецом задумывалось. Если бы плеер умел запоминать место воспроизведения предыдущего трека, то можно было чего ни будь придумать.
Понятно! А то я вставил звуковое сопровождение наливания и решил включить плеер посмотреть, как согласуется, и да - плеер играет, звуки прочие гаснут, но я ещё не проверял с отсутствием рюмок и плеером. Думал что что-то накосячил - отключил то, что добавил, а звук так и не появился. Ок, значит всё как задумано!
Господа помогите правильно вставить код работы mp3 модуля в скеч Алекса Гайвера, просто чтоб тост озвучивался после наполнения рюмок. У меня собран такой наливатор, хотел добавить туда такую фишку.
// ======== НАСТРОЙКИ ======== #define NUM_SHOTS 4 // количество рюмок (оно же кол-во светодиодов и кнопок!) #define TIMEOUT_OFF 5 // таймаут на выключение (перестаёт дёргать привод), минут #define SWITCH_LEVEL 0 // кнопки 1 - высокий сигнал при замыкании, 0 - низкий #define INVERSE_SERVO 0 // инвертировать направление вращения серво // положение серво над центрами рюмок const byte shotPos[] = {25, 60, 95, 145, 60, 60}; // время заполнения 50 мл const long time50ml = 5500; #define KEEP_POWER 1 // 1 - система поддержания питания ПБ, чтобы он не спал // отладка #define DEBUG_UART 1 // =========== ПИНЫ =========== #define PUMP_POWER 3 #define SERVO_POWER 4 #define SERVO_PIN 5 #define LED_PIN 6 #define BTN_PIN 7 #define ENC_SW 8 #define ENC_DT 9 #define ENC_CLK 10 #define DISP_DIO 11 #define DISP_CLK 12 const byte SW_pins[] = {A0, A1, A2, A3, A4, A5}; // =========== ЛИБЫ =========== #include #include #include #include #include "encUniversalMinim.h" #include "buttonMinim.h" #include "timer2Minim.h" // =========== ДАТА =========== #define COLOR_DEBTH 2 // цветовая глубина: 1, 2, 3 (в байтах) LEDdata leds[NUM_SHOTS]; // буфер ленты типа LEDdata (размер зависит от COLOR_DEBTH) microLED strip(leds, NUM_SHOTS, LED_PIN); // объект лента GyverTM1637 disp(DISP_CLK, DISP_DIO); // пин clk, пин dt, пин sw, направление (0/1), тип (0/1) encMinim enc(ENC_CLK, ENC_DT, ENC_SW, 1, 1); ServoSmooth servo; buttonMinim btn(BTN_PIN); buttonMinim encBtn(ENC_SW); timerMinim LEDtimer(100); timerMinim FLOWdebounce(20); timerMinim FLOWtimer(2000); timerMinim WAITtimer(400); timerMinim TIMEOUTtimer(15000); // таймаут дёргания приводом timerMinim POWEROFFtimer(TIMEOUT_OFF * 60000L); bool LEDchanged = false; bool pumping = false; int8_t curPumping = -1; enum {NO_GLASS, EMPTY, IN_PROCESS, READY} shotStates[NUM_SHOTS]; enum {SEARCH, MOVING, WAIT, PUMPING} systemState; bool workMode = false; // 0 manual, 1 auto int thisVolume = 50; bool systemON = false; bool timeoutState = false; bool volumeChanged = false; bool parking = false; // =========== МАКРО =========== #define servoON() digitalWrite(SERVO_POWER, 1) #define servoOFF() digitalWrite(SERVO_POWER, 0) #define pumpON() digitalWrite(PUMP_POWER, 1) #define pumpOFF() digitalWrite(PUMP_POWER, 0) #if (DEBUG_UART == 1) #define DEBUG(x) Serial.println(x) #else #define DEBUG(x) #endif __________________________________________________________ //вкладка void setup// void setup() { #if (DEBUG_UART == 1) Serial.begin(9600); DEBUG("start"); #endif // епром if (EEPROM.read(1000) != 10) { EEPROM.write(1000, 10); EEPROM.put(0, thisVolume); } EEPROM.get(0, thisVolume); // тыкаем ленту strip.setBrightness(130); strip.clear(); strip.show(); DEBUG("strip init"); // настройка пинов pinMode(PUMP_POWER, 1); pinMode(SERVO_POWER, 1); for (byte i = 0; i < NUM_SHOTS; i++) { if (SWITCH_LEVEL == 0) pinMode(SW_pins[i], INPUT_PULLUP); } // старт дисплея disp.clear(); disp.brightness(7); DEBUG("disp init"); // настройка серво servoON(); servo.attach(SERVO_PIN, 600, 2400); if (INVERSE_SERVO) servo.setDirection(REVERSE); servo.write(0); delay(800); servo.setTargetDeg(0); servo.setSpeed(60); servo.setAccel(0.3); servoOFF(); serviceMode(); // калибровка dispMode(); // выводим на дисплей стандартные значения timeoutReset(); // сброс таймаута TIMEOUTtimer.start(); } ____________________________________________________ вкладка // луп // луп void loop() { encTick(); btnTick(); flowTick(); LEDtick(); timeoutTick(); } _________________________________________________________ вкладка buttonMinim.h // мини-класс для работы с кнопкой, версия 1.0 #pragma pack(push,1) typedef struct { bool holdedFlag: 1; bool btnFlag: 1; bool pressF: 1; bool clickF: 1; bool holdF: 1; } buttonMinimFlags; #pragma pack(pop) class buttonMinim { public: buttonMinim(uint8_t pin); boolean pressed(); boolean clicked(); boolean holding(); boolean holded(); private: buttonMinimFlags flags; void tick(); uint32_t _btnTimer; byte _pin; }; buttonMinim::buttonMinim(uint8_t pin) { pinMode(pin, INPUT_PULLUP); _pin = pin; } void buttonMinim::tick() { boolean btnState = digitalRead(_pin); if (!btnState && !flags.btnFlag && ((uint32_t)millis() - _btnTimer > 90)) { flags.btnFlag = true; _btnTimer = millis(); flags.pressF = true; flags.holdedFlag = true; } if (btnState && flags.btnFlag && ((uint32_t)millis() - _btnTimer < 350)) { flags.btnFlag = false; _btnTimer = millis(); flags.clickF = true; flags.holdF = false; } if (flags.btnFlag && ((uint32_t)millis() - _btnTimer > 900)) { if (!btnState) { flags.holdF = true; } else { flags.btnFlag = false; flags.holdF = false; _btnTimer = millis(); } } } boolean buttonMinim::pressed() { buttonMinim::tick(); if (flags.pressF) { flags.pressF = false; return true; } else return false; } boolean buttonMinim::clicked() { buttonMinim::tick(); if (flags.clickF) { flags.clickF = false; return true; } else return false; } boolean buttonMinim::holding() { buttonMinim::tick(); if (flags.holdF) { return true; } else return false; } boolean buttonMinim::holded() { buttonMinim::tick(); if (flags.holdF && flags.holdedFlag) { flags.holdedFlag = false; return true; } else return false; } ____________________________________________________________ вкладка c_func // различные функции void serviceMode() { if (!digitalRead(BTN_PIN)) { byte serviceText[] = {_S, _E, _r, _U, _i, _C, _E}; disp.runningString(serviceText, sizeof(serviceText), 150); while (!digitalRead(BTN_PIN)); // ждём отпускания delay(200); servoON(); int servoPos = 0; long pumpTime = 0; timerMinim timer100(100); disp.displayInt(0); bool flag; for (;;) { servo.tick(); enc.tick(); if (timer100.isReady()) { // период 100 мс // работа помпы со счётчиком if (!digitalRead(ENC_SW)) { if (flag) pumpTime += 100; else pumpTime = 0; disp.displayInt(pumpTime); pumpON(); flag = true; } else { pumpOFF(); flag = false; } // зажигаем светодиоды от кнопок for (byte i = 0; i < NUM_SHOTS; i++) { if (!digitalRead(SW_pins[i])) { strip.setLED(i, mCOLOR(GREEN)); } else { strip.setLED(i, mCOLOR(BLACK)); } strip.show(); } } if (enc.isTurn()) { // крутим серво от энкодера pumpTime = 0; if (enc.isLeft()) { servoPos += 5; } if (enc.isRight()) { servoPos -= 5; } servoPos = constrain(servoPos, 0, 180); disp.displayInt(servoPos); servo.setTargetDeg(servoPos); } if (btn.holded()) { servo.setTargetDeg(0); break; } } } disp.clear(); while (!servo.tick()); servoOFF(); } // выводим объём и режим void dispMode() { disp.displayInt(thisVolume); if (workMode) disp.displayByte(0, _A); else { disp.displayByte(0, _P); pumpOFF(); } } // наливайка, опрос кнопок void flowTick() { if (FLOWdebounce.isReady()) { for (byte i = 0; i < NUM_SHOTS; i++) { bool swState = !digitalRead(SW_pins[i]) ^ SWITCH_LEVEL; if (swState && shotStates[i] == NO_GLASS) { // поставили пустую рюмку timeoutReset(); // сброс таймаута shotStates[i] = EMPTY; // флаг на заправку strip.setLED(i, mCOLOR(RED)); // подсветили LEDchanged = true; DEBUG("set glass"); DEBUG(i); } if (!swState && shotStates[i] != NO_GLASS) { // убрали пустую/полную рюмку shotStates[i] = NO_GLASS; // статус - нет рюмки strip.setLED(i, mCOLOR(BLACK)); // нигра LEDchanged = true; timeoutReset(); // сброс таймаута if (i == curPumping) { curPumping = -1; // снимаем выбор рюмки systemState = WAIT; // режим работы - ждать WAITtimer.reset(); pumpOFF(); // помпу выкл } DEBUG("take glass"); DEBUG(i); } } if (workMode) { // авто flowRoutnie(); // крутим отработку кнопок и поиск рюмок } else { // ручной if (btn.clicked()) { // клик! systemON = true; // система активирована timeoutReset(); // таймаут сброшен } if (systemON) flowRoutnie(); // если активны - ищем рюмки и всё такое } } } // поиск и заливка void flowRoutnie() { if (systemState == SEARCH) { // если поиск рюмки bool noGlass = true; for (byte i = 0; i < NUM_SHOTS; i++) { if (shotStates[i] == EMPTY && i != curPumping) { // поиск noGlass = false; // флаг что нашли хоть одну рюмку parking = false; curPumping = i; // запоминаем выбор systemState = MOVING; // режим - движение shotStates[curPumping] = IN_PROCESS; // стакан в режиме заполнения servoON(); // вкл питание серво servo.attach(); servo.setTargetDeg(shotPos[curPumping]); // задаём цель DEBUG("find glass"); DEBUG(curPumping); break; } } if (noGlass && !parking) { // если не нашли ни одной рюмки servoON(); servo.setTargetDeg(0); // цель серво - 0 if (servo.tick()) { // едем до упора servoOFF(); // выключили серво systemON = false; // выключили систему parking = true; DEBUG("no glass"); } } } else if (systemState == MOVING) { // движение к рюмке if (servo.tick()) { // если приехали systemState = PUMPING; // режим - наливание FLOWtimer.setInterval((long)thisVolume * time50ml / 50); // перенастроили таймер FLOWtimer.reset(); // сброс таймера pumpON(); // НАЛИВАЙ! strip.setLED(curPumping, mCOLOR(YELLOW)); // зажгли цвет strip.show(); DEBUG("fill glass"); DEBUG(curPumping); } } else if (systemState == PUMPING) { // если качаем if (FLOWtimer.isReady()) { // если налили (таймер) pumpOFF(); // помпа выкл shotStates[curPumping] = READY; // налитая рюмка, статус: готов strip.setLED(curPumping, mCOLOR(LIME)); // подсветили strip.show(); curPumping = -1; // снимаем выбор рюмки systemState = WAIT; // режим работы - ждать WAITtimer.reset(); DEBUG("wait"); } } else if (systemState == WAIT) { if (WAITtimer.isReady()) { // подождали после наливания systemState = SEARCH; timeoutReset(); DEBUG("search"); } } } // отрисовка светодиодов по флагу (100мс) void LEDtick() { if (LEDchanged && LEDtimer.isReady()) { LEDchanged = false; strip.show(); } } // сброс таймаута void timeoutReset() { if (!timeoutState) disp.brightness(7); timeoutState = true; TIMEOUTtimer.reset(); TIMEOUTtimer.start(); DEBUG("timeout reset"); } // сам таймаут void timeoutTick() { if (systemState == SEARCH && timeoutState && TIMEOUTtimer.isReady()) { DEBUG("timeout"); timeoutState = false; disp.brightness(1); POWEROFFtimer.reset(); jerkServo(); if (volumeChanged) { volumeChanged = false; EEPROM.put(0, thisVolume); } } // дёргаем питание серво, это приводит к скачку тока и powerbank не отключает систему if (!timeoutState && TIMEOUTtimer.isReady()) { if (!POWEROFFtimer.isReady()) { // пока не сработал таймер полного отключения jerkServo(); } else { disp.clear(); } } } void jerkServo() { if (KEEP_POWER) { disp.brightness(7); servoON(); servo.attach(); servo.write(random(0, 4)); delay(200); servo.detach(); servoOFF(); disp.brightness(1); } } _____________________________________________________________________ вкладка d_control // кнопки-крутилки void encTick() { enc.tick(); if (enc.isTurn()) { volumeChanged = true; timeoutReset(); if (enc.isLeft()) { thisVolume += 5; thisVolume = constrain(thisVolume, 5, 1000); } if (enc.isRight()) { thisVolume -= 5; thisVolume = constrain(thisVolume, 5, 1000); } dispMode(); } } void btnTick() { if (btn.holded()) { timeoutReset(); workMode = !workMode; dispMode(); } if (encBtn.holded()) { pumpON(); while (!digitalRead(ENC_SW)); timeoutReset(); pumpOFF(); } } ____________________________________________________________________ вкладка encUniversalMinin.h // мини-класс для работы с энкодером, версия 1.0 class encMinim { public: encMinim(uint8_t clk, uint8_t dt, uint8_t sw, boolean dir, boolean type); void tick(); boolean isClick(); boolean isTurn(); boolean isRight(); boolean isLeft(); boolean isRightH(); boolean isLeftH(); private: byte _clk, _dt, _sw; boolean _type = false; boolean _state, _lastState, _turnFlag, _swState, _swFlag, _turnState; byte _encState; uint32_t _debTimer; // 0 - ничего, 1 - лево, 2 - право, 3 - правоНажат, 4 - левоНажат }; encMinim::encMinim(uint8_t clk, uint8_t dt, uint8_t sw, boolean dir, boolean type) { if (dir) { _clk = clk; _dt = dt; } else { _clk = dt; _dt = clk; } _sw = sw; _type = type; pinMode (_clk, INPUT); pinMode (_dt, INPUT); pinMode (_sw, INPUT_PULLUP); _lastState = digitalRead(_clk); } void encMinim::tick() { _encState = 0; _state = digitalRead(_clk); _swState = digitalRead(_sw); if (_state != _lastState) { _turnState = true; _turnFlag = !_turnFlag; if (_turnFlag || !_type) { if (digitalRead(_dt) != _lastState) { if (_swState) _encState = 1; else _encState = 3; } else { if (_swState) _encState = 2; else _encState = 4; } } _lastState = _state; } if (!_swState && !_swFlag && millis() - _debTimer > 80) { _debTimer = millis(); _swFlag = true; _turnState = false; } if (_swState && _swFlag && millis() - _debTimer > 80) { _debTimer = millis(); _swFlag = false; if (!_turnState) _encState = 5; } } boolean encMinim::isTurn() { if (_encState > 0 && _encState < 5) { return true; } else return false; } boolean encMinim::isRight() { if (_encState == 1) { _encState = 0; return true; } else return false; } boolean encMinim::isLeft() { if (_encState == 2) { _encState = 0; return true; } else return false; } boolean encMinim::isRightH() { if (_encState == 3) { _encState = 0; return true; } else return false; } boolean encMinim::isLeftH() { if (_encState == 4) { _encState = 0; return true; } else return false; } boolean encMinim::isClick() { if (_encState == 5) { _encState = 0; return true; } else return false; } ___________________________________________ вкладка timer2Minim.h // мини-класс таймера, версия 2.0 // использован улучшенный алгоритм таймера на millis // алгоритм чуть медленнее, но обеспечивает кратные интервалы и защиту от пропусков и переполнений class timerMinim { public: timerMinim(uint32_t interval); // объявление таймера с указанием интервала void setInterval(uint32_t interval); // установка интервала работы таймера boolean isReady(); // возвращает true, когда пришло время. Сбрасывается в false сам (AUTO) или вручную (MANUAL) void reset(); // ручной сброс таймера на установленный интервал void stop(); void start(); private: uint32_t _timer = 0; uint32_t _interval = 0; bool _status = true; }; timerMinim::timerMinim(uint32_t interval) { _interval = interval; _timer = millis(); } void timerMinim::setInterval(uint32_t interval) { _interval = (interval == 0) ? 10 : interval; } void timerMinim::start() { _status = true; _timer = millis(); } void timerMinim::stop() { _status = false; } // алгоритм таймера v2.0 boolean timerMinim::isReady() { uint32_t thisMls = millis(); if (_status && thisMls - _timer >= _interval) { do { _timer += _interval; if (_timer < _interval) break; // переполнение uint32_t } while (_timer < thisMls - _interval); // защита от пропуска шага return true; } else { return false; } } void timerMinim::reset() { _timer = millis(); }Подскажите где скачать 32 версию скетча?
предыдущая страница. 2614 сообщение
Блин, после включения опции проигрывания звука во время налива, при проверке обнаружилось, что этот звук так же включается в режиме промывки, причём играет только первый раз, но играет без остановки в момент отпускания кнопки - перешибается другим действием (установка стопки, нажатие кнопки). В последующие разы при запуске промывки звук больше не проигрывается.
Значит надо так
if(!imyFlag && !promivka) { // старт трека myFlag = true; }флаг промывки уже есть в скетче.
Нужно чтобы при промывке не проигрывался совсем, не нужен он там... Тогда написать в этом месте false?
1if(!imyFlag && !promivka) {23myFlag = false;4}Всё так и будет, надо делать, как в сообщении 2666 и ничего более.
Спасибо! Попробую! Это же там же, где звук трека прописывал изначально?
P.S. Замечательно!!!
Добавил воспроизведение трека при розливе. 18 трек добавлен в папку mp3, спасибо Acket. Надо тестить.
Сделал отключение, на этапе компиляции, в скетче всего, что связанно с батареей, некоторые делают без АКБ.
Изменил пункт настроек бармен, теперь бармен-долив. Добавил сохраняемую опцию долив. Если в момент розлива, пока разливной кран не уехал в нулевую позицию, убирать и снова устанавливать стопки на места, то разлив может длиться бесконечно))). Опция долив как раз отключает это и розлив будет идти только в установленные стопки не зависимо от того были ли добавлены стопки в процессе, т.е. максимум 6 стопок.
33 скетч
Как хорошо жить!!! А хорошо жить ещё лучче!! Спасибо!!
Прошил. Очень сильно всё перелопачено внутри кода - большая работа!
На первый взгляд:
Режим калибровка сервы во время калибровки выводит координаты только после вращения энкодера, иначе предыдущее значение показывает.
С новым барменом идея понятна, но, мне кажется, что долив, что включен, что выключен - одинаково...
А запись громкости плеера в епром было бы тоже полезно!
Косяк с калибровкой серво исправил, перезалил 33 скетч.
Про запись громкости надо подумать, да и в какой момент её записывать, если после каждого изменения в меню плеера, то дыру протрём в eeprom))). Скорее всего сделаю запись после выхода из меню плеера.
Долив можно проверить так, ставим стопку в центре одну, нажимаем налив, кран пошёл к этой стопке, идёт налив, ставим в это время другую стопку на первую позицию, если кран стал наливать и её после, то долив включен, если нет то выключен
Запись же можно сделать только тогда, когда значение громкости изменено и осуществлён выход из меню? Или нет?
Роман,(raven78) а можно вашу почту,хотелось бы с вами связаться, есть несколько вопросов
Да так и будет.
Роман,(raven78) а можно вашу почту,хотелось бы с вами связаться, есть несколько вопросов
ravenrv78@mail.ru
Куда поделиться?
Добрый день, Уважаемый! могли бы вы поделиться своим проектом? Как понимаю Вы закрыли ссылки на яндексе. Вот мой email: bereznyak1612@gmail.com , спасибо!
парни а схемку с концевиками можно
Докладываю...
С прискорбием...
https://aliexpress.ru/item/32962993969.html?spm=a2g0s.9042311.0.0.365333...
норм работает около часа стоял без перебоев
Получил сегодня с этой ссылки... те же яйца, только в профиль... 8-10сек и отрубается.
Другие меню работают без проблем. TTP перепаивалhttps://aliexpress.ru/item/33041395708.html?spm=a2g0o.detail.1000014.3.3bd322e3eUQssW&gps-id=pcDetailBottomMoreOtherSeller&scm=1007.14976.157518.0&scm_id=1007.14976.157518.0&scm-url=1007.14976.157518.0&pvid=59a203b8-bbb6-4fcf-924d-e9546256880f&_t=gps-id:pcDetailBottomMoreOtherSeller,scm-url:1007.14976.157518.0,pvid:59a203b8-bbb6-4fcf-924d-e9546256880f,tpp_buckets:668%230%23169576%232_668%23808%234093%23705_668%23888%233325%233_4976%230%23157518%230_4976%232711%237538%23913_668%232717%237567%23993
Эти тоже пришли, перепаял, 30сек примерно держит, потом моргать начинает...
парни а схемку с концевиками можно
Да тут и без схемы понятно, при установке рюмок на место, концевик замыкает на массу-минус вывод ардуино, к которому подключен.
A0-----[10k]-----\ sw1
GND--------------/ sw2
в скетче низкий уровень концевиков (т.е. в 0)...
придётся тоже механические втыкать... досадно, блин...
все таки надо подтягивать 10 ком резистором ко входам ардуинки
парни а на питание сервы ставите доп кондер?
Если управление идёт низким уровнем(так делать правильней), то резисторы не нужны, сделана подтяжка к плюсу в самой ардуино. Высоким уровнем у меня управляется идёт через сенсоры, то резисторы тоже не нужны, если всё же делать так через концевики, то резистор подтягиваем к минусу уже.
Кондёр ставить нужно на всю схему питания по 5 вольтам, от которых запитываем и серву.
raven, я собрал наливатор для 5-ти рюмок и на ик датчиках, так что пришлось по колдовать над твоей прошивкой (я не программист, я только учусь, хотя мне уже 45). Я добавил в меню настройки "настройка ик датчика" для каждой рюмки для изменения порога срабатывания, так как при подключении их на на ноль или единицу нет возможности регулировки. Возле окна срабатывают :(, а после регулировки - нет :). Пришлось использовать всё таки аналоговый пин А6, не знаю как это повлияет на работу плеера - не пробовал. А вообще прошивка супер!!! СПАСИБО :)
Пришлось использовать всё таки аналоговый пин А6, не знаю как это повлияет на работу плеера - не пробовал. А вообще прошивка супер!!! СПАСИБО :)
В принципе ничего критичного, надо посмотреть как будет с рандомом тостов, вероятно стартовать будет всегда с одного и того же .
Обновил мальца скетч, добавил запись громкости плеера в память, как и договаривались))). Чего то мудрил с меню плеера и другими меню, избавлялся от моргания дисплея )))
Во вкладку a_setup добавил во вторую строку параметр для корректировки углов серво, нужно раскомментировать строку
и вбить свои параметры, если серва по какой то причине упирается в ноль или не доезжает до 180 градусов.
ТЫЦ
raven78,Роман ты ваще красавчик!Скетч постоянно доводишь,людям все разжевываешь досконально.Спасибо огромное друг.За твою работу и донат не жалко.Выложи реквизиты,думаю те люди кто пользуется твоей прошивкой отблагодарят тебя,ведь работа выполнена великолепно и постоянно обновляется. Если не тут то хотя бы в прошивке оставь данные. Так держать дружище!.
Пришлось использовать всё таки аналоговый пин А6, не знаю как это повлияет на работу плеера - не пробовал. А вообще прошивка супер!!! СПАСИБО :)
В принципе ничего критичного, надо посмотреть как будет с рандомом тостов, вероятно стартовать будет всегда с одного и того же .
Да, протестировал и оказалось, что все тосты идут в определённой последовательности и после перезагрузки все с начало ;(
Докладываю...
С прискорбием...
https://aliexpress.ru/item/32962993969.html?spm=a2g0s.9042311.0.0.365333...
норм работает около часа стоял без перебоев
Получил сегодня с этой ссылки... те же яйца, только в профиль... 8-10сек и отрубается.
Другие меню работают без проблем. TTP перепаивалhttps://aliexpress.ru/item/33041395708.html?spm=a2g0o.detail.1000014.3.3bd322e3eUQssW&gps-id=pcDetailBottomMoreOtherSeller&scm=1007.14976.157518.0&scm_id=1007.14976.157518.0&scm-url=1007.14976.157518.0&pvid=59a203b8-bbb6-4fcf-924d-e9546256880f&_t=gps-id:pcDetailBottomMoreOtherSeller,scm-url:1007.14976.157518.0,pvid:59a203b8-bbb6-4fcf-924d-e9546256880f,tpp_buckets:668%230%23169576%232_668%23808%234093%23705_668%23888%233325%233_4976%230%23157518%230_4976%232711%237538%23913_668%232717%237567%23993
Эти тоже пришли, перепаял, 30сек примерно держит, потом моргать начинает...
при калибровке помпы все рюмки на местах, но говорит нет рюмок. и при промывке... Уровень датчиков стоит 0
в остальных местах стопки видит, и наливает...
хотя при повторном включении устройства промывка сработала, но потом перешёл на калибровку помпы, рюмку не убирал, соответственно обругалось на это, затем снял и обратно поставил - всё равно, говорит, нет рюмок. затем перевключил устройство, сразу пошёл в калибровку помпы, поставил пустую рюмку - пошла работать помпа.Переставил в другое место - работает. как только повторилась ситуация с отсутствием рюмки, дальше она повторяется независимо от снятия стопок...
перезалей скетч 3,4 все норма будет
он и залит.
Всё обнулил. Перезалил бутлодер и прошивку.
просто заново скачай с гитхаба прошивку и перезалей,Роман уже все исправил.
т.е алгоритм такой:
включение--->свободно--->наливает--->занято/отсутствует--->не наливает--->свободно/занято--->не наливает...|--->
попробуйте убрать стопки и включить промывку, затем поставить стопку и снова включить - работает?
Залил 33-й скетч. такая же история.
Залил 32-й всё работает...
Сорри. Залил 3.4 который 3 часа назад изменён. - всё поправлено.
Доброго дня! Хочу спросить - для таймера сна можно указать как-то, что активность с установкой стопок - это активность, во время которой засыпать не нужно? Сейчас можно поставить стопку и следом идёт переход в сон
Да, протестировал и оказалось, что все тосты идут в определённой последовательности и после перезагрузки все с начало ;(
Нашел в нете какой то генератор случайных чисел, тем самым освобождаем аналоговый пин от участия в рандоме. Рандом стал более случайным, он нужен для перемешивания тостов в случайном порядке и для мушкетёров. НУЖНО ПРОБОВАТЬ)))).
Доброго дня! Хочу спросить - для таймера сна можно указать как-то, что активность с установкой стопок - это активность, во время которой засыпать не нужно? Сейчас можно поставить стопку и следом идёт переход в сон
Тоже сделал, так конечно правильней.
ГИТ
Приветствую всех, хочу еще раз поднять тему по оптодатчикам, чтобы светодиод излучал свет импульсами с частотой допустим 100 герц, и ардуино срабатывало только если с фотоприемника поступал такой же сигнал, соответственно от солнца не будет ошибочных сработок, но как это программно реализовать я не знаю, так как больше с паяльником дружу, и нигде про это сильно не описано