Valdiklio programa

Karšto vandens saulės kolektoriaus valdiklio programa (su apsauga nuo užšalimo)
// *****************************************************************************************************
//                                  W W W . S a u l e V i r e . l t
// ********************************************************************************************************                                  
// Projektas pavadinimu "pasidaryk pats mikrprocesorinį karšto vandens saulės kolektoriaus valdiklį".
// Visi failai yra ir čia:- http://fritzing.org/projects/hot-water-solar-controller/
// ********************************************************************************************************
//                              P  A  K  E  I  T  I  M  A  I
// ********************************************************************************************************
// 2013 12 27
// Išgaudytos klaidos, sugedus davikliams įjungiamas siurblys kolektoriaus apsaugojimui nuo perkaitimo
// pagal tokį algoritma:
// Jei kolektoriaus temperatūros jutiklis neveikia, įjungiamas siurblys. 
// Kas kiek laiko nurodo kintamasis REQUEST_Collector_Error
// Jei po siurblio įjungimo boilerio temperatūra mažėja, siurblys išjungiamas.
// Jei blogas boilerio daviklis, o kolektoriaus temperatūra didesnė negu 95 laipsniai, įjungiamas siurblys, 
// kai kolektoriaus temperatūra nukrenta iki 85 laipsnių, siurblys išjungiamas.
// 2013 12 21
// Pataisyta apsauga nuo užšalimo. Tikrinama kas 5 sek. Galima laiką keisti keičiant kintamąjį- REQUEST_freezing 
// Galima atjungti 3 temperatūros daviklį, jei jis nenaudojamas keičiant kintamojo "Temp3_daviklis" reikšmę.
// Kintamasis trečio daviklio naudojimui 0- nenaudojamas, 1- naudojamas. Rodoma klaida, jei daviklis nepajungtas ar blogas.
// 2013 12 15
// kosmetiniai pataisymai : pataisytas LCD info rodymas, pataisytas į nuoseklujį prievadą išvedamų duomenų formatas 
// 2013 11 28
// pataisyta "apsaugos nuo užšalimo" klaida. Priskirus kintamąjam "freezing" reikšmę "0", apsauga neišsijungdavo.
// 2013 05 12
// Pridėta galimybė pasirinkti montažinės plokštės versiją. Lietuvoje ir Kinijoje gamintose plokštelėse
// panaudoti skirtingi procesoriaus išvadai. Todėl prieš įrašydami pasirinkite su kuria plokštele procesorius dirbs.
// Ieškokite eilutės "VERSIJA"
// 2013 05 05
// ekrane rodoma žvaigždutė, jei įjungta apsauga nuo užšalimo
// 2013 04 23 
// pridėtas kintamasis "freezing" apsaugai nuo užšalimo įjungti (freezing = 1) arba išjungti (freezing = 0)
// --------------------------------------------------------------------------------------------------------
// Reikalingos bibliotekos:
// "Dallas Temperature Control" biblioteką rasite čia:
// http://milesburton.com/index.php?title=Dallas_Temperature_Control_Library
// OneWire (Version 2.1) biblioteką  rasite čia:
// http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip
// Bibliotekas reikia ispakuoti į c:\arduino-X.x.x\library katalogą. c:\arduino-X.x.x\library\dallas-temperature-control
// katalogą reikia pervardinti į c:\arduino-X.x.x\library\DallasTemperatureControl (be brūkšnelių)
// ****************************************************************************************************************
// 1. Kai temperatūros skirtumas tarp saulės kolektoriaus ir boilerio didesnis kaip 5 laipsniai, įjungiama relė. 
// 	Tempertūra matuojama ir rodoma ekrane nuolat, bet skirtumas tikrinamas kas 15 sekundžių.
// 2. Kai temperatūros skirtumas tarp saulės kolektoriaus ir boilerio mažesnis kaip 2 laipsniai, siurblį valdanti relė išjungiama.
// 	Skirtumas tikrinamas kas 15 seundžių.
// 3. Potenciometru galima užduoti bet kokį skaičių nuo 0 iki 100, jis rodomas ekrane. Kai 3-čio daviklio temperatūra
// 	pasieks nurodytą ribą įsijungs 2-oji relė. Temperatūrai nukritus žemiau nurodytos ribos relė išsijungs. 
// 4. Vietoj dviejų daviklių (išlitavus 2 varžas arba perpovus takelį plokštėje) galima jungti dar vieną 2 kanalų 
// 	relių modulį, o reikiamus daviklius jungti nuosekliai ant vieno laido. Kad valdiklis veiktų po tokių pakeitimų
// 	reikia minimalių programos patobulinimų. 
// 5. Daviklius DS18b20 galima jungti 2 arba 3 laidais. 
// 6. Ekrane rodoma boilerio temperatūra, kolektoriaus temperatūra, temperatūrų skirtumas,
// 	3-čio daviklio temperatūra, potenciometru nustatyta temperatūra, relių būsena.
// 7. Jei kolektoriaus temperatūra mažesnė arba lygi 0, įjungiamas siurblys ir kolektorius apsaugomas nuo užšalimo.	
// *******************************************************************************************************************
// 

#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
boolean bBlink = true;

//#define VERSIJA 10 //reikia ištrinti du pirmus eilutės simbolius, jei plokštelė gaminta Lietuvoje, (vario-geltona spalva)
//#define VERSIJA 11 //reikia ištrinti du pirmus eilutės simbolius, jei ant Jūsų polokštelės yra  www.SauleVire.lt reklama ir užrašas "Order #100010284"

#ifndef VERSIJA 
#error "Jus turite pasirinkti kintamojo VERSIJA reiksme. Nuimkite komentarų simbolius (//) vienoje is eiluciu #define VERSIJA 10 (arba 11)"
#endif

// jei Jūsų plokštelė tokia (kitokia)
#if  VERSIJA == 10
#define Pump 11 //Siurblio valdymo relės išvadas
#define Relay2 12 //Termostato valdymo relės išvadas
int analogPin =  A0; //daugiasūkio rezistoriaus pajungimo išvadas
// versijos 10 pasirinkimo pabaiga
#else
// Čia antrojoje plokštelės versijoje (gaminta Kinijoje, žalia spalva) naudojami išvadai 
//jei Jūsų plokštelė tokia (kitokia)
#define Pump A0 //Siurblio valdymo relės išvadas
#define Relay2 A1 //Termostato valdymo relės išvadas
int analogPin = A2; ////daugiasūkio rezistoriaus pajungimo išvadas
// versijos 11 pasirinkimo pabaiga
#endif

#define SERIAL_BAUD_RATE 9600
// Temperatūros jutiklių duomenų laidai prijungti prie Arduino išvadų 8,9,10
#define Collector 8 //Kolektoriaus jutiklio išvadas
#define Boiler 9 //Boilerio jutiklio išvadas
#define Temp_3 10 //termostato jutiklio išvadas

int relayPin = Pump;
int relay2Pin = Relay2;
static long timer_pump=0;
static long timer_Relay2=0;
static long timer_freezing=0;

static long timer_Collector_Error=0;
static long timer_Boiler_Error=0;
//Laiko intervalai
// REQUEST_Pump_Control minimalus siurblio reles veikimo laiko intervalas, pasikeitus temperatūrų reikšmėms
// REQUEST_Relay2_Control minimalus termostato reles veikimo laiko intervalas, pasikeitus temperatūrų reikšmėms
// REQUEST_Collector_Error laiko intervalas veiksmui, jei kolektoriaus temperatūros jutiklis rodo klaidą
// REQUEST_Boiler_Error laiko intervalas veiksmui, jei boilerio temperatūros jutiklis rodo klaidą
#define REQUEST_Pump_Control 10000          // 10000 millis= 10 sekundziu
#define REQUEST_Relay2_Control 10000       // 15000 millis= 15 sekundziu
#define REQUEST_Collector_Error 600000    // 10minuciu
#define REQUEST_Boiler_Error 10000       // 30000 millis= 30 sekundziu
#define REQUEST_freezing 5000          // 30000 millis= 30 sekundziu

int freezing = 1; //kintamasis apsaugai nuo užšalimo įjungti (freezing = 1) arba išjungti (freezing = 0)
int Temp3_daviklis = 1 ; //kintamasis trečio daviklio naudojimui 0- nenaudojamas, 1- naudojamas
int Differential_ON=5; //Čia užduodama prie kokio temperatūrų skirtumo įjungiama kolektoriaus siurblio relė
int Differential_OFF=3; //prie tokio skirtumo siurblio relė išjungiama
int Collector_Error, Boiler_Error,Temp_3_Error; // jutiklio būsenos "klaida" žymė
float Collector_tempC, Boiler_tempC, Sensor3_tempC; //kintamieji temperatūros matavimų reikšmėms saugoti
float Saved_Collector_tempC, Saved_Boiler_tempC;
//Siurblio įjungimo simbolis (rodyklė į viršų)
byte arrow_up[8]={ B00100,B01110,B11111,B00100,B00100,B00100,B00100,B00100};
//Siurblio įšungimo simbolis (rodyklė į žemyn)
byte arrow_down[8]={ B00100,B00100,B00100,B00100,B00100,B11111,B01110,B00100};

      // nustatomos reikšmės valdiklio "susikalbėjimui" su jutikliais DS18B20
      OneWire Collector_T(Collector);
      OneWire Boiler_T(Boiler);
      OneWire Temp_T(Temp_3);
      DallasTemperature CollectorSensor(&Collector_T);
      DallasTemperature BoilerSensor(&Boiler_T);
      DallasTemperature TempSensor(&Temp_T);
      //masyvai jutiklių adresams saugoti
      DeviceAddress Collector_Sensor_Address;
      DeviceAddress Boiler_Sensor_Address;
      DeviceAddress Temp_3_Sensor_Address;

// LCD ekrano nustatymai
// prijungimas:
// rs (LCD išvadas 4) - Arduino išvadas 2
// enable (LCD išvadas 6) - Arduino išvadas 3
// LCD išvadas 15 - Arduino išvadas 13
// LCD išvadai d4, d5, d6, d7 - Arduino išvadai 4, 5, 6, 7

int backLight = 13;    // išvadas 13 valdo ekrano apšvietimą
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
// Kintamasis termostato užduotai reikšmei saugoti
int val = 0;
//Programos nustatymų pradžia
void setup() {
  Serial.begin(SERIAL_BAUD_RATE);
  pinMode(Pump, OUTPUT);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Pump, HIGH);
  digitalWrite(Relay2, HIGH);
  // Arduino išvadų paruošimas darbui su LCD ekranu:
  pinMode(backLight, OUTPUT);
  pinMode(backLight, OUTPUT);
  analogWrite(backLight, 200); // Įjungiamas apšvietimas.
  lcd.createChar(1, arrow_down);
  lcd.createChar(2, arrow_up);

  lcd.begin(16, 2);
  // Reklaminio užrašo išvedimas į ekraną (TAI LABAI SVARBU :-).
          lcd.print("www.SauleVire.lt");
          lcd.setCursor(0,1);lcd.print("      v2.0      ");
          Serial.println();
          Serial.println("www.SauleVire.lt");
		Serial.print("Siurblys isijungs, kai temperaturu skirtumas bus - ");  Serial.println(Differential_ON);
		Serial.print("Siurblys issijungs, kai temperaturu skirtumas bus - ");  Serial.println(Differential_OFF);
		if (freezing == 1) {Serial.println("IJUNGTA kolektoriaus apsauga nuo uzsalimo");}
		else {Serial.println("Kolektoriaus apsauga nuo uzsalimo NEIJUNGTA");}
          delay(5000); //Reklama trunka tik 5 sekundes.
          lcd.clear();
CollectorSensor.begin();
          if (!CollectorSensor.getAddress(Collector_Sensor_Address, 0))
          Serial.println("neveikia kolektoriaus temperaturos daviklis");
          // nustatomas didžiausias jutiklio tikslumas- 12 bitų.
          CollectorSensor.setResolution(Collector_Sensor_Address, 12);
BoilerSensor.begin();
          if (!BoilerSensor.getAddress(Boiler_Sensor_Address, 0))
          Serial.println("Neveikia boilerio temperaturos daviklis");
          // nustatomas didžiausias jutiklio tikslumas- 12 bitų.
          BoilerSensor.setResolution(Boiler_Sensor_Address, 12);
TempSensor.begin();
          if (!TempSensor.getAddress(Temp_3_Sensor_Address, 0))
          Serial.println("Neveikia Temp_3 temperaturos daviklis");
          // nustatomas didžiausias jutiklio tikslumas- 12 bitų.
          TempSensor.setResolution(Temp_3_Sensor_Address, 12);          
} 
//____________________________
//Programos nustatymų pabaiga
//____________________________
void loop() { //Prasideda pagrindinė programa
bBlink = ((bBlink) ? false : true);
 Serial.println();
 Serial.print("Siurblys isijungs, kai temperaturu skirtumas bus - ");  Serial.println(Differential_ON);
 Serial.print("Siurblys issijungs, kai temperaturu skirtumas bus - ");  Serial.println(Differential_OFF);

if (freezing == 1) {lcd.setCursor(14,0);
        Serial.println("Kolektoriaus apsauga nuo uzsalimo I_J_U_N_G_T_A");
 	lcd.print("*");
 }else {
        Serial.println("Kolektoriaus apsauga nuo uzsalimo N_E_I_J_U_N_G_T_A");
	lcd.setCursor(14,0);
	lcd.print(" ");}

// ******************* trečiojo daviklio naudojimas  P_R_A_D_Ž_I_A *****************************************
 if (Temp3_daviklis == 1){
 val = (analogRead(analogPin) * 100.0) / 1024; //nuskaitoma kintamu rezistoriumi nustatyta termostato reikšmė ir
lcd.setCursor(7,1);
   lcd.print("N");
   lcd.setCursor(8,1);
   lcd.print(val); //parodoma ekrane

if (!TempSensor.getAddress(Temp_3_Sensor_Address, 0)) {
   lcd.setCursor(10,1);
  if (bBlink) lcd.print("KLAIDA!");
  else lcd.print("-------");
   Serial.println("3 daviklio temperatura: K_L_A_I_D_A");
   Temp_3_Error=1;
}
else 
{
  TempSensor.requestTemperatures();
  Sensor3_tempC=TempSensor.getTempC(Temp_3_Sensor_Address);
  Serial.print("Nustatyta termostato reiksme "); Serial.println(val); //spausdinama į terminalą, jei prijungtas kompiuteris
  Sensor3_tempC=TempSensor.getTempC(Temp_3_Sensor_Address);

  if (Sensor3_tempC==-127){lcd.setCursor(10,1);
  if (bBlink)lcd.print("KLAIDA");
  else lcd.print("------"); 
  Serial.println(" K L A I D A !"); Temp_3_Error=1;
  } else {
  lcd.setCursor(10,1);lcd.print(" ");lcd.print(Sensor3_tempC);
  Serial.print("Ismatuota termostato reiksme "); Serial.println(Sensor3_tempC);}
    if (millis() > timer_Relay2 + REQUEST_Relay2_Control) {
  timer_Relay2 = millis();
// Jei potenciometru nustatyta temperatura mazesne, negu ismatuota 3-ciuoju davikliu, RELE IJUNGIAMA  
  if (Sensor3_tempC >= val)  Rele_2_ijungta(); 
  if (Sensor3_tempC <= val)  Rele_2_isjungta();
// Jei potenciometru nustatyta temperatura Didesne, negu ismatuota 3-ciuoju davikliu, RELE IJUNGIAMA  
//  if (Sensor3_tempC <= val)  Rele_2_ijungta(); 
//  if (Sensor3_tempC >= val)  Rele_2_isjungta();

 }
}} 
// ************************** trečiojo daviklio naudojimas  P_A_B_A_I_G_A *************************

  if (!BoilerSensor.getAddress(Boiler_Sensor_Address, 0)) {
  lcd.setCursor(0,1);
  if (bBlink) lcd.print("KLAIDA!"); 
  else lcd.print("-------");
  Serial.println("Boilerio Temperatura: K_L_A_I_D_A");
  Boiler_Error=1;
  }
else{
BoilerSensor.requestTemperatures();
Serial.print("Boilerio temperatura: ");
Boiler_tempC=BoilerSensor.getTempC(Boiler_Sensor_Address);
if (Boiler_tempC==-127.00){
  lcd.setCursor(0,1);
  if (bBlink) lcd.print("KLAIDA!"); 
  else lcd.print("-------");
  Serial.println(" K L A I D A !");
  Boiler_Error=1;
}
else{
Serial.println(Boiler_tempC);
  lcd.setCursor(0,1);
  lcd.print("B");
  lcd.setCursor(1,1);
  lcd.print(Boiler_tempC);
  lcd.print(" ");
  Boiler_Error = 0;
}}

if (!CollectorSensor.getAddress(Collector_Sensor_Address, 0)) {
   lcd.setCursor(0,0);
  if (bBlink) lcd.print("KLAIDA!");
  else lcd.print("-------");
   Serial.println("Kolektoriaus Temperatura: K_L_A_I_D_A");
   Collector_Error=1;
}else{
  CollectorSensor.requestTemperatures(); // Komanda jutikliui parodyti išmatuotą temperatūrą
Serial.print("Kolektoriaus Temperatura: ");
Collector_tempC=CollectorSensor.getTempC(Collector_Sensor_Address);
if (Collector_tempC==-127.00){
  lcd.setCursor(0,0);
  if (bBlink) lcd.print("KLAIDA!");
  else lcd.print("-------");
  Serial.println(" K L A I D A !");
  Collector_Error=1;
  }else{
Serial.println(Collector_tempC);
  lcd.setCursor(0,0);
  lcd.print("K");
  if (Collector_tempC >= 0) lcd.print(" "); 
  else lcd.setCursor(1,0);
  lcd.print(Collector_tempC);
  lcd.setCursor(8,0);
  if (Collector_tempC-Boiler_tempC >=0) lcd.print(" ");
  lcd.print(Collector_tempC-Boiler_tempC);
  if (Collector_tempC-Boiler_tempC <=10) lcd.print(" ");
  Collector_Error = 0;
  }}

// Tikrinama ar reikia apsaugos nuo užšalimo PRADŽIA
if (millis() > timer_freezing + REQUEST_freezing) {
    timer_freezing = millis();
if (freezing == 1) { //jei apsauga įjungta,
	//tikrinama ar kolektoriaus temperatūra teigiama
if ((Collector_tempC  <= 0 ) && (Collector_Error == 0)) { //jei temperatūra neigiama, 
   Siurblys_ijungtas();       //įjungiamas siurblys
   Serial.println("I_J_U_N_G_T_A_S siurblys apsaugai nuo uzsalimo");
   } 
      }
} 
// Tikrinimo ar reikia apsaugos nuo užšalimo PABAIGA

//__________________________________________________
//Tikrinama kokia turį būti siurblio būsena. Pradžia
//--------------------------------------------------
//kintamasis REQUEST_Pump_Control nurodo kas kiek laiko tai daryti
if (millis() > timer_pump + REQUEST_Pump_Control) {
    timer_pump = millis();
if (Boiler_Error == 0){ // jei boilerio daviklis geras
if (Collector_Error == 0){ // jei kolektoriaus daviklis geras
//tikrinama at kolektorius nėra šiltesnis už boilerį	
if (Collector_tempC - Boiler_tempC >= Differential_ON) {
   Siurblys_ijungtas();
   Serial.println("___________________________");
   Serial.println("Siurblys- _I_J_U_N_G_T_A_S_");
   Serial.println("___________________________");
}
//tikrinama ar kolektoriaus ir boilerio temperatūrų skirtumes nėra mažesnis už nustatytą
if (Collector_tempC - Boiler_tempC <= Differential_OFF) { 
   Siurblys_isjungtas();
   Serial.println("_________________________");
   Serial.println("Siurblys- _N_E_D_I_R_B_A_");
   Serial.println("_________________________");
}

//______________________________________________
//Kolektoriaus jutiklių klaidų tikrinimo pražia
//----------------------------------------------
}else{Serial.println("************* Kolektoriaus daviklio zyme- BLOGAS! ********************************");
// Jei kolektoriaus temperatūros jutiklis neveikia, įjungiamas siurblys. 
// Kas kiek laiko nurodo kintamasis REQUEST_Collector_Error
// Jei boilerio temperatūra mažėja, siurblys išjungiamas.
if (millis() > timer_Collector_Error + REQUEST_Collector_Error) {
   timer_Collector_Error = millis();
   Saved_Boiler_tempC = Boiler_tempC; //Atsimenama boilerio temperatūra
   Siurblys_ijungtas();
   lcd.setCursor(8,0); lcd.print(" ??.??");
   Serial.println("____________________________________________________________");
   Serial.println("***** kolektoriaus apsauga nuo perkaitimo, siurblys ijungtas");
   Serial.println("____________________________________________________________");
   Serial.println(Saved_Boiler_tempC);
}else{ if (Saved_Boiler_tempC - Boiler_tempC >= 0.5 )
       {Siurblys_isjungtas(); timer_Collector_Error = millis();
       }
}
//______________________________________________
  //Boilerio jutiklių klaidų tikrinimo pražia
  //----------------------------------------------

}
}
else{ Serial.println("************* Boilerio daviklio zyme- BLOGAS! ********************************");
      Serial.println("* Siurblys bus ijungtas, kai kolektoriaus temperatura pakils iki 95 laipsniu *");
      Serial.println("* Siurblys bus isjungtas, kai kolektoriaus temperatura nukris iki 85 laipsniu *");
      Serial.println("******************************************************************************");
      if (Collector_tempC >= 95) Siurblys_ijungtas();
      if (Collector_tempC <= 85) Siurblys_isjungtas();
  // if (Collector_tempC >=95){Siurblys_ijungtas();} //Jei kolektoriaus temperatūra didesnė negu 95 laipsniai, įjungiamas siurblys 

}
} //__________________________________________________
   //
   //--------------------------------------------------

}//Pagrindinės programos pabaiga
//_______________________________________
//      P A P R O G R A M Ė S 
//siurblio ir termostato relių junginėjimui
//---------------------------------------
//siurblio įjungimas ir atitinkamo ženklo ekrane rodymas
void Siurblys_ijungtas()  {
 digitalWrite(Pump, LOW);
 digitalWrite(13, HIGH);
   lcd.setCursor(15,0);
   lcd.write((uint8_t)2);//char up to LCD
//   lcd.setCursor(15,1);
//   lcd.write((uint8_t)2);//char up to LCD
}
//siurblio įšjungimas ir atitinkamo ženklo ekrane rodymas
void Siurblys_isjungtas(){
digitalWrite(Pump, HIGH);
   lcd.setCursor(15,0);
   lcd.write((uint8_t)1);//char down to LCD
//   lcd.setCursor(15,1);
//   lcd.write((uint8_t)1); //char down to LCD
}
//termostato relės įjungimas ir atitinkamo ženklo ekrane rodymas
void Rele_2_ijungta()  {
digitalWrite(Relay2, LOW);
digitalWrite(13, HIGH);
   lcd.setCursor(9,1);
   lcd.write((uint8_t)2);//char up to LCD
}
//termostato reles įsjungimas ir atitinkamo ženklo ekrane rodymas
void Rele_2_isjungta(){
digitalWrite(Relay2, HIGH);
   lcd.setCursor(9,1);
   lcd.write((uint8_t)1); //char down to LCD
}