Уровень воды в емкости

Maverik
Offline
Зарегистрирован: 12.09.2012

Встретил как-то в сети проект по определению уровня воды в емкости, простой, на четырех транзисторах. Решил добавить туда ардуину.

Вот что исходная схема, только на выходах слева у меня реле и дисплей.

Печатка получилась такая, под arduino pro mini. 

На всякий случай выведены отдельно пины для перепрошивки дуины. Схема функциональная, с запасом, нарисовать ее для лута можно даже маркером.

вверху две большие колодки под провода - слева выходы щупов, справа питание.  6-7 вольт вполне достаточно. 

 

Фото готового девайса

http://savepic.su/5852177.jpg

 

В архиве скетч,  плата в lay6, фотки. 

Техподдержки нет, скетч нормально комментирован. Мне пришел ультразвуковой дальномер так что сделал в результате проект на нём, этот до блеска не допиливал, только убедился в работоспособности.

Maverik
Offline
Зарегистрирован: 12.09.2012

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

подключение дисплея - с 4 по 8 цифровые пины, распиновка в скетче. остальное вроде очевидно. 

архив  здесь https://yadi.sk/d/ECyGiq39kUdQR

скетч. присутствует быдлокод, писал быстро, особо не проверял.  для работы вочдога нужен оптибут.

// УПРАВЛЕНИЕ НАСОСОМ, 3 УРОВНЯ ВОДЫ В БАКЕ

#include <avr/wdt.h>
//#include "Arduino.h"
#include "U8glib.h"
U8GLIB_PCD8544 u8g(8, 7, 6, 5, 4); // подключение дисплея NOKIA 5110, по порядку- SCK=CLK, MOSI=DN, CS=CE, A0=DC, Reset

#define LedPin     13 // пин сигнального светодиода
#define RelePin     2 // пин реле
#define SoundPin    3 // пин звуковой сигнализации

#define LowPin      10 // нижний уровень воды
#define MiddlePin   11 // средний уровень воды
#define UpperPin    12 // верхний уровень воды

int WaterLevel = -1; // 0 - нулевой уровень воды,  1- нижний уровень, 2 - средний уровень, 3 - высокий уровень,  -1 - ошибка
unsigned long PumpingTime = 0;       // текущее время работы насоса (с момента последнего включения)
unsigned long IdleTime = 0;          // текущее вермя простоя насоса (с момента последнего выключения)
unsigned long StartPumpingTime = 0;  // момент последнего включения
unsigned long StopPumpingTime = 0;   // момент последнего выключения
unsigned long Pause = 3000;          // время на техническую паузу между циклами
boolean Pumping = 0;                 // флаг состояния насоса вкл/выкл

String Error  = "";   
String WLevel = "";

void setup()
{
  u8g.setColorIndex(1); // pixel on
  Serial.begin(9600);
  pinMode(LedPin,OUTPUT);
  pinMode(RelePin,OUTPUT);  digitalWrite(RelePin, LOW); delay(100);
  pinMode(SoundPin, OUTPUT);
  pinMode(LowPin,INPUT);      
  pinMode(MiddlePin,INPUT);   
  pinMode(UpperPin,INPUT);  
  delay(1000); 
 // wdt_enable (WDTO_8S);
}

void loop()
{ 
u8g.firstPage();
wDelay(Pause); // пауза цикла + wd_reset
WaterLevel = CheckLevel(); // checking level
if (Pumping) PumpingTime = millis() - StartPumpingTime;  
else         IdleTime = millis() - StopPumpingTime;
CheckErrors();

if (WaterLevel == 0 || WaterLevel ==1 && IdleTime >  60000) // если уровень низкий и время простоя > 1 min
      {  if(!Pumping) PowerOnPump(); 
      }
if (WaterLevel < 2 && IdleTime > 120000) // если уровень средний и время простоя > 2 min
      {  if (!Pumping) PowerOnPump(); 
      } 
if (WaterLevel == 3)
      {  PowerOffPump();
      }       
}

int CheckLevel()
{
 boolean all_OK = 0; // флаг успешности проверки на ошибки
 byte counter = 0;
 while (!all_OK)
   {
   delay(1000);
   WaterLevel == -1;   
   if (digitalRead(UpperPin) == LOW )  // проверить на верхний уровень
       {  if (digitalRead(MiddlePin) == LOW && digitalRead(LowPin) == LOW) WaterLevel = 3; // верхний уровень ДА
         else WaterLevel = -1;                              // ошибка
       }   
   else if (digitalRead(MiddlePin) == LOW )  
       {  if (digitalRead(LowPin) == LOW) WaterLevel = 2;  // средний уровень ДА          
          else WaterLevel = -1;                             // ошибка
       }
   else if (digitalRead(LowPin) == LOW )  WaterLevel = 1;   // нижний уровень ДА
          else WaterLevel = 0;                              // нулевой уровень ДА
   delay(100);
   if (WaterLevel == -1) 
       { delay (1000); counter++; 
         if (counter > 100) return WaterLevel; // появилась ошибка - здесь можно поставить перезагрузку 
       }
   else all_OK = 1; 
   } 
return WaterLevel;
}

void PowerOnPump()
{  if (IdleTime < 120000) delay (120000); // перед включением  насоса задержка на две минуты (debounce)
   PumpingTime = 0; IdleTime = 0;
   if (!Pumping)
     {  digitalWrite(RelePin, HIGH); delay (1000);
        Pumping = 1; StartPumpingTime = millis();
     } 
   else Error = "Already pumping";
}

void PowerOffPump()
{
  PumpingTime = 0; IdleTime = 0;
  delay(100); 
  if (Pumping)
     {  digitalWrite(RelePin, LOW); 
        Pumping = 0; StopPumpingTime = millis();
     } 
   else 
     {  //Error = "Already Stopped"; 
        Pumping = 0;
        digitalWrite(RelePin, LOW); }
}

int CheckErrors()  // проверка ошибочных ситуаций
{ 
  do {draw();} while(u8g.nextPage());
  
  Serial.println("_______________________________");
  if(Pumping) { Serial.print("Pumping time= "); Serial.print(PumpingTime/1000); Serial.println(" sec");  } 
  else       { Serial.print("Idle time= "); Serial.print(IdleTime/1000); Serial.println(" sec");  }
  Serial.print("Water level ="); Serial.println(WaterLevel); 
  
  if (Pumping && PumpingTime > 1200000 && WaterLevel < 1) // ошибка - насос работает больше 20 мин но уровень низкий
    Error = "Slow rate";
  if (Pumping && PumpingTime > 1800000) // ошибка - насос работает больше получаса
    Error = "Long pumping";
  if (WaterLevel == -1) 
    Error = "Wrong level"; // ошибка - одновременно активны верхний и нижний датчкик, но не средний
 
  if (Error)         // обработчик ошибочной ситуации
       { Serial.print("E: "); Serial.println(Error); PowerOffPump(); delay(2000);
             while(1){ tone (SoundPin, 500); delay(100); tone(SoundPin, 1000); delay(100);}
       } 
  else { Serial.println("OK");} 
  Serial.print("Uptime = "); Serial.print(millis()/60000); Serial.println(" min");
}

void wDelay(unsigned long Pau)  // для пауз при активном вочдоге
{  while (Pau >= 5000)  // 
     { delay(5000);  wdt_reset(); Pau = Pau - 5000;}
  delay(Pau);  wdt_reset();    

}

void draw()
{
    if      (WaterLevel == 0) WLevel = " empty";   else if (WaterLevel == 1) WLevel = "   low"; 
    else if (WaterLevel == 2) WLevel = "middle"; else if (WaterLevel == 3) WLevel = "  high"; else WLevel = "-- n/a --";    
    u8g.setFont(u8g_font_5x8r);
    u8g.setPrintPos(2, 10); u8g.print ("On  ="); u8g.setPrintPos(30, 10);  u8g.print(PumpingTime/1000,DEC); u8g.setPrintPos(70, 10);  u8g.print("sec");
    u8g.setPrintPos(2, 20); u8g.print ("Off = ");  u8g.setPrintPos(30, 20); u8g.print(IdleTime/1000,DEC);    u8g.setPrintPos(70, 20);  u8g.print("sec");
    u8g.setPrintPos(2, 30); u8g.print ("Level  =");  u8g.setPrintPos(55, 30);  u8g.print(WLevel);
    u8g.setPrintPos(2, 40); u8g.print ("Uptime =");  u8g.setPrintPos(50, 40); 
    if (Error = "") { u8g.print(millis()/60000); u8g.setPrintPos(70, 40);  u8g.print("min"); }
    else u8g.print(Error);
}