Итак, был заказан контроллер ARDUINO UNO R3, релюхи, светодиоды, набор сопротивлений разного номинала, и датчик температуры DALLAS DS18B20 (по моему так). Всего по 2 штуки, чтобы можно было оперативно заменить. После размышлений как доставить температурный датчик в зону пара в перегонный куб, неожиданно на глаза попался стержень от ручки паркер, он идеально подходил для этой цели: тонкие стенки, с одной стороны он цельный( не надо паять, сминать и тд), подходящий по длине и диаметру. Стержень был схвачен, отпилен со стороны пера и рапотрашен. Для того чтобы избавиться от остатков чернил, стержень был замочен в ацетоне на неделю (просто забыл про него))). Потом вытащил его, протер, после чего он опять валялся неделю. Далее датчик был помещен внутрь стержня и герметизирован силиконовыми прокладками. Форма для запекания из силикона очень выручила, хватило на все не экономя и осталось 70% от нее еще. Дальше стержень был "инсталлирован" )))... Ну не внедрен же)))... в корпус от выпускного клапана через силиконовые прокладки. Можно было конечно заказать у китайцев готовый термометр в герметичном корпусе, но не заказался как то.

 

IMG 20150712 200623 320x320Все было собрано, программулина написана, собран из коробки и лампы стенд для испытаний, отработана логика /уж какая была, исходя из моего тогдашнего опыта и представления о процессе/, но опять же спешка, подходила брага, да и дел кучу никто не отменял, найти и купить градусник для измерения реальной температуры не удосужился.

Схема первого варианта автоматики (во втором варианте убрал блок из 5 светодиодов и поставил экран от нокиа5510, купленный на aliexpress, по программке можно запросто разобраться что куда подключено, схема как пример подключения элементов):

Схема автоматики самогонного аппарата

 

После первой же перегонки был заказан электронный градусник и было обнаружено что:
1. Разность в показании градусника и датчика примерно в 2 градуса (так и не определился чему верить), причем инертность самого датчика на остывание достаточно большая, но это не принципиально.
2. Установленный киловатный тэн, в режиме работы 4/6, 4/7 (нагрев, сек/пауза, сек) практически до конца перегонки поддерживает очень плавное повышение температуры, 0.3-0.5 градусов минут за 20-30, при этом процесс не останавливается и идет постоянно.
3. Выявлен косяк с работой китайских реле.
Реле от стандартного шилда для ардуины на 10А не подойдут. Было непонятно что происходит, какой то промежуток все работало нормально, потом температура начинала быстро расти и спасало только отключение аппарата. Стало понятно что реле не справляется с возложенной на нее функцией. Контакты залипали и в один прекрасный момент контакты реле просто приварились. Срочно реле была заменена для окончания перегонки на новую, после чего начались поиски более надежного варианта.IMG 20150712 223137 320x320

 

  Было решено управлять симистором с помощью реле или оптопары. Сначала был установлен небольшой симистор, в последствии он был утерян и по маркировке ничего сказать и посмотреть уже не могу, но он достаточно сильно грелся. После этого был раздобыт монстрячий симистор BTA41-800B (40А по даташиту) и прикрутил его к достаточно большому радиатору. Но и эта связка при работе ТЭНа на полной мощности нагревается, без вентилятора как то страшновато, поставил вентилятор - проблем нет.

 

CYMERA 20150712 225655 400x400Схема:

sxema 640x606

 

 Вердикт: работает прекрасно, без нареканий и неожиданностей. Пока включаю вентилятор на первичный нагрев, далее автоматизирую этот процесс (в дальнейших модификациях выполнено).

После того как я перестал думать что контакты релюхи могут залипнуть и процесс превратится в неуправляемый, пошла дальнейшая модернизация.

Вид автоматики:

вид и состав автоматики на ардуино

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

Цель: насколько это возможно оптимизировать процесс и устраниться от контроля за ним (очно-визуальным по крайней мере).

Сейчас идея программки (скетча) такая:

  1. вначале цикла делаем запрос температурному датчику, засекаем время обращения по прошествии секунды получаем от него температуру. Это делаю потому что иначе с кнопками траблы получаются, если delay (1000) выставить.
  2. дальше кнопками определяем переменные, которые потом обрабатываются условиями.
  3. и собственно сами условия.

Скетч (скачать)

Скетч на этой странице

Строго не судить, я понимаю что можно было сделать красивее, можно было применять функции... но так как я его кучу раз допиливал и писал иногда в автобусе на планшете - так получилось. Коментарии некоторые тоже старые и неактуальные - обещаю разобраться /не сделано - не вижу смысла, новый скетч хорошо комментирован и более функционален/.

К этому моменту проведено достаточно много перегонок и опытным путем было определено, что для отбора голов оптимален режим нагрева (тем же киловатным тэном, нагрев, сек/пауза, сек) 4/7 - это и есть мощность старта перегонки после начала процесса. Далее я определился что две прегонки - это минимальное количество. Соответственно первая перегонка может быть автоматизирована от окончания отбора голов и до достижения заданной, определенной мной температуры. Вторая перегонка по определению дробная, празничная и подлежащая дегустации)))... здесь автоматика лишняя (неправильно думал, вторую перегонку тоже можно автоматизировать и прекратить по достижению 45-50%), но необходимо в ручном режиме влиять на мощность нагрева, не часто, но нужно. Также было бы неплохо оповещать звуком о наполнении очередного поллитра (а то бегай смотри как там))) - это решается достаточно просто, если есть свободные пины на контроллере. В дальнейшем есть еще мысли по модернизации - внедрение веб-сервера для контроля с дивана за процессом, но это попозже)))

Что-то переделать (модернизировать) - сложней чем сделать заново. Установленный ЖК-экран, 4 кнопки, 3 светодиода, бипер, термодатчик и реле отъели все пины на контроллере, оставив только 2 аналоговых. Все это изначально не задумывалось и не планировалось, поэтому получился такой затык... 2 пина конечно хватит для внедрения контроля за наполнением емкости, но не спасет от полной переделки, т.к. есть задумка как это все сделать более компактно и с большим функционалом и комфортом опять же)))


программка для ардуино:

#include <OneWire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
OneWire  ds(10);
// D7 - Serial clock out (CLK oder SCLK)
// D6 - Serial data out (DIN)
// D5 - Data/Command select (DC oder D/C)
// D4 - LCD chip select (CE oder CS)
// D3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
int ReleDevice = 2;         //реле подключено ко 2му пину
int LedReleDevice = A2;     // светодиод индикации работы реле
int Beeper = 9;             // BEEPER PIN
int StartShow = 0;          // переменная для перебора светодиодов при старте
int LedPin1 = A0;           // светодиод кнопки 1 на порту A0
int ButPin1 = 8;            // Кнопка 1 на пине 8
int LedPin2 = A1;           // светодиод кнопки 2 на порту A1
int ButPin2 = 13;           // Кнопка 2 на пине 13
int FlipButMinus = 12;      // Кнопка "Качелька минус"
int FlipButPlus = 11;       // Кнопка "Качелька плюс"
int flag_B1 = 0;            // флаг состояния кнопки 1 (используется для отслеживания срабатывания кнопки)
int flag_B2 = 0;            // флаг состояния кнопки 2 (используется для отслеживания срабатывания кнопки)
int flag_FlipButMinus = 0;  // флаг состояния "Качелька минус" (используется для отслеживания срабатывания кнопки)
int flag_FlipButPlus = 0;   // флаг состояния "Качелька плюс" (используется для отслеживания срабатывания кнопки)
int OnOff = 0;              // переменная вкл и выкл режима начального нагрева до 68 град (кнопка 1)
int HeadOff = 0;            // переменная окончания режима отбора голов и начало нагрева до 78 град (кнопка 2)
int BasicModeU = 4;          // режим переключения пошагового набора температуры (с помощью качельки)
int BasicModeD = 7;          // режим переключения пошагового набора температуры (с помощью качельки)
int TempUpSlow = 0;         // переменная отслеживания режима быстрого/плавного нагрева
// начальное соотношение нагрев/пауза
unsigned long tD = 7000;   // (time down) время отключенного реле в режиме плавного нагрева (mсек)
unsigned long tU = 4000;   // (time up) время включенного реле в режиме плавного нагрева (mсек)
unsigned long tDr = 0;
unsigned long tUr = 0;
// ***
unsigned long AllTime;      // переменная для записи времени прошедшего со старта программы
unsigned long MemTime;      // переменная для записи времени начала события относительно времени прошедшего с начала программы
unsigned long AllTempTime;     // переменная для записи времени прошедшего со старта программы для опроса DALLAS DS18 (температуры)
unsigned long MemTempTime;     // переменная для записи времени начала события относительно времени прошедшего с начала программы для опроса DALLAS DS18 (температуры)
int flagTemp = 0;           // переменная отслеживания опроса датчика температуры
int tTempTemp = 0;           // временная переменная для записи расчета времени с последнего опроса датчика, не совсем верно, но по коду можно разобраться зачем))))
int Temp = 0;
int data[10];
int TempBeepMode_1 = 0;     // | переменные для бипера при вкл/откл реле
int TempBeepMode_2 = 0;     // |
int TempBeepMode_3 = 0;     // |
int TempBeepMode_4 = 0;     // |
int TempBeepMode_5 = 0;     // |
int TempBeepMode_6 = 0;     // |
int TempBeepMode_7 = 0;     // |
int Temp1 = 87;
int Temp2 = 89;
int Temp3 = 91;
int TempEnd = 96;
unsigned long tD1 = 6000;
unsigned long tD2 = 5000;
unsigned long tD3 = 4000;
void setup()
{
  display.begin(); // инициализируем дисплей
  display.setContrast(60);  // устанавливаем контраст LCD
  display.clearDisplay();   // очищаем экран
  pinMode(LedPin1, OUTPUT);   
  pinMode(LedPin2, OUTPUT);
  pinMode(ReleDevice, OUTPUT);
  pinMode(Beeper, OUTPUT);
  pinMode(LedReleDevice, OUTPUT);
  digitalWrite(ReleDevice, 0);
  digitalWrite(LedReleDevice, 0);
  Serial.begin(9600);
//  analogWrite(9, 20);          // значение должно находится между 0 и 255
  delay(100);
 // analogWrite(9, 0);
    delay(50);
//  analogWrite(9, 20);          // значение должно находится между 0 и 255
  delay(100);
//  analogWrite(9, 0);
    delay(50);
//      analogWrite(9, 20);      // значение должно находится между 0 и 255
  delay(100);
//  analogWrite(9, 0);
    delay(50);
}  
 void BeepFunction(){
      analogWrite(9, 20);      // +BEEP значение должно находится между 0 и 255
      delay(30);
      analogWrite(9, 0);       // -BEEP
    }
void loop()
{
  // *** НАЧАЛО ТЕМПЕРАТУРА
    
if (flagTemp == 0){
    byte data[2];                             // | если включили основной режим (до 78 град) |
    ds.reset();                               // | измеряем температуру и разблокируем блок  |
    ds.write(0xCC);                           // | 5ти светодиодов                           |
    ds.write(0x44);
  flagTemp = 1;              // выставляем флаг на пропуск этого блока, пока не пройдет 1000 мс  
  MemTempTime = millis();   // засекаем время
  }else{
      AllTempTime = millis();  //
      tTempTemp = AllTempTime - MemTempTime;
      if (tTempTemp < 1000){
       flagTemp = 1;
      }else{
flagTemp = 0;
    ds.reset();
    ds.write(0xCC);
    ds.write(0xBE);
    data[0] = ds.read();
    data[1] = ds.read();
    Temp = (data[1]<<8)+data[0];
    Temp = Temp>>4;
  }
  }
  // *** КОНЕЦ ТЕМПЕРАТУРЫ
 
       // *** НАЧИЛО КНОПКИ
 
     // кнопка 1 (OnOff)
 
 if (digitalRead(ButPin1) == HIGH && flag_B1 == 0)
    {                                           
      digitalWrite(LedPin1, !digitalRead(LedPin1));  //изменяем состояние LED1
      flag_B1 = 1;                                   //ставим флаг нажатия кнопки
      BeepFunction();
      if(OnOff == 0)
      {          // OnOff = 1 - это постоянно включенное реле
      OnOff = 1;
      TempUpSlow = 0;
      }else if(OnOff == 1){          // OnOff = 2 - это режим плавного нагрева вкл./выкл. (tD; tU)
      OnOff = 2;
      TempUpSlow = 0;
    }else{
      OnOff = 0;
      HeadOff = 0;
      TempUpSlow = 1;
      digitalWrite(LedPin1, 0);
      digitalWrite(LedPin2, 0);
   }
    }
 if(digitalRead(ButPin1) == LOW && flag_B1 == 1)
    {
      flag_B1 = 0;
    }
    // End кнопка 1
    // кнопка 2 (HeadOff)
 if(digitalRead(ButPin2) == HIGH && flag_B2 == 0 && OnOff != 0)
    {                                              
      digitalWrite(LedPin2, !digitalRead(LedPin2));
      flag_B2 = 1;
      BeepFunction();
    if(OnOff != 0 && HeadOff == 0){
      HeadOff = 1;
      }else if(OnOff != 0 && HeadOff == 1){
      HeadOff = 2;
    }else{
      HeadOff = 0;
   }
    }  
 if(digitalRead(ButPin2) == LOW && flag_B2 == 1)
    {
      flag_B2 = 0;
    }                                                  
       // End кнопка 2
       // качелька ПЛЮС
       if(digitalRead(FlipButPlus) == HIGH && flag_FlipButPlus == 0 && OnOff != 0)
    {                                              
      flag_FlipButPlus = 1;
    if(BasicModeU != 20 && HeadOff == 0){
      BasicModeU = BasicModeU+1;
      TempUpSlow = 0;
      tU = (BasicModeU*1000);
      BeepFunction();
      }else if(BasicModeU == 20 && HeadOff == 0){
      BasicModeU = 20;
      TempUpSlow = 0;
      BeepFunction();     
      }else if(BasicModeD != 20 && HeadOff == 1){
      BasicModeD = BasicModeD+1;
      TempUpSlow = 0;
      tD = (BasicModeD*1000);
      BeepFunction();
      }else if(BasicModeD == 20 && HeadOff == 1){
      BasicModeD = 20;
      TempUpSlow = 0;
      BeepFunction();     
   }
    }
 if(digitalRead(ButPin2) == LOW && flag_FlipButPlus == 1)
    {
      flag_FlipButPlus = 0;
    }                           
    // End качелька ПЛЮС
       // качелька МИНУС
       if(digitalRead(FlipButMinus) == HIGH && flag_FlipButMinus == 0 && OnOff != 0)
    {                                              
      flag_FlipButMinus = 1;
    if(BasicModeU != 1 && HeadOff == 0){
      BasicModeU = BasicModeU-1;
      TempUpSlow = 0;
      tU = (BasicModeU*1000);
      BeepFunction();
      }else if(BasicModeD == 1 && HeadOff == 0){
      BasicModeU = 1;
      TempUpSlow = 0;
      BeepFunction();     
   }
    if(BasicModeD != 1 && HeadOff == 1){
      BasicModeD = BasicModeD-1;
      TempUpSlow = 0;
      tD = (BasicModeD*1000);
      BeepFunction();
      }else if(BasicModeD == 1 && HeadOff == 1){
      BasicModeD = 1;
      TempUpSlow = 0;
      BeepFunction();     
   }
    }
 if(digitalRead(ButPin2) == LOW && flag_FlipButMinus == 1)
    {
      flag_FlipButMinus = 0;
    }
    // End качелька МИНУС
    // BODY
if(OnOff != 0 && HeadOff == 2 && Temp >= Temp1 && Temp < Temp2){
 tD = tD1;
}else if (OnOff != 0 && HeadOff == 2 && Temp >= Temp2 && Temp < Temp3){
 tD = tD2;
}else if (OnOff != 0 && HeadOff == 2 && Temp >= Temp3 && Temp < TempEnd){
 tD = tD3;
}else if (OnOff != 0 && HeadOff == 2 && Temp == TempEnd){
OnOff = 0;
HeadOff = 0;
digitalWrite(LedPin1, 0);
digitalWrite(LedPin2, 0);
TempUpSlow = 0;
      digitalWrite(ReleDevice, 0);
      digitalWrite(LedReleDevice, 0);
}
   if (OnOff == 0 && Temp > Temp1){
   BeepFunction();
   delay(1500);
   }
   else if (OnOff == 1)
   {                                           // нажимаем кнопку OnOff 1 раз - постоянный нагрев (OnOff = 1)
    digitalWrite(ReleDevice, 1);
    digitalWrite(LedReleDevice, 1);
//###########################################    
    }
    else if(OnOff == 2)
    {         // нажимаем кнопку OnOff 2 раза - плавный-регулируемый нагрев (OnOff = 2)
//###########################################
if (HeadOff == 2){
  digitalWrite(LedPin2, !digitalRead(LedPin2));
}
    if (TempUpSlow == 0){                     //цикл вкл\выкл не начался
    TempUpSlow = 1;      // говорим что запустили плавный режим
    MemTime = millis();   // засекаем время
    digitalWrite(ReleDevice, 0);
    digitalWrite(LedReleDevice, 0);
//###########################################    
    }else{
      AllTime = millis();  //
      if(tD > AllTime-MemTime){
        tUr = 0;
        tDr = AllTime-MemTime;
      digitalWrite(LedPin1, !digitalRead(LedPin1));  // моргаем светодиодом первой кнопки
      digitalWrite(ReleDevice, 0);                   // выключаем реле
      digitalWrite(LedReleDevice, 0);                // выключаем светодиод индикации работы реле  
//###########################################      
      }else if(tU > AllTime-MemTime-tD){
        tDr = 0;
        tUr = AllTime-MemTime-tD;
      digitalWrite(LedPin1, !digitalRead(LedPin1));
      digitalWrite(ReleDevice, 1);
      digitalWrite(LedReleDevice, 1);
//###########################################      
      }else{
      TempUpSlow = 0;
      digitalWrite(ReleDevice, 0);
      digitalWrite(LedReleDevice, 0);
      }
    }
    }
    // END BODY
  display.clearDisplay();
  display.setTextSize(1);
  display.print("Temp = ");
  display.println(Temp);
  display.drawLine(0, 11, 84, 11, BLACK);
  display.println(" ");
  display.print("U> ");
  if (tU/1000 < 10){
  display.print(" ");
  display.print(tU/1000);
  display.print(" | ");
  display.println(tUr);
  }else{
  display.print(tU/1000);
  display.print(" | ");
  display.println(tUr);
  }
  display.print("D> ");
  if (tD/1000 < 10){
  display.print(" ");
  display.print(tD/1000);
  display.print(" | ");
  display.println(tDr);
  }else{
  display.print(tD/1000);
  display.print(" | ");
  display.println(tDr);
  }
  display.drawLine(0, 35, 84, 35, BLACK);
  display.println(" ");
  if (HeadOff == 0 && OnOff == 0){
  display.println(" DISTSYS.RU ");    
  }else if (OnOff != 0 && HeadOff == 0){
  display.println("EDIT UP Time");    
  }else if (OnOff != 0 && HeadOff == 1){
  display.println("EDIT DOWN Time");    
  }else if (OnOff != 0 && HeadOff == 2){
  display.println("AUTOMATIC MODE");    
  }
  display.display();
  delay(100);
}
void set_text(int x,int y,String text,int color){ 
  display.setTextColor(color);
  display.setCursor(x,y);
  display.println(text);
  display.display();
}
 

 

На этом с данной верстей закончено, собрана версия 2, о ней в другой статье, а этот " прототип" разобран.