Support http://amicus.ba with small donation

Arduino termometar može biti korišten i za upravljanje digitalnim izlazima. Znači da posjetilac Arduino web stranice, pored očitavanja  izmjerene temperature, može uključivati i isključivati Arduino digitalne izlaze.

Na slici ispod je primjer Arduino termometra sa termistorom u AREF spoju koji izmjerenu temperaturu prikazuje na vastitom web serveru koji omogućava i upravljanje digitalnim izlazima.

Web upravljanje i termometar

Budući da su izmjerene temperature prikazane na web serveru, to je potrebno izvršiti spajanje Arduino ploče na LAN mrežu. U primjeru iznad je to izvršeno pomoću LAN shield-a (mrežni modul sa RJ45 konektorom), ali je princip rada isti i za slučaj WiFi konekcije.

Za ostvarivanje mrežne komunikacije putem ethernet shield-a, u sketch je potrebno uključiti biblioteku Ethernet.h

Ispod je kôd sketch-a koji vrši mjerenje temperature pomoću termistora u AREF spoju prikaz mjerenih vrijednosti na vlasitom web serveru (kopirajte kompletan kôd ispod u Arduino IDE prozor i upload-ujte ga na Arduino) :

/////////////////////////////////////////////////////
// Arduino web server na SD kartici sa prikazom    //
// slika i temperature koja se mjeri pomoću        //
// termistora.                                     //
// Pored toga, web server omogućava upravljanje sa //
// četiri Arduino digitalna izlaza pomoću četiri   //
// tipke na prikazanoj web stranici.               //
//                                                 //
// Arduino je, u LAN mrežu spojen pomoću ethernet  //
// shield-a.                                       //
//                                                 //
// Autor: Samir Gutić, http://amicus.ba            //
// 27. decembar 2017.                              //
/////////////////////////////////////////////////////

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

#define REQ_BUF_SZ 60 // Veličina buffer-a za HTTP zahtjeve

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC adresa za Ethernet shield
IPAddress ip(192, 168, 1, 100); // IP adresa za Ethernet shield
EthernetServer server(80); // Kreiranje servera na portu 80
File webFile; // Dokument web stranice na SD kartici
char HTTP_req[REQ_BUF_SZ] = {0}; // Buffer-ovani HTTP zahtjev smješten u null terminiran string
unsigned char req_index = 0; // index u HTTP_req buffer
boolean LED_state[4] = {0}; // Smiješta stanja LED dioda
unsigned char c;

// Deklaracije za termometar
float floatSuma;
float floatProsjek;
float floatOtpor;
float floatTemperatura;

//Vrijeme refreširanja prikaza temperature
#define intOdgoda 1000

//Pin za analogno očitavanje
#define pinAnalogTerm A1

//Vrijednost rednog otpornika u omima
#define redniOtpor 9900

//Broj očitavanja za računanje prosječne vrijednosti
#define intBrCitanja 5

//Otpor na 20.6 stepeni C
#define intTermistorNa25 12080

//Nominalna temperatura
#define intNominalnaTemp 20.6

//Beta koeficijent termistora (obično 3000-4000)
#define intBetaKoeficijent 4016.032
// Kraj deklaracija za termometar

void setup()
{
// Inicijalizacija digitalnih izlaza
pinMode(2, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);

// Onemogući Ethernet čip
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);

// Za termometar
//Spojiti AREF na 3.3V i koristiti za napajanje (manje smetnji nego na 5V)
analogReference(EXTERNAL);
// Kraj za termimetar

// Inicijalizacija SD kartice
if (!SD.begin(4))
{
  return; // Inicijalizacija NIJE uspjela
}

if (!SD.exists("index.htm")) // Traženje index.htm na SD kartici
{
  return; // Na SD kartici nije moguće pronaci index.htm
}

Ethernet.begin(mac, ip); // Inicijalizacija Ethernet uređaja
server.begin(); // Početak osluškivanja konekcija klijenata
}

void loop()
{
// Za termometar
//Očitavanje vrijednosti sa termistora
floatSuma = 0;
for (int i=0; i<intbrcitanja; i++)<br="">

{
  floatSuma = floatSuma+analogRead(pinAnalogTerm);
  delay(10);
}

//Računanje prosječne vrijednosti u zadnjih intBrCitanja očitavanje
floatProsjek = floatSuma/intBrCitanja;

//Konverzija vrijednosti u otpor
floatOtpor = redniOtpor*floatProsjek/(1023-floatProsjek);

// Steinhart-Hart metod računanja
floatTemperatura = floatOtpor / intTermistorNa25; // (R/Ro)
floatTemperatura = log(floatTemperatura); // ln(R/Ro)
floatTemperatura = floatTemperatura/intBetaKoeficijent; // 1/B * ln(R/Ro)
floatTemperatura = floatTemperatura+1.0 / (intNominalnaTemp + 273.15); // + (1/To)
floatTemperatura = 1.0 / floatTemperatura; // Invertovati vrijednost
floatTemperatura = floatTemperatura-273.15; // Konverzija u stepene C

// Kraj za termometar

EthernetClient client = server.available(); // Pokušaj konekcije sa klijentom

// Upravljanje pomoću tipki
if (client)
{ // Dobijen klijent?
  boolean currentLineIsBlank = true;
  while (client.connected())
{
if (client.available())
{
  // Podaci od klijenta su dostupni za čitanje
  c = client.read(); // Pročitaj 1 byte (znak) od klijenta

// Limitiraj veličinu sačuvanog primljenog HTTP zahtjeva
// Buffer-uj prvi dio HTTP zahtjeva u HTTP_req niz (string)
// Zadnji element postavi na 0 za null terminisranje stringa (REQ_BUF_SZ - 1)
if (req_index < (REQ_BUF_SZ - 1))
{
  HTTP_req[req_index] = c; // Sačuvaj znak HTTP zahtjeva
  req_index++;
}

// Zadnja linija zahtjeva od klijenta je prazna i završava sa \n
// Odgovori klijentu samo nakon prijema zadnje linije
if (c == '\n' && currentLineIsBlank)
{
  client.println("HTTP/1.1 200 OK"); // Pošalji standardno zaglavlje http odgovora

  // Ostatak zaglavlja slijedi ispod, odvisno od toga da li je web ili XML zahtjev
  // Za Ajax zahtjev - pošalji XML dokument
if (StrContains(HTTP_req, "ajax_inputs"))
{
  // Pošalji ostatak HTTP zaglavlja
  client.println("Content-Type: text/xml");
  client.println("Connection: keep-alive");
  client.println();
  SetLEDs();

  // Pošalji XML dokument koji sadrži stanja ulaza
  XML_response(client);
}

// Za web zahtjev - pošalji index.htm
else if (StrContains(HTTP_req, "GET / ") || StrContains(HTTP_req, "GET /index.htm"))
{
  // Pošalji ostatak HTTP zaglavlja
  client.println("Content-Type: text/html");
  client.println("Connection: keep-alive");
  client.println();

  // Pošalji web stranicu
  webFile = SD.open("index.htm"); // Otvori dokument web stranice
if (webFile)
{
  while(webFile.available())
   {
     client.write(webFile.read()); // Pošalji web stranicu klijentu
   }
  webFile.close();
}
}

// Resetuj buffer indeks i sve elemente buffer-a na 0
req_index = 0;
StrClear(HTTP_req, REQ_BUF_SZ);
break;
}

// Svaka linija teksta primljena od klijenta završava sa \r\n
if (c == '\n')
{
  // Zadnji znak u primljenoj liniji teksta
  // Startanje nove linije pročitanim znakom
  currentLineIsBlank = true;
}
else if (c != '\r')
{
  // Od klijenta je primljen znak teksta
  currentLineIsBlank = false;
}
}
}

delay(0.5); // Daj web pregledniku vrijeme da primi podatke
client.stop(); // Zatvori konekciju
}
}

// Provjera da li je primljeni HTTP zahtjev ukjučivanje/isključivanje digitalnih izlaza
// Takođe sačuvati trenutna stanja digitalnih izlaza
void SetLEDs(void)
{
// LED 1 (pin 2)
if (StrContains(HTTP_req, "LED1=1"))
{
  LED_state[0] = 1; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(2, HIGH); // Uključi digitalni izlaz
}
else if (StrContains(HTTP_req, "LED1=0"))
{
  LED_state[0] = 0; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(2, LOW); // Isključi digitalni izlaz
}
// LED 2 (pin 6)
if (StrContains(HTTP_req, "LED2=1"))
{
  LED_state[1] = 1; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(6, HIGH); // Uključi digitalni izlaz
}
else if (StrContains(HTTP_req, "LED2=0"))
{
  LED_state[1] = 0; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(6, LOW); // Isključi digitalni izlaz
}
// LED 3 (pin 7)
if (StrContains(HTTP_req, "LED3=1"))
{
  LED_state[2] = 1; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(7, HIGH); // Uključi digitalni izlaz
}
else if (StrContains(HTTP_req, "LED3=0"))
{
  LED_state[2] = 0; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(7, LOW); // Isključi digitalni izlaz
}
// LED 4 (pin 8)
if (StrContains(HTTP_req, "LED4=1"))
{
  LED_state[3] = 1; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(8, HIGH); // Uključi digitalni izlaz
}
else if (StrContains(HTTP_req, "LED4=0"))
{
  LED_state[3] = 0; // Sačuvaj stanje digitalnog izlaza
  digitalWrite(8, LOW); // Isključi digitalni izlaz
}
}

// Pošalji XML dokument sa podacima i stanjima digitalnih izlaza
void XML_response(EthernetClient cl)
{
float analog_val; // Sadrži vrijednosti varijabli za slanje
int count; // Brojač za FOR petlje
// int sw_arr[] = {3, 4, 5}; // Pinovi prekidača

cl.print("");
cl.print("");

// Slanje vlastitih varijabli na web stranicu
analog_val = floatTemperatura;
cl.print("");
cl.print(analog_val);
cl.println("");

// Setovanje stanja digitalnih izlaza
// LED1
cl.print("");
if (LED_state[0])
{
  cl.print("on");
}
else
{
  cl.print("off");
}
cl.println("");

// LED2
cl.print("");
if (LED_state[1])
{
  cl.print("on");
}
else
{
  cl.print("off");
}
cl.println("");

// LED3
cl.print("");
if (LED_state[2])
{
  cl.print("on");
}
else
{
  cl.print("off");
}
cl.println("");

// LED4
cl.print("");
if (LED_state[3])
{
  cl.print("on");
}
else
{
  cl.print("off");
}
cl.println("");
cl.print("");
}

// Postavljanje svih elemenata niza na 0 (nuliranje niza)
void StrClear(char *str, char length)
{
for (int i = 0; i < length; i++)

{
  str[i] = 0;
}
}

// Traženje stringa sfind u stringu str
// Vraća 1 ako je string pronađen a 0 ako nije pronađen
char StrContains(char *str, char *sfind)
{
char found = 0;
char index = 0;
char len;

len = strlen(str);

if (strlen(sfind) > len)
{
  return 0;
}
while (index < len)
{
  if (str[index] == sfind[found])
   {
     found++;
     if (strlen(sfind) == found)
     {
       return 1;
     }
   }
   else
   {
     found = 0;
   }
  index++;
}
return 0;
}

Više datalja o termistoru možete pronaći u članku Arduino termistor termometar (AREF) sa upisom na SD karticu.

Budući da sam već objašnjavao princip rada termometra sa termistorom u AREF spoju, kao i korištenju ethernet shield-a, ovdje neću govoriti o tome. Novost je korištenje opcija upravljanja digitalnim izlazima putem web stranice na Arduino web serveru.

U ovom primjeru je web server na standardnom portu 80, mada je moguće podesiti i port po želji.

Za prikaz web stranice kao na slici ispod, na root SD kartice je potrebno iskopirati sljedeći idex.htm file:

Termometar i upravljanje - web stranica
Na slici lijevo je screenshot posjete arduino web serveru sa mobitela (browser Firefox).

U web browser je potrebno upisati IP Arduino servera definisanog na početku sketch-a (u ovom primjeru 192.168.1.100) nakon čega će, ako je Arduino uspješno povezan na istu LAN mrežu na kojoj je mobitel, biti prikazan sadržaj kao na slici lijevo.

Napominjem još jednom da Arduino i mobitel/računar kojim pristupamo web serveru moraju biti u istoj LAN mreži. Ako nisu, jedini način da se pristupi Arduino web serveru je putem rutiranja između dvije mreže. U primjeru iznad je Arduino ethernet shield, UTP kablom, spojen na RJ45 port WiFi router-a dok su mobitel i računar, na isti router, konektovani preko WiFi konekcije.

Drugi način je da se Arduino web serveru omogući pristup sa interneta tako da se na router-u, koji je gateway za internet, kreira redirekt porta 80 na IP adresu koju ima Arduino ethernet shield čime će svako ko poznaje WAN IP vašeg router-a, putem interneta moći pristupiti Arduino web serveru i očitati izmjerenu temperaturu.

Pored prikaza izmjerene temperature, na slici lijevo se vide i četiri tipke za upravljanje sa četiri Arduino digitalna izlaza. Na digitalne izlaze 2, 6, 7 i 8 sam spojio LE diode (preko otpornika od 200Ω) da je moguće vidjeti kada je digitalni izlaz uključen ili isključen.

U suštini, moguće je spojiti releje ili tranzistore koji će igratu ulogu prekidača.

Pritiskom na tipku na prikazanoj web stranici, šalje se komanda Arduinu. Na osnovu primljene komande Arduino uključuje/isključuje digitalne izlaze te na web stranici prikazuje uključenu ili isključenu sijalicu (odvisno od stanja digitalnog izlaza) i na pritisnutoj tipki prikazuje tekst da je odgovarajući digitalni izlaz uključen ili isključen.

To znači, da pored mogućnosti slanja komande, postoji i mogućnost provjere stvarnog stanja digitalnog izlaza.

Ovim se već otvara široko polje upotrebe Arduino mikrokontrolera za dvosmjernu komunikaciju i izgradnju smart uređaja u kući.

Na slici iznad su prikazane i sličice uključene i isključene sijalice a na SD kartici je samo index.htm file. Uključena sijalicaIsključena sijalicaSlike su base64 enkodirane i 'ugrađene' u sam index.htm tako da ih nije potrebno posebno kopirati niti svaki puta čitati sa SD kartice. Zbog toga je prikaz web stranice dosta brži (Arduino ima ograničenu procesorsku moć).

Princip rada

Arduino kreira web server na portu 80 pomoću instrukcije server.begin(); 

Sa SD kartice pročita index.htm file i tu stranicu prikaže na zahtjev klijenta (PC ili mobilni browser). Prikazana web stranica, na vrhu ispisuje temperaturu koju je izmjerio Arduino kao i 4 dugmeta i 4 sličice sijalica koje su uključene ili isključene odvisno od trenutnog stanja digitalnih izlaza 2, 6, 7 i 8.

Ako želite promijeniti stanje neko od četiri pomenuta digitalna izlaza, potrebno je kliknuti na odgovarajuće dugme nakon čega će Arduino primiti komandu kao: LED1=1

Ova komanda će izvršiti uključivanje digitalnog izlaza na koji je spojena LED1 (digitalni izlaz 2). U slučaju da je poslata komanda LED1=0 Arduino bi isključio digitalni izlaz 2. Nakon toga, na prikazanoj web stranici će biti promijenjet tekst na pritisnutom dugmetu i izvršena zamjena sličice sijalice što će označiti trenutno stanje digitalnog izlaza.

Base64 enkodiranje slika

Za enkodiranje ove dvije sličice sam koristio stranicu base64-image.de U suštini, moguće je koristiti bilo koju stranicu ili program koji vrši base64 enkodiranje slika. Na slici ispod je početna stranica sa već učitanom slikom ukljuc.pngbase64 web stranicaSlika ispod prikazuje screenshot rezultata enkodiranja. Moguće je izabrati jedan od dva rezultata: za korištenje u <img> tagu ili kao CSS pozadina.

base64 web stranica - završeno enkodiranje

U ovom primjeru sam koristio kod za <img> tagove i on izgleda kao jaaaako veliki niz slova i brojeva. Djelić tog niza izgleda kao:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE0AAABNCAYAAADjCemwAAAAVXpUWHRSYXcgcHJvZmlsZSB09

Kako izgleda kompletna slika, i kako se koristi možete pogledati ako, u nekom tekstualnom editoru, otvorite index.htm koji je dostupan za download sa linka iznad.

Šeme spoja

Šema spoja elemenata kreirana u Fritzing programu je na slici ispod (Arduino ploča je ispod ethernet shield-a).

Termometar sa web serverom i upravljanje sa  4 izlaza

Električna šema spoja je na sljedećoj slici.

Termometar sa web serverom i upravljanje sa  4 izlaza - električna šema

Potrebne komponente:

1 x Arduino UNO

1 x Breadboard (mala)

1x NTC termistor 12.08KΩ na 25ºC

1x otpornik 9900Ω

1 x Ethernet shield sa microSD modulom

1x microSD kartica (max 2GB)

4x LED

4x otpornik 200Ω

Žice za spajanje

9V napajanje