Podesivi termostat s relejom

Što ću dobiti s ovim tutorialom?

 
Prevenstveno cilj tutoriala je na konkretnom primjeru kombinirati više modula s Croduinom. Kombinirati znači praviti mogusobne uvjete i korelacije pojedinih očitanja i prikazivati ih, odnosno upravljati njima. Moduli koje ćemo koristiti nalaze se u tablici desno, a večinu ih možete pronaći u CSP Hobby setu.
 
Konačno dobiti ćemo uređaj koji će s obzirom na temperaturu paliti, odnosno gasiti relej (grijač). Temperatura prilikom koje će se to događati biti će podesiva s tipkovnicom, a sve navedeno očitavati ćemo na LCD displayu.
 
Popis komponenata i pojediničanih tutoriala:
Croduino Basic2 - instalacija drivera
DHT11 - KKM
Matrix membranska tipkovnica - KKM
LCD 16x2 - KKM
Relej - pregled proizvoda

Povezivanje modula

 
Svi moduli već su pojedninačno obrađeni u KKM - Kako koristiti module tutorialima. Stoga nećeo ponovno isto raditi. U predhodno poglavlju nalaze se linkovi za pojedinačne tutoriale. Sada povežite modula kako pokazuje slika dolje, pa krećemo odmah s programiranjem.
 
Podesivi termometar fritzing

Svi moduli u jedan sketch

 
Plan je kopirati dio koda iz KKM tutoriala koji nam je potreban za svaki modul posebno. Nakon čega ćemo napisati potrebne uvijete i funkcije za određene varijable. Pa krenimo...
 
DHT11
 
NAPOMENA: budite sigurni da ste predhodno instalirali potreben librarye, kako je zapisano u KKM tutorialima

#include "dht.h" // dodajemo dht library

// potrebno definirati za ocitanja s DHTa
dht DHT; 
#define dht_dpin A0 //data pin DHT11 na A0 pinu Croduina
int ocitanaTemp = 0;
 
void setup(){
   
}
 
void loop(){

  // čitamo stanje DHT11
  // ova naredba sprema ocitanje temperature u "DHT.temperature"
  DHT.read11(dht_dpin);
  // ocitanje temperature spremamo u varijablu ocitanaTemp
  ocitanaTemp = DHT.temperature;
 
  delay(800); // minimalni razmak ocitanja s DHT11 je 800ms
}

 
Matrix Membranska Tipkovnica
 
NAPOMENA: dalje ćemo u postojeći kod samo dodavati nove dijelove, kako je označeno komentarima

// PREDDEFINIRAMO

#include "Keypad.h"  // dodajemo library Keypad

// potrebno definirati za Matrix tipkovnicu
  const byte red = 4;    // Tipkovnica ima 4 reda
  const byte stupac = 4; // i 4 stupca
 
  char tipke[red][stupac]  = {  // definiraj polozaj tipki na tipkovnici
    {'1','2','3','A'},
    {'4','5','6','B'},
    {'7','8','9','C'},
    {'*','0','#','D'}
  };
 
  byte red_pinovi[red] = {7,6,5,4};   // pinove redova spajamo redom na PIN9, PIN8, PIN7, PIN6    
  byte stupac_pinovi[stupac] = {3,2,1,0};  // pinove stupaca spajamo redom na PIN5, PIN4, PIN3, PIN2
   
  Keypad tipkovnica = Keypad(makeKeymap(tipke), red_pinovi, stupac_pinovi, red, stupac);
  // pritisnutu tipku oslusavati cemo pomocu: "tipkovnica.getKey()"

// VOID SETUP()
   // ovdje ništa

 
// VOID LOOP()

  // ovdje ništa
  // pritisnutu tipku oslusavati cemo pomocu: "tipkovnica.getKey()"

 
LCD 16x2
 

// PREDEFINIRAMO

#include "LiquidCrystal_I2C.h" // dodajemo potrebni library za LCD
#include "Wire.h" // pošto koristimo I2C za LCD

// potrebno definirati za LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// VOID SETUP()

lcd.begin(16,2);  // podesi LCD 16x2
   lcd.backlight();  // ukljuci pozadinsko osvjetljenje LCDa
   
   // ispisi pozdravnu poruku
   lcd.setCursor(0,0); // postavi kursor pisanja na prvi stupac i prvi red
   lcd.print("Termostat"); // pripazite da String ne bude duži od 16 znakova
   lcd.setCursor(0,1) // postavi kursor na prvi stupac, drugi red
   lcd.print("e-radionica.com");

// VOID LOOP()

  // za sada ništa

 
Relej
 

// PREDEFINIRAMO

int relej = 8; // relej spajamo na D8

// VOID SETUP()

pinMode(relej, OUTPUT); // definiramo relej kao izlaznu komponentu

// VOID SETUP

// ovdje ništa

 
Sketch sada izgleda ovako:
 

#include "dht.h" // dodajemo dht library
#include "Keypad.h"  // dodajemo library Keypad
#include "LiquidCrystal_I2C.h" // dodajemo potrebni library za LCD
#include "Wire.h" // pošto koristimo I2C za LCD

// potrebno definirati za ocitanja s DHTa
  dht DHT; 
  #define dht_dpin A0 //data pin DHT11 na A0 pinu Croduina
  int ocitanaTemp = 0;

// potrebno definirati za Matrix tipkovnicu
  const byte red = 4;    // Tipkovnica ima 4 reda
  const byte stupac = 4; // i 4 stupca
 
  char tipke[red][stupac]  = {  // definiraj polozaj tipki na tipkovnici
    {'1','2','3','A'},
    {'4','5','6','B'},
    {'7','8','9','C'},
    {'*','0','#','D'}
  };
 
  byte red_pinovi[red] = {7,6,5,4};   // pinove redova spajamo redom na PIN9, PIN8, PIN7, PIN6    
  byte stupac_pinovi[stupac] = {3,2,1,0};  // pinove stupaca spajamo redom na PIN5, PIN4, PIN3, PIN2
   
  Keypad tipkovnica = Keypad(makeKeymap(tipke), red_pinovi, stupac_pinovi, red, stupac);
  // pritisnutu tipku oslusavati cemo pomocu: "tipkovnica.getKey()"

// potrebno definirati za LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// potrebno definirati za relej
int relej = 8; // relej spajamo na D8

void setup(){
   pinMode(relej, OUTPUT); // definiramo relej kao izlaznu komponentu
  
   lcd.begin(16,2);  // podesi LCD 16x2
   lcd.backlight();  // ukljuci pozadinsko osvjetljenje LCDa
   
   // ispisi pozdravnu poruku
   lcd.setCursor(0,0); // postavi kursor pisanja na prvi stupac i prvi red
   lcd.print("Termostat"); // pripazite da String ne bude duži od 16 znakova
   lcd.setCursor(0,1); // postavi kursor na prvi stupac, drugi red
   lcd.print("e-radionica.com");
   delay(1000); // neka nam se ova poruka prikazuje 1 sekundu
   lcd.clear(); // nakon čega ćemo ju obrisati
}
 
void loop(){

  // čitamo stanje DHT11
  // ova naredba sprema ocitanje temperature u "DHT.temperature"
  DHT.read11(dht_dpin);
  // ocitanje temperature spremamo u varijablu ocitanaTemp
  ocitanaTemp = DHT.temperature;
 
  delay(800); // minimalni razmak ocitanja s DHT11 je 800ms
}

Pisanje uvjeta

 
Za početak ispišimo temperaturu očitanu s DHT11 senzora. Napraviti ćemo posebnu funkciju koja će to izvršiti. Funkciju "Ispis()" možemo zapisaati prije ili poslije "setup()" i "void()" funkcija.

// funkcija koja ispisuje ocitanja
void Ispis() {
  // ispis temp ocitane s DHT11 senzora
  lcd.clear(); // obrisi sve predhodno zapisano na LCDu
  lcd.setCursor(0,0); // postavi kursor na prvi stupac, prvi red
  lcd.print("Ocitano:" + String(ocitanaTemp));
}

 
Vrijeme je da postavimo izbornik u kojemo ćemo postavljati temperaturu prilikom koje će se paliti relej. Postaviti ćemo izbornik tako da tipka '#' s membranske tipkovnica otvara izbornik. Dakle, kada pritisnemo tipku '#' otvoriti će se izbornik koji će spremiti unos "podešene temperature". Objašnjenje u kodu dolje.

// PREDEFINIRAMO

// za vise o tipovima varijabli pogledajte : https://e-radionica.com/hr/blog/2015/10/18/arduino-ide-varijable/
int podesenaTemp = 0; // varijabla u koju ćemo spremiti podesenu temperaturu
String unosString = "";  // string varijabla u kojoj ćemo "graditi" unos tipkovnice
boolean boolUnosTemp = false; // uvjet ulaska i izlaska iz izbornika

 
Napisimo sada dio koda koji ce slusati kada je tipka koja poziva izbornik - '#' pritisnuta. Želimo da sketch stalno bude u mogućnosti ući u izbornik stoga ga pišemo pod void loop()

// VOID LOOP()

char pritisnuto = tipkovnica.getKey(); // pritisnuta tipka sprema se u varijablu pritisnuto
                                       // zbog delay(800) koji je nužan za čitanje s DHT11
                                       // moguće je da će tipku trebati držati i do 800ms pritisnuto
                                       // kako bi je registrirao ovaj dio sketcha

// ulazak u izbornik za podešavanje temperature
if( pritisnuto == '#' && boolUnosTemp == false) {  // ako je pritisnuta tipka '#' i već nismo u izborniku
    boolUnosTemp = true; // usli smo u Menu
    
    // ispisi tekst Menu-a
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("postavi temp:");
    unosString = "";

    // napravimo loop koji ce slusati unos temperature, sve dok ponovno ne pritisnemo tipku '#'
    // nakon čega ćemo izači iz Menu-a
    while( boolUnosTemp == false)
    {
      // spremi pritisnutu tipku u "unos"
      char unos = tipkovnica.getKey();
      // pošto zelimo samo brojeve u temperaturi, sve ostale znakove moramo zanemaariti:
      // ako je zadovoljen jedan od navedenih uvjeta unos je "prazan" char
      if( unos == 'A' || unos == 'B' || unos == 'C' || unos == 'D' || unos == '*' ) unos = '\0';
      // ako je pak pritisnuta tipka '#' izači iz ovog izbornika, te ispisati i usporediti unešenu temperaturu
      else if( unos == '#' ) {
        boolUnosTemp = false; // ovo će izaći iz zadanog while-a
        unos = '\0'; // ne želimo da ništa bude dodano u naš unosString
      }
      

      // spremimo svaku pojedinačnu tipku u jedan string, kojeg cemo kasnije uspoređivati s trenutnom temperaaturom
      // te s obzirom na to paliti, odnosno gasiti relej
      unosString += String(unos);
      //ispisujemo što zapisujemo
      lcd.setCursor(0,1);
      lcd.print(unosString);
      }
}

 
unosString je podešena temperatura našeg sustava. Pa dodajmo tu temperaturu na ispis LCD-a u funkciju ispis, koja sada izgleda ovako:

// funkcija koja ispisuje ocitanja
void Ispis() {
  // ispis temp ocitane s DHT11 senzora
  lcd.clear(); // obrisi sve predhodno zapisano na LCDu
  lcd.setCursor(0,0); // postavi kursor na prvi stupac, prvi red
  lcd.print("Ocitano:" + String(ocitanaTemp));

  // ispis temp zadane u izborniku
  lcd.setCursor(0,1); // postavljamo kursor na prvi stupac, drugi red
  lcd.print("Podeseno:" + unosString);
}

 
Kako bi se relej stalno pali gasio s obzirom na očitanu i podešenu temperaturu, u loop, potrebno je zadati uvjet:

// uvjet prema kojem se relej pali, odnosno gasi
// u slučaju da je podešena temperatura manja od očitane upali relej
if( unosString.toInt() > ocitanaTemp ) digitalWrite(relej, HIGH);
// ugasi relej u svim ostalim slučajevima
else digitalWrite(relej, LOW);

 
Ukoliko ne želimo da nam se izgubi temperatura koju smo postavili kada resetiramo Croduino ili kada izgubimo napajanje na pločici, potrebno ju je spremiti u EEPROM memoriju kontrolera. Više pročitajte u EEPROM tutorialu.

// PREDEFINIRAMO
#include "EEPROM.h"

// očitavamo vrijednom spremljenu na adresi 10 EEPROM memorije
// u tu adresu spremiti ćemo svaku promjenu koju napravimo na ovoj varijabli
String unosString = String(EEPROM.read(10));

// VOID LOOP()
// na mjestu na kojem smo napravili promjene u varijabli, potrebno ju je i spremiti u EEPROM memoriju

      //spremamo promjene u EEPROM memoriju na adresu 10
      EEPROM.write(10,unosString.toInt());

 
Dodatno možemo definirati tipka A, B, C i D kao predefinirane vrijednosti podešene temperature:

// VOID LOOP()
// ako je pritisnuta tipka 'A', podesi temperaturu na 15 stupnjeva
else if( pritisnuto == 'A' ) unosString = "15";
// ako je pritisnuta tipka 'B', podesi temperaturu na 20 stupnjeva
else if( pritisnuto == 'B' ) unosString = "20";
// ako je pritisnuta tipka 'C', podesi temperaturu na 25 stupnjeva
else if( pritisnuto == 'C' ) unosString = "25";
// ako je pritisnuta tipka 'D', podesi temperaturu na 30 stupnjeva
else if( pritisnuto == 'D' ) unosString = "30";

Cijeli, konačni kod

 
Cijeli, konačni kod je pomalo nabacan te ga možete kopirati ovdje. U njemu se nalazi hrpa komentara pa možete preskočiti odlomak iznad. Ako se pojavi problem u razumjevanju, uvijek možete škicnuti tamo za dodatna pojašnjenja.
 
Cilj ovog tutorijala je, na primjeru, prikazati logiku nakon čega vas ohrabrujemo da kod napišete sami. Isti izbornik može se napisati na mnogo načina i dobra je vježba. Ukoliko zapnete, javite se s konkretnim pitanjima (molimo da iskomentirate kod). Ne zaboraviti instalirati potrebne library-e.

#include "dht.h" // dodajemo dht library
#include "Keypad.h"  // dodajemo library Keypad
#include "LiquidCrystal_I2C.h" // dodajemo potrebni library za LCD
#include "Wire.h" // pošto koristimo I2C za LCD
#include "EEPROM.h"

// potrebno definirati za ocitanja s DHTa
  dht DHT; 
  #define dht_dpin A0 //data pin DHT11 na A0 pinu Croduina
  int ocitanaTemp = 0;

// potrebno definirati za Matrix tipkovnicu
  const byte red = 4;    // Tipkovnica ima 4 reda
  const byte stupac = 4; // i 4 stupca
 
  char tipke[red][stupac]  = {  // definiraj polozaj tipki na tipkovnici
    {'1','2','3','A'},
    {'4','5','6','B'},
    {'7','8','9','C'},
    {'*','0','#','D'}
  };
 
  byte red_pinovi[red] = {7,6,5,4};   // pinove redova spajamo redom na PIN9, PIN8, PIN7, PIN6    
  byte stupac_pinovi[stupac] = {3,2,1,0};  // pinove stupaca spajamo redom na PIN5, PIN4, PIN3, PIN2
   
  Keypad tipkovnica = Keypad(makeKeymap(tipke), red_pinovi, stupac_pinovi, red, stupac);
  // pritisnutu tipku oslusavati cemo pomocu: "tipkovnica.getKey()"

// potrebno definirati za LCD
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// potrebno definirati za relej
int relej = 8; // relej spajamo na D8

// dodatne postavke izbornika
int podesenaTemp = 0; // varijabla u koju ćemo spremiti podesenu temperaturu
// očitavamo vrijednom spremljenu na adresi 10 EEPROM memorije
// u tu adresu spremiti ćemo svaku promjenu koju napravimo na ovoj varijabli
String unosString = String(EEPROM.read(10));  // string varijabla u kojoj ćemo "graditi" unos tipkovnice
boolean boolUnosTemp = false; // uvjet ulaska i izlaska iz izbornika

void setup(){
   pinMode(relej, OUTPUT); // definiramo relej kao izlaznu komponentu
  
   lcd.begin(16,2);  // podesi LCD 16x2
   lcd.backlight();  // ukljuci pozadinsko osvjetljenje LCDa
   
   // ispisi pozdravnu poruku
   lcd.setCursor(0,0); // postavi kursor pisanja na prvi stupac i prvi red
   lcd.print("Termostat"); // pripazite da String ne bude duži od 16 znakova
   lcd.setCursor(0,1); // postavi kursor na prvi stupac, drugi red
   lcd.print("e-radionica.com");
}
 
void loop(){

  // čitamo stanje DHT11
  // ova naredba sprema ocitanje temperature u "DHT.temperature"
  DHT.read11(dht_dpin);
  // ocitanje temperature spremamo u varijablu ocitanaTemp
  ocitanaTemp = DHT.temperature;

  char pritisnuto = tipkovnica.getKey(); // pritisnuta tipka sprema se u varijablu pritisnuto
                                       // zbog delay(800) koji je nužan za čitanje s DHT11
                                       // moguće je da će tipku trebati držati i do 800ms pritisnuto
                                       // kako bi je registrirao ovaj dio sketcha

// ulazak u izbornik za podešavanje temperature
if( pritisnuto == '#' && boolUnosTemp == false) {  // ako je pritisnuta tipka '#' i već nismo u izborniku
    boolUnosTemp = true; // usli smo u Menu
    
    // ispisi tekst Menu-a
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("postavi temp:");
    unosString = "";

    // napravimo loop koji ce slusati unos temperature, sve dok ponovno ne pritisnemo tipku '#'
    // nakon čega ćemo izači iz Menu-a
    while( boolUnosTemp == false)
    {
      // spremi pritisnutu tipku u "unos"
      char unos = tipkovnica.getKey();
      // pošto zelimo samo brojeve u temperaturi, sve ostale znakove moramo zanemaariti:
      // ako je zadovoljen jedan od navedenih uvjeta unos je "prazan" char
      if( unos == 'A' || unos == 'B' || unos == 'C' || unos == 'D' || unos == '*' ) unos = '\0';
      // ako je pak pritisnuta tipka '#' izači iz ovog izbornika, te ispisati i usporediti unešenu temperaturu
      else if( unos == '#' ) {
        boolUnosTemp = false; // ovo će izaći iz zadanog while-a
        unos = '\0'; // ne želimo da ništa bude dodano u naš unosString
      }

      // spremimo svaku pojedinačnu tipku u jedan string, kojeg cemo kasnije uspoređivati s trenutnom temperaaturom
      // te s obzirom na to paliti, odnosno gasiti relej
      unosString += String(unos);
      //ispisujemo što zapisujemo
      lcd.setCursor(0,1);
      lcd.print(unosString);
      //spremamo promjene u EEPROM memoriju na adresu 10
      EEPROM.write(10,unosString.toInt());
      }
}

  // ostali uvjeti, za tipke A,B,C i D
  
  // ako je pritisnuta tipka 'A', podesi temperaturu na 15 stupnjeva
  else if( pritisnuto == 'A' ) unosString = "15";
  // ako je pritisnuta tipka 'B', podesi temperaturu na 20 stupnjeva
  else if( pritisnuto == 'B' ) unosString = "20";
  // ako je pritisnuta tipka 'C', podesi temperaturu na 25 stupnjeva
  else if( pritisnuto == 'C' ) unosString = "25";
  // ako je pritisnuta tipka 'D', podesi temperaturu na 30 stupnjeva
  else if( pritisnuto == 'D' ) unosString = "30";


// uvjet prema kojem se relej pali, odnosno gasi
// u slučaju da je podešena temperatura manja od očitane upali relej
  if( unosString.toInt() > ocitanaTemp ) digitalWrite(relej, HIGH);
// ugasi relej u svim ostalim slučajevima
  else digitalWrite(relej, LOW);
  delay(800); // minimalni razmak ocitanja s DHT11 je 800ms
}

// funkcija koja ispisuje ocitanja
void Ispis() {
  // ispis temp ocitane s DHT11 senzora
  lcd.clear(); // obrisi sve predhodno zapisano na LCDu
  lcd.setCursor(0,0); // postavi kursor na prvi stupac, prvi red
  lcd.print("Ocitano:" + String(ocitanaTemp));

  // ispis temp zadane u izborniku
  lcd.setCursor(0,1); // postavljamo kursor na prvi stupac, drugi red
  lcd.print("Podeseno:" + unosString);
}
Leave a Reply