181

Re: Узел отбора на перистальтическом насосе

Gerundey ©:

Заказал нормальный еще.

А что с этой не так? Работает ведь.

Homo est mundi pars

182

Re: Узел отбора на перистальтическом насосе

Danil ©:

Работает ведь.

Как оказалось хреновенько. Т.е не хватает мощи. Когда навешиваешь на него сам насос, он начинает пропускать обороты

183

Re: Узел отбора на перистальтическом насосе

А я спалил все.. коротнул с подстроечника на какой-то контакт. Сгорел и драйвер и ардуина. Заказал новое, драйвер такой же. А какой надо-то? Закажу еще один.

Homo est mundi pars

184

Re: Узел отбора на перистальтическом насосе

Danil ©:

А я спалил все.

О, брат как!  *ELECTRO*
Вот номерок 1609523735  нужен DRV8825

185

Re: Узел отбора на перистальтическом насосе

Danil, да ебтить... Как так-то?

Я то свою меру отлично знаю, а вот вас... вас я давно наблюдаю. (с)

186

Re: Узел отбора на перистальтическом насосе

Димон ©:

Как так-то?

Крутил подстречник и случайно коротнул на соседний контакт :(

Homo est mundi pars

187

Re: Узел отбора на перистальтическом насосе

Danil ©:

спалил все

Danil, ардуина с драйвером связана всего лишь одним портом, может ты порт спалил? Неужели всю ардуину?

188

Re: Узел отбора на перистальтическом насосе

Четланин, на ардуине лампочки горят, а дисплей погас. Да хрен с ней, новая скоро приедет.

Homo est mundi pars

189

Re: Узел отбора на перистальтическом насосе

Danil ©:

скоро приедет.

У тебя персональный канал с Китая?!  o_O

Винокурня Аркадия
---
До седин я у жизни хожу в подмастерьях,
Все еще не зачислен в разряд мастеров... (c)

190

Re: Узел отбора на перистальтическом насосе

Gerundey ©:

У меня если там выставить 0,65в нихрена не работает.

Возможно это А4988. У него надо  в 1,6 раза больше напряжение выставлять, чем на DRV8825. Хотя, как пишут, бывают варианты. Но скорее всего, именно в 1,6 раза. Вот, - у одного продавца:


  • A4988vs8825.jpg
    size: 133.12Кб type: jpg
С уважением, Олег Кузнецов.

191

Re: Узел отбора на перистальтическом насосе

Аркадий, месяц... разве это долго?

Homo est mundi pars

192

Re: Узел отбора на перистальтическом насосе

Kusnezov Oleg ©:

в 1,6 раза больше напряжение выставлять,

Не, эт ваще хрень какая-то. На нем если 0,6 выставляешь он не работает, так куда больше то.

193

Re: Узел отбора на перистальтическом насосе

Danil ©:

месяц... разве это долго?

а разве это быстро?!  o_O  :D

Винокурня Аркадия
---
До седин я у жизни хожу в подмастерьях,
Все еще не зачислен в разряд мастеров... (c)

194

Re: Узел отбора на перистальтическом насосе

Коллеги, просветите по поводу пина EN на драйвере. Я так понял, что драйвер включается при соединении его с массой. А с управляющего пина ардуины тмаса что мы получим? Там же вроде либо +5В, либо ничего...
Извиняюсь за дилетантские вопросы.

Homo est mundi pars

195

Re: Узел отбора на перистальтическом насосе

Danil ©:

Там же вроде либо +5В, либо ничего...

Та либо высокий уровень, равный 5В, либо низкий, эквивалентный замыканию на gnd.

Я то свою меру отлично знаю, а вот вас... вас я давно наблюдаю. (с)

196 (2019-11-05 16:11:25 отредактировано Kusnezov Oleg)

Re: Узел отбора на перистальтическом насосе

Danil, "ничего" быть не должно. Либо 0 (масса, как ты назвал), либо единица (+5 В).
Если GND контроллеров соединены, то на ЕN  будет 0, если на внешнем (тмас?) контроллере 0 и единица (+5В) - в любом другом случае (он "подтянут" на +5 В).
Ну да... пока писал уже ответили... *DRINK*
UPD Не... ошибся, на 0 он подтянут...

С уважением, Олег Кузнецов.

197

Re: Узел отбора на перистальтическом насосе

Димон, Kusnezov Oleg, дошло :) Спасибо!

Homo est mundi pars

198 (2019-12-07 16:08:59 отредактировано kvic)

Re: Узел отбора на перистальтическом насосе

Четланин ©:

очередь за тобой.

Вот очередь и подошла.

Kusnezov Oleg ©:

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

Попытался написать. Что-то получилось.

Четланин ©:

Подождём...твою скетч.

Скетч....
Из функциональности.
1. Отбор с заданной скоростью (мл/час)
2. Автостоп по задаваемому объему.
3. Калибровка с записью в EEPROM.
4. Может отображать общий объем отбора, скорость отбора, шаг отбора, остаток до автостопа.
5. Нелинейные регулировки скорости отбора и шага дозатора. При малых скоростях/объемах шаг мелкий, при средних средний при больших большой.
За основу принят аппарат Четланина:
Узел отбора на перистальтическом насосе
по схеме из:
Узел отбора на перистальтическом насосе
с некоторыми доработками:

Добавлено подключение кнопки энкодера и сигнал "стоп" с TMAS заведён непосредственно в контроллер отбора.
Ввод сигнала схематичен.
Можно как есть, можно напрямую уровнем, можно через оптрон, например.
Активный уровень - низкий, вызывает немедленный стоп.
Алгоритм работы изображён на нижеприведённой каринке:

Скетч написан исходя из имеющихся подключений оригинального варианта.
Но это вариабельно, подключать устройства /энкодер, дисплей, вход от TMAS/ можно практически к любым ногам ардуины,
библиотеки позволяют некоторую вольность,
надо только отредактировать это в скетче.
---
Все строки, относящиеся к Serial можно безболезненно удалить.
---
Вот и сам скетч:

#include <EEPROM.h>                           // Стандартная библиотека
#include "GyverEncoder.h"                     // Библиотеки с сайта 
#include "GyverTM1637.h"                      // https://alexgyver.ru/lessons/arduino-libraries/
#include "directTimers.h"                     // https://codeload.github.com/AlexGyver/GyverLibs/zip/master
//------------------------------------------------------------------------------------------
//**********************************************************************************************************
#define STEP8     // Закомментировать, если используется шаг/4, раскомментировать, если используется шаг/8 *
//**********************************************************************************************************
//--------------------------- Настройка железа ---------------------------------------------
// Подключение энкодера
#define SW1 A2                                // Сигнал энкодера 1 // Если кручение влево/вправо перепутано,
#define SW2 A3                                // Сигнал энкодера 2 // можно поменять местами
#define KEY A4                                // Кнопка энкодера
Encoder enc1(SW1, SW2, KEY, TYPE2);

// Подключение TM1637
#define CLK 9                                 // Тактовые импульсы TM1637
#define DIO 10                                // Данные для TM1637
GyverTM1637 disp(CLK, DIO);

// Подключение DRV8825
#define STEP 2                                // Тактовые импульсы на драйвер ШД
// Внешнее управление
#define TMAS 5                                // Сюда подключаем управление от TMAS, низкий уровень вызовет паузу
#define LED 13                                // Встроенный светодиод


//--------------------------------------------------------------------------------------
// Наименования режимов работы
//----------------------------------------------
#define RUNNING               0               //
#define PAUSED                1               //
#define PAUSED_BY_EXT         2               //
#define PAUSED_BY_VOL         3               //
#define SELECT_VOL            4               //
#define TUNING                10              //
#define TUNING_PAUSE          11              //
//----------------------------------------------
// Константы
//----------------------------------------------
#define maximumRate           2500            //  Максимальная скорость отбора мл/час
#define rateStep              10              //  Мелкий шаг регулировки отбора
#define rateMidStep           50              //  Средний шаг регулировки отбора
#define rateBigStep           100             //  Крупный шаг регулировки отбора
#define volStep               10              //  Шаг регулировки дозатора
#define volMidStep            50              //  Средний шаг регулировки дозатора
#define volBigStep            500             //  Крупный шаг регулировки дозатора
#define maxDrinkVol           5000            //  Максимальный объем, выдаваемый дозатором
#define defaultDrink          0               //  Объем дозатора по умолчанию. 0 - без ограничения.
#define defaultStepsFor100ml  400000          //  Количество шагов потребное для отбора 100 мл по умолчанию при шаге/4
#define minStepsFor100ml      150000          //  Минимально возможное число шагов для отбора 100 мл при шаге/4    
#ifdef STEP8
#define defaultStepsFor100ml  800000          //  Количество шагов потребное для отбора 100 мл по умолчанию при шаге/8
#define minStepsFor100ml      550000          //  Минимально возможное число шагов для отбора 100 мл при шаге/8
#endif
//----------------------------------------------
// Переменные
//----------------------------------------------
unsigned long stepsFor100ml;                  //  Количество шагов потребное для отбора 100 мл
unsigned int  stepsForOneMl;                  //  Количество шагов потребное для отбора 1 мл
unsigned long stepsCount     = 0;             //  Счетчик количества шагов
unsigned long drinkBackCounter = 0;           //  Обратный счётчик шагов дозатора
unsigned long temp           = 0;             //  Временная переменная для разнообразных нужд
unsigned int  timer1EndValue = 65535;         //  Значение при котором происходит прерывание от таймера 1 (11739)
byte          thousandth     = 0;             //
byte          tenth          = 0;             //
byte          backCounter0   = 0;             //
byte          backCounter1   = 0;             //
byte          counterA       = 0;             //
byte          currentMode    = RUNNING;       // Текущий режим работы
int           rate           = 0;             // Скорость отбора мл/час 0 - maximumRate
int           totalVolume    = 0;             // Общий объем отбора мл
int           drinkVolume    = 0;             // Шаг рОзлива
bool          newSecond      = false;
bool          newTenth       = false;
bool          stepEnabled    = false;
bool          tmasStop       = false;
bool          drinkStop      = false;
bool          infoEnable     = false;
bool          bc0flag        = false;
bool          bc1flag        = false;

//--------------------------------------------------------------------------------------
void setup()
{
  Serial.begin(115200);
  // Настройка входов и выходов
  pinMode(STEP, OUTPUT);
  pinMode(CLK,  OUTPUT);
  pinMode(DIO,  OUTPUT);
  pinMode(LED,  OUTPUT);
  pinMode(SW1,  INPUT_PULLUP);
  pinMode(SW2,  INPUT_PULLUP);
  pinMode(KEY,  INPUT_PULLUP);
  pinMode(TMAS, INPUT_PULLUP);
  digitalWrite(STEP, 1);

  // Настройка таймера 1, он задаёт частоту шагания двигателя
  TIMER1_setClock(PRESCALER_64);            // Частота тактирования таймера 1: 16/64 = 0.25 МГц при шаге/4
#ifdef STEP8
  TIMER1_setClock(PRESCALER_8);           // Частота тактирования таймера 1: 16/8 = 2 МГц при шаге/8
#endif
  TIMER1_setMode(CTC_MODE);                 // Режим работы таймера - сравнение со значением, прерывание и рестарт
  TIMER1_COMPA_setValue(timer1EndValue);    // Значение для сравнения
  TIMER1_attach_COMPA();                    // Прерывание от таймера 1 по сравнению

  // Настройка таймера 2, он отсчитывает временные интервалы для работы программы
  TIMER2_setClock(PRESCALER_128);           // Частота тактирования таймера 2: 16/128 = 0.125 МГц
  TIMER2_setMode(CTC_MODE);                 // включаем сброс таймера по совпадению
  TIMER2_COMPA_setValue(124);               // настраиваем следование прерываний с частотой 1000 гц
  TIMER2_attach_COMPA();                    // прерывание с опросом энкодера

  // Настройка дисплея и вывод привета.
  disp.clear();
  disp.brightness(1);

  byte welcome_banner[] = { _empty, _empty,_dash, _dash, _r, _u, _n, _dash, _dash, _empty, _empty};
  disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
  //byte troll[4] = {_r, _U, _n, _empty};
  //disp.scrollByte(troll, 100);
  disp.displayInt(0);

  // Попытка прочитать установки из EEPROM
  EEPROM.get(0, stepsFor100ml);
  if ((stepsFor100ml < minStepsFor100ml) or (stepsFor100ml > minStepsFor100ml * 4)) // Если в EEPROM не установлено число шагов на 100 мл, то
  {
    stepsFor100ml = defaultStepsFor100ml;                     // Установим число шагов на 100 мл по умолчанию
  }
  stepsForOneMl = round((float)stepsFor100ml / 100);
  calcOCR1A();
  drinkVolume = defaultDrink;
  drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
  //if (enc1.isHolded()) {
  if (!digitalRead(KEY)) {
    currentMode = TUNING;
    byte troll[4] = {_t, _u, _n, _E};
    disp.displayByte(troll);
    backCounter0 = 0;
    infoEnable = false;
    enc1.isHolded();
  }
  else {
    currentMode = RUNNING;
    infoEnable = true;
  }
  Serial.println(drinkVolume);          //
  Serial.println(stepsFor100ml);        //
  Serial.println(stepsForOneMl);        //
  Serial.println(drinkBackCounter);     //
  Serial.println("Setup completed");
}
//--------------------------------------------------------------------------------------
//---------------------- Начало основного цикла ----------------------------------------
void loop()
{
  if (newSecond) {
    newSecond = false;
    oneSecSub();
  }
  if (newTenth)  {
    newTenth = false;
    oneTenthSub();
  }
  if (bc0flag)   {
    bc0flag = false;
    infoEnable = true;
  }
  //---------------------------------------------------------------
  switch (currentMode)
  {
    //-------------------------------------------------------------
    // Режим калибровки насоса основной экран ---------------------
    //-------------------------------------------------------------
    case TUNING:            // Настройка количества шагов на 100 мл.
      {
        infoEnable = false;
        //--------------------
        if (bc1flag)
        {
          bc1flag = false;
          byte troll[4] = {_t, _u, _n, _E};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
        {
          increaseRate();
          stepEnabled = true;
          disp.displayInt(rate);
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
        {
          decreaseRate();
          if (rate != 0)
          {
            stepEnabled = true;
          }
          disp.displayInt(rate);
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isClick())
        {
          stepEnabled = false;
          currentMode = TUNING_PAUSE;
          byte troll[4] = {_t, _P, _A, _u};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isHolded())
        {
          Reset();
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Пауза в режиме калибровки насоса ---------------------------
    //-------------------------------------------------------------
    case TUNING_PAUSE:
      {
        //--------------------
        if (bc1flag)
        {
          bc1flag = false;
          counterA = 0;
          byte troll[4] = {_t, _P, _A, _u};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
        {
          increaseRate();
          disp.displayInt(rate);
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
        {
          decreaseRate();
          disp.displayInt(rate);
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isClick())
        {
          stepEnabled = true;
          currentMode = TUNING;
          byte troll[4] = {_t, _u, _n, _E};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isHolded())
        {
          stepsCount = 0;
          totalVolume = 0;
          byte welcome_banner[] = {_c, _o, _u, _n, _t, _E, _r, _S, _empty, _c, _l, _e, _a, _r, _e, _d};
          disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
          bc1flag = true;
        }
        //--------------------
        if (enc1.isRightH())
        {
          tryToSaveStepsFor100ml();
        }
        //--------------------
        if (enc1.isLeftH())
        {
          tryToSaveStepsFor100ml();
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Основной режим. Идёт отбор. --------------------------------
    //-------------------------------------------------------------
    case RUNNING:
      {
        //--------------------
        if (enc1.isClick()) // Клик на кнопку (режим RUNNING)
        {
          stepEnabled = false;
          currentMode = PAUSED;
          byte troll[4] = {_S, _t, _o, _P};
          //disp.twistByte(troll, 20);
          disp.displayByte(troll);
          backCounter0 = 0;
          infoEnable = false;
        }
        //--------------------
        if (tmasStop)      // Внешний сигнал, появление (режим RUNNING)
        {
          stepEnabled = false;
          currentMode = PAUSED_BY_EXT;
          byte troll[4] = {_o, _u, _t, _S};
          //disp.twistByte(troll, 20);
          disp.displayByte(troll);
          backCounter0 = 0;
          infoEnable = false;
        }
        //--------------------
        if (drinkStop)     // Налит запрошенный объем (режим RUNNING)
        {
          stepEnabled = false;
          drinkStop = false;
          currentMode = PAUSED_BY_VOL;
          drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
          byte troll[4] = {_d, _o, _n, _E};
          //disp.twistByte(troll, 20);
          disp.displayByte(troll);
          backCounter0 = 0;
          infoEnable = false;
        }
        //--------------------
        if (enc1.isRight())     // Вращение по часовой (режим RUNNING)
        {
          if (backCounter0 != 0)
          {
            increaseRate();
            stepEnabled = true;
          }
          disp.displayInt(rate);
          infoEnable = false;
          backCounter0 = 20;
        }
        //--------------------
        if (enc1.isLeft())      // Вращение против часовой (режим RUNNING)
        {
          if (backCounter0 != 0)
          {
            decreaseRate();
            if (rate != 0)
            {
              stepEnabled = true;
            }
          }
          disp.displayInt(rate);
          infoEnable = false;
          backCounter0 = 20;
        }
        //--------------------
        if (enc1.isHolded())    // Удержание кнопки (режим RUNNING)
        {
          if ((rate == 0) and (stepsCount != 0))
          {
            stepsCount = 0;
            totalVolume = 0;
            drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
            byte welcome_banner[] = {_c, _o, _u, _n, _t, _E, _r, _S, _empty, _c, _l, _e, _a, _r, _e, _d};
            disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
          }
          else
          {
            if (infoEnable) {
              if (drinkVolume == 0)
              {
                byte troll[4] = {_empty, _i, _n, _f};
                disp.displayByte(troll);
              }
              else
              {
                disp.displayInt((drinkBackCounter + 1) / stepsForOneMl);
              }
            }
            infoEnable = false;
            backCounter0 = 20;
          }
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Остановка по нажатию кнопки --------------------------------
    //-------------------------------------------------------------
    case PAUSED:
      {
        //--------------------
        if (bc1flag)
        {
          bc1flag = false;
          //stepEnabled = false;
          byte troll[4] = {_S, _t, _o, _P};
          disp.displayByte(troll);
          infoEnable = false;
        }
        //--------------------
        if (enc1.isClick())
        {
          resumeRun();
        }
        //--------------------
        if (enc1.isRight())
        {
          if (backCounter1 != 0)
          {
            increaseRate();
          }
          disp.displayInt(rate);
          infoEnable = false;
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isLeft())
        {
          if (backCounter1 != 0)
          {
            decreaseRate();
          }
          disp.displayInt(rate);
          infoEnable = false;
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isHolded())
        {
          infoEnable = false;
          currentMode = SELECT_VOL;
          byte troll[4] = {_S, _t, _E, _P};
          disp.displayByte(troll);
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Остановка по внешнему сигналу ------------------------------
    //-------------------------------------------------------------
    case PAUSED_BY_EXT:
      {
        if (!tmasStop)
        {
          resumeRun();
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Остановка по достижению заданного разового объема отбора ---
    //-------------------------------------------------------------
    case PAUSED_BY_VOL:
      {
        //--------------------
        if (enc1.isHolded())
        {
          infoEnable = false;
          currentMode = SELECT_VOL;
          byte troll[4] = {_S, _t, _E, _P};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isClick())
        {
          resumeRun();
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    // Режим выбора разового объема -------------------------------
    //-------------------------------------------------------------
    case SELECT_VOL:
      {
        //--------------------
        if (bc1flag)
        {
          bc1flag = false;
          byte troll[4] = {_S, _t, _E, _P};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isHolded())
        {
          drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
          resumeRun();
        }
        //--------------------
        if (enc1.isClick())
        {
          currentMode = PAUSED;
          drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
          byte troll[4] = {_S, _t, _o, _P};
          disp.displayByte(troll);
        }
        //--------------------
        if (enc1.isRight())
        {
          if (backCounter1 != 0)
          {
            if (drinkVolume >= 1000) {
              drinkVolume = drinkVolume + volBigStep;
            } else {
              if (drinkVolume >= 100) {
                drinkVolume = drinkVolume + volMidStep;
              } else {
                drinkVolume = drinkVolume + volStep;
              }
            }
            if (drinkVolume >= maxDrinkVol) drinkVolume = 5000;
          }
          disp.displayInt(drinkVolume);
          backCounter1 = 20;
        }
        //--------------------
        if (enc1.isLeft())
        {
          if (backCounter1 != 0)
          {
            if (drinkVolume >= (1000 + volBigStep)) {
              drinkVolume = drinkVolume - volBigStep;
            } else {
              if (drinkVolume >= (100 + volMidStep)) {
                drinkVolume = drinkVolume - volMidStep;
              } else {
                drinkVolume = drinkVolume - volStep;
              }
            }
            if (drinkVolume <= 0) drinkVolume = 0;
          }
          disp.displayInt(drinkVolume);
          backCounter1 = 20;
        }
        //--------------------
      }
      break;
    //-------------------------------------------------------------
    default:
      //-------------------------------------------------
      break;
  }
  //-------------------------------------------------
}
//---------------------- Конец основного цикла -----------------------------------------
//--------------------------------------------------------------------------------------
void resumeRun()
{
  byte troll[4] = {_dash, _G, _o, _dash};
  disp.displayByte(troll);
  currentMode = RUNNING;
  if (rate != 0)
  {
    stepEnabled = true;
  }
  backCounter0 = 5;
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую секунду --------------------------------------------------
void oneSecSub()
{
  calcTotalVolume();
  Serial.println(String(stepsCount) + " " + String(totalVolume) + " " + String(timer1EndValue));
  if (infoEnable)
  {
    //noInterrupts();
    disp.displayInt(totalVolume % 10000);
    //interrupts();
  }
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую десятую долю секунды -------------------------------------
void oneTenthSub()
{
  tmasStop = !digitalRead(TMAS);
  digitalWrite(13, tmasStop);
}
//--------------------------------------------------------------------------------------
// Прерывание таймера 2 (1000 раз в секунду) -------------------------------------------
ISR_T2_COMPA
{
  enc1.tick();
  thousandth++;                                         // Счетчик миллисекунд
  if (thousandth >= 100)                                // Началась новая десятая доля секунды
  { thousandth = 0; tenth++; newTenth = true;           // Счетчик десятых долей секунды
    if (backCounter0  != 0) {
      backCounter0--;
      if (backCounter0 == 0) {
        bc0flag = true;
      }
    }
    if (backCounter1  != 0) {
      backCounter1--;
      if (backCounter1 == 0) {
        bc1flag = true;
      }
    }
    if (tenth >= 10) {
      tenth = 0;  // Началась новая секунда
      newSecond = true;
    }
  }
}

//--------------------------------------------------------------------------------------
// Прерывание по совпадению А в таймере 1 ----------------------------------------------
ISR_T1_COMPA
{
  if ((stepEnabled) or (!(stepEnabled) and !(digitalRead(STEP).
    // Если шаги разрешены или запрещены и уровень на тактовом выходе низкий, то:
  {
    digitalWrite(STEP, !digitalRead(STEP));   // Меняем уровень на шагательной ноге на противоположный
    if (digitalRead(STEP))                    // Если был переход 0->1,
    {
      stepsCount++;                           // то увеличиваем счетчик шагов
      TIMER1_COMPA_setValue(timer1EndValue);  // и перезагружаем значение сравнения счетчика.
      if (drinkVolume != 0)                   // Если задан ненулевой объем наливайки
      {
        if (drinkBackCounter == 0)            // и налито, сколько запрошено,
        {
          stepEnabled = false;                // останавливаем отбор
          drinkStop = true;                   // и устанавливаем флаг готовности дринка. (обрабатывается в основном цикле)
        }
        else
        {
          drinkBackCounter--;                 // Иначе уменьшаем дринковый счетчик.
        }
      }
    }
  }
}

//--------------------------------------------------------------------------------------
// Расчет числа, загружаемого в OCR1A в зависимости от нужной скорости отбора ----------
void calcOCR1A()
{
  stepEnabled = false;
  temp = round((float)450000000 / stepsForOneMl); // шаг/4
#ifdef STEP8
  temp = round((float)3600000000 / stepsForOneMl); // шаг/8
#endif
  // OCR1A = (Fcpu*3600)/(2*N*K*R)-1
  temp = round((float)temp / rate);             // Fcpu = 16000000 Гц, N - количество шагов на 1 мл,
  temp = temp - 1;                              // K - делитель перед счетчиком Т1 (64), R - скорость отбора мл/час
  if (temp >= 65535)
  {
    rate = 0;
    disp.displayInt(rate);
  }
  else
  {
    noInterrupts();                               // Обеспечиваем атомарность действия
    timer1EndValue = temp;                        //
    interrupts();                                 // Восстанавливаем прерывания
  }
}
//--------------------------------------------------------------------------------------
// Пересчёт количества шагов в миллилитры ----------------------------------------------
void calcTotalVolume()
{
  totalVolume = stepsCount / stepsForOneMl;
}
//--------------------------------------------------------------------------------------
// Увеличение скорости отбора ----------------------------------------------------------
void increaseRate()
{
  if (rate >= 1000) {
    rate = rate + rateBigStep;
  } else {
    if (rate >= 200) {
      rate = rate + rateMidStep;
    } else {
      rate = rate + rateStep;
    }
  }
  if (rate >= maximumRate) rate = maximumRate;
  calcOCR1A();
}
//--------------------------------------------------------------------------------------
// Уменьшение скорости отбора ----------------------------------------------------------
void decreaseRate()
{
  if (rate >= (1000 + rateBigStep)) {
    rate = rate - rateBigStep;
  } else {
    if (rate >= (200 + rateMidStep)) {
      rate = rate - rateMidStep;
    } else {
      rate = rate - rateStep;
    }
  }
  if (rate <= 0) rate = 0;
  calcOCR1A();
}
//--------------------------------------------------------------------------------------
void tryToSaveStepsFor100ml()
{
  backCounter1 = 20;
  counterA++;
  if (counterA > 10)
  {
    if ((stepsCount > minStepsFor100ml) and (stepsCount < 4 * minStepsFor100ml))
    {
      EEPROM.put(0, stepsCount);
      byte welcome_banner[] = {_C, _A, _L, _i, _b, _r, _A, _t, _i, _n, _G, _empty, _d, _o, _n, _E, _empty, _r, _e, _S, _t, _A, _r, _t, _i, _n, _G, _empty, _empty};
      disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
      Reset();
    }
  }
}
//--------------------------------------------------------------------------------------
inline void Reset() {
  asm("JMP 0");
}

Отдельно на гуглодиске:
https://drive.google.com/open?id=1F2CP0 … BD6CzoVWvZ
В архиве сам скетч и требуемые библиотеки.
Ссылки на библиотеки приведены в теле скетча.
Из общей кучи нужны библиотеки GyverEncoder , GyverTM1637 , directTimers  .
Всё это испытано на макетке.
Вроде работает.
Желающие могут испытать всё это на своём оборудовании.   *YES*
Как всегда, от всякой ответственности отказываюсь.
Всё на свой страх и риск с осознанием возможных последствий.
Так же всё отдаётся в свободное использование и модификацию.
----------
Конструктивная критика и предложения принимаются.
----------
Если что не понятно, пишите, постараюсь пояснить.
----------
09.11
Один косячок уже нашёл и исправил.
Не отрабатывала корректно ветка RUNNING->STOP->STEP->(изменить шаг)->STOP->RUNNING
Поправлено. Файл перезалил.
----------
27.11
Ниже по ссылке архив со всеми необходимыми библиотеками.
Версия со звуковым сопровождением. (см.ветку обсуждения)
https://drive.google.com/file/d/1ZHZ6Nh … 1XrW6x3gqy

  • Uzel_otbora_3.GIF
    size: 63.62Кб type: GIF
  • Логика_управяющей_программы_узла_отбора.png
    size: 204.28Кб type: png
  • дрожжи.jpg
    size: 110.08Кб type: jpg
РК 35х1600

199

Re: Узел отбора на перистальтическом насосе

Сегодня попробовал прошить ардуину. С IDE не шьется, что-то там в ардуине крутится и постоянно мигает красный диод, и выводит в сом-порт какое-то значение напряжения и еще что-то. Взял загрузочный файл ТМАСа, грузанул его, ардуина прогрузилась, первоначальное мигание закончилось.
Тогда сделал скетч чтобы помигать диодом на 13 ноге, скомпилировал в HEX и прогрузил X-loader'ом, все вроде нормально, мигает. Потом скомпилировал скетч Четланина, он судя по индикаторам и реакции X-loader'а тоже прогрузился.
Пне это все так понравилось, что я решил еще раз перезаписать скетч с мигающим диодом. И тут наступила засада. X-loader выдал сообщение Upload failed, и больше ни одного скетча загрузить на ардуину я не могу. И судя по диодам rx/tx никакого обмена не идет.
Сломался загрузчик? За новой ехать?

Я то свою меру отлично знаю, а вот вас... вас я давно наблюдаю. (с)

200

Re: Узел отбора на перистальтическом насосе

Димон ©:

С IDE не шьется, что-то там в ардуине крутится и постоянно мигает красный диод, и выводит в сом-порт какое-то значение напряжения и еще что-то.

Проверил, шьётся.
Ардуино иде 1.8.10 , если что.
В порт вывод примерно такой:

Скорость порта 115200.

  • COM_9.JPG
    size: 62.05Кб type: JPG
РК 35х1600