Re: Узел отбора на перистальтическом насосе
Головка насоса самодельная из алюминия
выложу сюда прошивку, схему..
...чертёж головки...
Ибо дядюшка Ляо что-то цены ломить начал.
Форум самогонщиков, винокуров, виноделов, пивоваров, бондарей и очень хороших людей |
Назад 1 … 15 16 17 18 19 … 53 Следующая
Чтобы отправить ответ, вы должны войти или зарегистрироваться
с 321 по 340 из 1 059
Головка насоса самодельная из алюминия
выложу сюда прошивку, схему..
...чертёж головки...
Ибо дядюшка Ляо что-то цены ломить начал.
...чертёж головки...
Ибо дядюшка Ляо что-то цены ломить начал.
Да, не вопрос! )
Выкладываю схему, логику и скетч моей версии перистальтического отбора, основанный на трудах kvic (https://alcodistillers.ru/forum/viewtop … 18#p157718).
Вместо TM1637 прикрутил LCD1602 I2C, добавил кнопку сброса скорости мотора на ноль (она же для входа в режим калибровки - у меня энкодер сильно контактами дребезжит, что вызывало сложности входа в режим, выходил сразу же).
#include <EEPROM.h> // Стандартная библиотека
#include <Wire.h> // Библиотека для управления устройствами по I2C
#include <LiquidCrystal_I2C.h> // Библиотека LCD_I2C
//-------------------------------
//#define _LCD_TYPE 1 //Тип подключения дисплея: 1 - по шине I2C, 2 - десятиконтактное. Обязательно указывать ДО подключения библиотеки
//#include <LCD_1602_RUS_ALL.h> // Кириллица https://github.com/ssilver2007/LCD_1602_RUS_ALL
//-------------------------------
#include <GyverEncoder.h> // Библиотеки с сайта
#include <directTimers.h> // https://codeload.github.com/AlexGyver/GyverLibs/zip/master
//************************************************************************************************************
//#define STEP8 // Закомментировать, если используется шаг/4, раскомментировать, если используется шаг/8 *
//************************************************************************************************************
//------------------------------------------------------------------------------------------
// Настройка железа
//----------------------------------------------
// Подключение энкодера
#define SW1 7 // Сигнал энкодера 1 // Если кручение влево/вправо перепутано,
#define SW2 6 // Сигнал энкодера 2 // можно поменять местами
#define KEY 5 // Кнопка энкодера
Encoder enc1(SW1, SW2, KEY, TYPE1);
// Подключение LCD1602
LiquidCrystal_I2C lcd(0x27,16,2); // Указываем I2C адрес (наиболее распространенное значение), а также параметры экрана (в случае LCD 1602 - 2 строки по 16 символов в каждой)
//LCD_1602_RUS <LiquidCrystal_I2C> lcd(0x27, 16, 2); //Если используется кириллица
// Подключение A4988 (DRV8825)
#define STEP 11 // Тактовые импульсы на драйвер ШД
// Внешнее управление
#define TMAS 4 // Сюда подключаем управление от TMAS, низкий уровень вызовет паузу
#define LED 13 // Встроенный светодиод
#define Button 9 // Сюда подключаем кнопку
#define PIEZO 8
#define soundA B00000101
#define soundB B00011111
//--------------------------------------------------------------------------------------
// Наименования режимов работы
//----------------------------------------------
#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 7000 // Максимальная скорость отбора мл/час
#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 200000 // Минимально возможное число шагов для отбора 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; // Текущий режим работы
byte pattern = 0; //
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;
bool sndFlag = false;
//--------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
lcd.begin(); // Инициализация дисплея
lcd.backlight(); // Подключение подсветки
lcd.clear();
lcd.setCursor(0,0); // Установка курсора в начало первой строки
// Настройка входов и выходов
pinMode(STEP, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(PIEZO, OUTPUT);
pinMode(SW1, INPUT_PULLUP);
pinMode(SW2, INPUT_PULLUP);
pinMode(KEY, INPUT_PULLUP);
pinMode(TMAS, INPUT_PULLUP);
pinMode(Button, INPUT_PULLUP);
digitalWrite(STEP, 1);
digitalWrite(PIEZO, 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(); // прерывание с опросом энкодера
rate = 0;
totalVolume = 0;
stepsCount = 0;
// Попытка прочитать установки из EEPROM
EEPROM.get(0, stepsFor100ml);
if ((stepsFor100ml < minStepsFor100ml) or (stepsFor100ml > minStepsFor100ml * 4)) // Если в EEPROM не установлено число шагов на 100 мл, то
{
stepsFor100ml = defaultStepsFor100ml; // Установим число шагов на 100 мл по умолчанию
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("EEPROM empty!"));
lcd.setCursor(0, 1);
lcd.print(F("Settings default"));
delay(5000);
}
stepsForOneMl = round((float)stepsFor100ml / 100);
calcOCR1A();
drinkVolume = defaultDrink;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
Serial.println(drinkVolume); //
Serial.println(stepsFor100ml); //
Serial.println(stepsForOneMl); //
Serial.println(drinkBackCounter); //
Serial.println("--READY--");
Serial.end();
//--------------------
if (!digitalRead(Button)) //(enc1.isHolded())
{
currentMode = TUNING;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode"));
backCounter0 = 0;
infoEnable = false;
}
else {
currentMode = RUNNING;
infoEnable = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Extraction"));
lcd.setCursor(0, 1);
lcd.print(F("Unit V1.0"));
//delay(5000);
}
}
//--------------------------------------------------------------------------------------
// Расчет числа, загружаемого в 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;
}
else
{
noInterrupts(); // Обеспечиваем атомарность действия
timer1EndValue = temp; //
interrupts(); // Восстанавливаем прерывания
}
}
void resumeRun()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process"));
lcd.setCursor(0, 1);
lcd.print(F("started.."));
currentMode = RUNNING;
if (rate != 0)
{
stepEnabled = true;
}
backCounter0 = 5;
}
//--------------------------------------------------------------------------------------
void speedReset()
{
rate = 0;
stepEnabled = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Pump speed"));
lcd.setCursor(0, 1);
lcd.print(F("reset.."));
currentMode = RUNNING;
backCounter0 = 10;
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую секунду --------------------------------------------------
void oneSecSub()
{
calcTotalVolume();
//Serial.println(String(stepsCount) + " " + String(totalVolume) + " " + String(timer1EndValue) + " " + drinkBackCounter);
if (infoEnable)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Total Volume, ml:");
lcd.setCursor(0, 1);
lcd.print(totalVolume % 10000);
}
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую десятую долю секунды -------------------------------------
void oneTenthSub()
{
tmasStop = !digitalRead(TMAS);
digitalWrite(13, tmasStop);
if ((sndFlag) and (tenth < 8))
{
if (bitRead(pattern, tenth))
{
digitalWrite(PIEZO, 0);
}
else
{
digitalWrite(PIEZO, 1);
}
}
else
{
digitalWrite(PIEZO, 1);
}
}
//--------------------------------------------------------------------------------------
// Прерывание таймера 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--; // Иначе уменьшаем дринковый счетчик.
}
}
}
}
}
//--------------------------------------------------------------------------------------
// Пересчёт количества шагов в миллилитры ----------------------------------------------
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);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Calibrating done");
lcd.setCursor(0, 1);
lcd.print("Restarting..");
setup();
}
else //(stepsCount < minStepsFor100ml)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Steps ERROR!");
}
}
}
//--------------------------------------------------------------------------------------
//---------------------- Начало основного цикла ----------------------------------------
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;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print("Fill the pump..");
backCounter1 = 0;
}
//--------------------
if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
{
if (backCounter1 != 0)
{
increaseRate();
stepEnabled = true;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("SpeedPump:"));
lcd.setCursor(11, 1);
lcd.print(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
{
if (backCounter1 != 0)
{
decreaseRate();
if (rate != 0)
{
stepEnabled = true;
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("SpeedPump:"));
lcd.setCursor(11, 1);
lcd.print(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isClick())
{
stepEnabled = false;
currentMode = TUNING_PAUSE;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("Pause.."));
lcd.setCursor(8, 1);
lcd.print(stepsCount);
backCounter1 = 0;
}
//--------------------
if (enc1.isHolded())
{
setup();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Пауза в режиме калибровки насоса ---------------------------
//-------------------------------------------------------------
case TUNING_PAUSE:
{
//--------------------
if (!digitalRead(Button))
{
rate = 0;
stepEnabled = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Pump speed"));
lcd.setCursor(0, 1);
lcd.print(F("reset.."));
backCounter1 = 15;
}
//--------------------
if (bc1flag)
{
bc1flag = false;
counterA = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("Pause.."));
lcd.setCursor(8, 1);
lcd.print(stepsCount);
backCounter1 = 0;
}
//--------------------
if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
{
if (backCounter1 != 0)
{
increaseRate();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("SpeedPump:"));
lcd.setCursor(11, 1);
lcd.print(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
{
if (backCounter1 != 0)
{
decreaseRate();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print(F("SpeedPump:"));
lcd.setCursor(11, 1);
lcd.print(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isClick())
{
stepEnabled = true;
currentMode = TUNING;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calculating ..."));
lcd.setCursor(0, 1);
lcd.print(F("steps for 100 ml"));
}
//--------------------
if (enc1.isHolded())
{
if (backCounter1 != 0)
{
}
stepsCount = 0;
totalVolume = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Calibrating mode:"));
lcd.setCursor(0, 1);
lcd.print("Couters cleared");
backCounter1 = 20;
bc1flag = false;
}
//-----------------------
if (enc1.isRightH())
{
tryToSaveStepsFor100ml();
}
//--------------------
if (enc1.isLeftH())
{
tryToSaveStepsFor100ml();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Основной режим. Идёт отбор. --------------------------------
//-------------------------------------------------------------
case RUNNING:
{
//--------------------
if (enc1.isClick()) // Клик на кнопку (режим RUNNING)
{
stepEnabled = false;
currentMode = PAUSED;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process paused"));
lcd.setCursor(0, 1);
lcd.print(F("by operator.."));
backCounter0 = 0;
infoEnable = false;
}
//--------------------
if (tmasStop) // Внешний сигнал, появление (режим RUNNING)
{
stepEnabled = false;
currentMode = PAUSED_BY_EXT;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process paused"));
lcd.setCursor(0, 1);
lcd.print(F("by External.."));
backCounter0 = 0;
infoEnable = false;
pattern = soundB;
sndFlag = true;
}
//--------------------
if (drinkStop) // Налит запрошенный объем (режим RUNNING)
{
stepEnabled = false;
drinkStop = false;
currentMode = PAUSED_BY_VOL;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process stopped"));
lcd.setCursor(0, 1);
lcd.print(F("Volume: Done!"));
backCounter0 = 0;
infoEnable = false;
pattern = soundA;
sndFlag = true;
}
//--------------------
if (enc1.isRight()) // Вращение по часовой (режим RUNNING)
{
if (backCounter0 != 0)
{
increaseRate();
stepEnabled = true;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Speed ml/H:"));
lcd.setCursor(0, 1);
lcd.print(rate);
infoEnable = false;
backCounter0 = 20;
}
//--------------------
if (enc1.isLeft()) // Вращение против часовой (режим RUNNING)
{
if (backCounter0 != 0)
{
decreaseRate();
if (rate != 0)
{
stepEnabled = true;
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Speed ml/H:"));
lcd.setCursor(0, 1);
lcd.print(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;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Processing:"));
lcd.setCursor(0, 1);
lcd.print("Couters cleared");
}
else
{
if (infoEnable) {
if (drinkVolume == 0)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Remaining volume");
lcd.setCursor(0, 1);
lcd.print("ml: ");
lcd.setCursor(4, 1);
lcd.print("---");
}
else
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Remaining volume");
lcd.setCursor(0, 1);
lcd.print("ml: ");
lcd.setCursor(4, 1);
lcd.print((drinkBackCounter + 1) / stepsForOneMl);
}
}
infoEnable = false;
backCounter0 = 20;
}
}
//--------------------
if (!digitalRead(Button))
{
speedReset();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Остановка по нажатию кнопки --------------------------------
//-------------------------------------------------------------
case PAUSED:
{
//--------------------
if (bc1flag)
{
bc1flag = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process paused"));
lcd.setCursor(0, 1);
lcd.print(F("by operator.."));
infoEnable = false;
}
//--------------------
if (!digitalRead(Button))
{
speedReset();
}
//--------------------
if (enc1.isClick())
{
resumeRun();
}
//--------------------
if (enc1.isRight())
{
if (backCounter1 != 0)
{
increaseRate();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Speed, ml/H"));
lcd.setCursor(0, 1);
lcd.print(rate);
infoEnable = false;
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft())
{
if (backCounter1 != 0)
{
decreaseRate();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Speed, ml/H"));
lcd.setCursor(0, 1);
lcd.print(rate);
infoEnable = false;
backCounter1 = 20;
}
//--------------------
if (enc1.isHolded())
{
infoEnable = false;
currentMode = SELECT_VOL;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Volume set, ml:"));
lcd.setCursor(0, 1);
lcd.print(drinkVolume);
}
//--------------------
}
break;
//-------------------------------------------------------------
// Остановка по внешнему сигналу ------------------------------
//-------------------------------------------------------------
case PAUSED_BY_EXT:
{
if (!tmasStop)
{
sndFlag = false;
resumeRun();
}
//--------------------
if (enc1.isRight() || enc1.isLeft())
{
sndFlag = false;
}
if (enc1.isClick())
{
stepEnabled = false;
currentMode = PAUSED;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process paused"));
lcd.setCursor(0, 1);
lcd.print(F("by operator.."));
backCounter0 = 0;
infoEnable = false;
}
//------------------------
if (enc1.isHolded())
{
infoEnable = false;
currentMode = SELECT_VOL;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Volume set, ml:"));
lcd.setCursor(0, 1);
lcd.print(drinkVolume);
}
//---------------------
if (!digitalRead(Button))
{
sndFlag = false; // Заткнуть пищалку
speedReset(); // и сбросить скорость мотора
}
}
break;
//-------------------------------------------------------------
// Остановка по достижению заданного разового объема отбора ---
//-------------------------------------------------------------
case PAUSED_BY_VOL:
{
//--------------------
if (enc1.isHolded())
{
infoEnable = false;
currentMode = SELECT_VOL; //Переход в режим SELECT_VOL
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Volume set, ml:"));
lcd.setCursor(0, 1);
lcd.print(drinkVolume);
sndFlag = false; // Заткнуть пищалку
}
//---------------------
if (!digitalRead(Button))
{
sndFlag = false; // Заткнуть пищалку
speedReset(); // и сбросить скорость мотора
}
//--------------------
if (enc1.isClick())
{
stepEnabled = false;
currentMode = PAUSED;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Process paused"));
lcd.setCursor(0, 1);
lcd.print(F("by operator.."));
backCounter0 = 0;
infoEnable = false;
}
//--------------------
if (enc1.isRight() || enc1.isLeft())
{
sndFlag = false; // Заткнуть пищалку
}
//--------------------
}
break;
//-------------------------------------------------------------
// Режим выбора разового объема -------------------------------
//-------------------------------------------------------------
case SELECT_VOL:
{
//--------------------
if (bc1flag)
{
bc1flag = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Volume set, ml:"));
lcd.setCursor(0, 1);
lcd.print(drinkVolume);
}
//--------------------
if (enc1.isHolded())
{
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
resumeRun();
}
//--------------------
if (enc1.isClick())
{
currentMode = PAUSED;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Processing paused"));
lcd.setCursor(0, 1);
lcd.print(F("by operator.."));
}
//--------------------
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;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Set volume, ml:"));
lcd.setCursor(0, 1);
lcd.print(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;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Set volume, ml:"));
lcd.setCursor(0, 1);
lcd.print(drinkVolume);
backCounter1 = 20;
}
//--------------------
}
break;
//-------------------------------------------------------------
default:
//-------------------------------------------------
break;
}
}
//-------------------------------------------------
//---------------------- Конец основного цикла -----------------------------------------
//--------------------------------------------------------------------------------------
По ссылке ниже, можно скачать скетч, используемые библиотеки, схему и логику. Там же лежат чертежи головки насоса под шланг 7мм (по наружи) со стенкой 1,5мм и подшипниками (4x11x4). Чертежи в следующих форматах: STL, STEP, DWG, PDF.
https://drive.google.com/drive/folders/ … sp=sharing
Насос буду еще упрощать - сделаю более плоским, уменьшу количество подшипников..
Опытным путем (заранее думать я не очень то не умею, как оказалось ) пришел к тому, что калибровать насос надо на работающей в режиме колонне!
Насос я калибровал на весах водой ~22 °С (100гр=100мл), а из узла отбора спирт идет горячий ~60 °C. Соответственно он занимает больший объем, чем после холодильника. Так, отобрав 750мл голов в мензурку, обнаружил недобор ~30мл. Откалибровал заново, на колонне.
отобрав 750мл голов в мензурку, обнаружил недобор ~30мл
Почти точно как в теории. 750*0.0011*(60-22)=31.35 мл.
Откалибровал заново, на колонне.
Может лучше спирт через предохладитель пустить?
Он совсем небольшой нужен при наших расходах.
Т.е. приведём к нормальным условиям.
А то в следующий раз спирт потеряет где-нибудь по дороге к насосу 10-20 цельсиев и случится перелив.
Может лучше спирт через предохладитель пустить?
Так получится, что весь отбор будет стекать в доохладитель и там накапливаться? А уже после капать посекундно.
Или я не в теме?
Может лучше спирт через предохладитель пустить?
У меня система охлаждения автономная (Автономное охлаждение) и температура охлаждающей жидкости меняется (иногда аж до 50°С доходила этим летом. Приходилось мощьность ТЭНа уменьшать, доохладитель полностью перекрывать, хоть и уже 2 радиатора охлаждения на чердаке(так и не перенес в подвал в всязи со стройкой отдельного помещеня винокурни - места не хватает уже )), в зависимости от погоды, от второго аппарата для сырца (работает он или нет). Температуру флегмы регулирую пока вручную скоростью потока охлаждайки через дефлегматор.
Есть мысли прикрутить к узлу отбора ds18b20 и корректировать скорость отбора отностительно температуры. Но надо ли? Я откалибровал щас на работающей колонне и теперь отбирает как надо и сколько задано.
весь отбор будет стекать в доохладитель и там накапливаться?
Не будет, он насквозь идёт.
Вот старая фотка:
Под №4 доохладитель.
Трубка внутренним диаметром 2 мм, длиной 40 см, намотанная на 8 мм.
Через 8 мм идёт охлаждающая вода.
Через 2 мм - отбор.
Вместе с подводящим шлангом объем тонкой трубки примерно 2 мл.
kvic, опять туплю.В трубку №2 льётся струёй, т.к. ничего, кроме диаметра трубки, не препятствует. А перистальтика уменьшает отбор до покапельного. Куда избыток девается? Накапливается в доохладителе, потом в трубке №2 и потом выше и в итоге возврат в царгу. Где я ошибся?
Куда избыток девается?
не куда, стоит в доохладителе пока насос не выкачает
Dimyn999,
Не будет, он насквозь идёт.
Судя по подключению на фото, спирт проходя через доохлодитедь попадает в насос так? поэтому этот доохлодитель несущественно увеличивает буферную зону, там буквально капли
там буквально капли
Понятно, что капли. Но это у него такой доохладитель. У меня на порядок ёмкость больше. И ещё вопрос:
Трубка внутренним диаметром 2 мм
Через неё 2,4 литра в час самотёком будет литься-то? Уж больно диаметр маленький.
Через неё 2,4 литра в час самотёком будет литься-то? Уж больно диаметр маленький.
будет, я думаю даже больше 3х л в час
Температуру флегмы регулирую пока вручную скоростью потока охлаждайки через дефлегматор.
Есть мысли прикрутить к узлу отбора ds18b20 и корректировать скорость отбора отностительно температуры. Но надо ли?
Не надо...
kvic, опять туплю.В трубку №2 льётся струёй, т.к. ничего, кроме диаметра трубки, не препятствует. А перистальтика уменьшает отбор до покапельного. Куда избыток девается? Накапливается в доохладителе, потом в трубке №2 и потом выше и в итоге возврат в царгу. Где я ошибся?
Избыток из стакана отбора идёт в возврат.
Классическая конструкция же.
В трубку №2 насос засасывает из стакана отбора.
Это своего рода продолжение его.
Длинное и тонкое.
Темп засоса задает контроллер.
Чем быстрее крутишь насос, тем больше скорость отсасывания из стакана.
Насквозь не протечёт, так как сосательная трубка пережата роликами насоса.
Сосает только при движении роликов.
Через неё 2,4 литра в час самотёком будет литься-то? Уж больно диаметр маленький.
Там нет самотёка. Насос принудительно сосает.
С двумясполовиной литрами вполне справляется.
---
Наверное корректнее будет не "доохладитель", а "предохладитель".
Чтобы не путаться.
В трубку №2 насос засасывает из стакана отбора.
Вот! Этого я не знал, спасибо.
Наверное корректнее будет не "доохладитель", а "предохладитель".
Логичнее всё же "доохладитель", ведь он доохлаждает то что не смог охладить димрот по понятным причинам.
Вчера перегонял сс,за весь перегон моторчик останавливался сам по себе раз 10.С чем это связано я не знаю!Рукой помогаешь,продолжает работать.
моторчик останавливался сам по себе раз 10
Стоит и гудит?
Мощи не хватает.
Увеличь ток подстроечником на плате драйвера.
А может бп проседает.
с 321 по 340 из 1 059