[094] Budujemy termostat - cz. 2

[094] Budujemy termostat - cz. 2

Skoro termometr już pracuje, czas powołać do życia jakiś element, którym będziemy mogli zmieniać temperaturę. Na płytce siedzi potencjometr. Wydaje się on wygodnym elementem do zbudowania termostatu. Wszak takie pokrętła znajdziemy w grzejnikach. Opanujmy go zatem.


#include <Wire.h>                                                      // Biblioteka obsługująca magistralę I2C
#include <hd44780.h>                                                   // Biblioteka obsługująca wyświetlacze 44780
#include <hd44780ioClass/hd44780_I2Cexp.h>                             // Dodatek obsługujący wyświetlacze podłączone do ekspandera I2C
hd44780_I2Cexp lcd(0x20, I2Cexp_MCP23008, 7, 6, 5, 4, 3, 2, 1, HIGH);  // Konfiguracja połączeń wyświetlacza LCD

const byte termometr = A2;    // Adres czujnika temperatury.
float temperaturaZmierzona;   // Temperatura w jednostkach rzeczywistych - stopniach Celsiusza.
const byte termostat = A1;    // Adres potencjometru nastawiającego temperaturę oczekiwaną.
float temperaturaNastawiona;  // Temperatura w jednostkach rzeczywistych - stopniach Celsiusza.

void setup() {
  lcd.begin(16, 2);  // Inicjuj wyświetlacz: 16 kolumn, 2 wiersze
}

void loop() {
  temperaturaZmierzona = (analogRead(termometr) * 0.125 - 22.0);  // Zmierz temperaturę i przenieś ją do zmiennej temperaturaZmierzona.
  lcd.setCursor(1, 0);                                            // Ustaw kursor na początku wyświetlacza.
  lcd.print("Temp: ");                                            // Wyświetl napis "Temp: ".
  lcd.print(temperaturaZmierzona, 1);                             // Wyświetl temperaturę z dokładnością do jednego miejsca po przecinku.
  lcd.print(" ");                                                 // Wyświetl spację.
  lcd.write(223);                                                 // Wyświetl znak stopnia.
  lcd.print("C  ");                                               // Wyświetl literę C i dwie spacje.

  temperaturaNastawiona = map(analogRead(termostat), 0, 1023, 10, 30);  // Zmierz wartość napięcia ślizgacza potencjometru i przenieś ją do zmiennej temperaturaNastawiona.
  lcd.setCursor(1, 1);                                                  // Ustaw kursor na początku wyświetlacza.
  lcd.print("Term: ");                                                  // Wyświetl napis "Term: ".
  lcd.print(temperaturaNastawiona, 1);                                  // Wyświetl temperaturę z dokładnością do jednego miejsca po przecinku.
  lcd.print(" ");                                                       // Wyświetl spację.
  lcd.write(223);                                                       // Wyświetl znak stopnia.
  lcd.print("C  ");                                                     // Wyświetl literę C i dwie spacje.

  delay(250);  // Pętla opóźniająca.
}

Siedzi on pod adresem A1, więc zadeklarujemy użycie tego portu oraz zmienną temperaturaNastawiona do przechowywania wartości temperatury w pewnym przedziale, którą będziemy potem porównywać z temperaturą mierzoną.

Pierwszy blok w poprzednim szkicu obsługiwał termometr i pierwszy wiersz wyświetlacza. Stworzymy teraz bliźniaczy blok, który będzie wyświetlał temperaturę ustawioną przez potencjometr, czyli taką, jaką będziemy chcieli uzyskać. Jak widać bloki różnią się tylko wyświetlanym napisem i pierwszą linią – tą z obliczeniami. Teraz zamiast mierzyć napięcie z termometru będziemy mierzyć napięcie pojawiające się na ślizgaczu potencjometru. Użyjemy funkcji map, bo w ten sposób najprościej można zmienić przedział regulowany potencjometrem. Przedostatnia pozycja to minimum: 10 stopni, ostatnia – maksimum: 30 stopni. Każdy może sobie ten przedział dobrać do własnych upodobań. Po kompilacji możemy pokręcić gałką, obserwując zmieniające się wartości w dolnej części wyświetlacza. Jeśli wszystko będzie pracować jak powinno, czas na etap kolejny: powiązanie obu elementów.

Ale czas także najwyższy powołać do życia element wykonawczy, czyli przekaźnik. Będzie on domyślnie włączał grzejnik. Na temat przekaźników pisałem już to i owo w kilku artykułach, więc nie będę rozwijał tego tematu. Przypomnę tylko, by był wystarczająco mocny, żeby sobie poradzić z grzejnikiem i żeby pamiętać o diodzie gaszącej przepięcia, wprowadzonej równolegle do cewki – o czym początkujący elektronicy zapominają. Przekaźniki sterujemy za pomocą wzmacniacza z tranzystora.

Mając w zapasach shield z czterema przekaźnikami, skorzystam z niego na potrzeby projektu, bo tam siedzą także tranzystory, diody zabezpieczające, a nawet diody świecące, wskazujące stan włączenia przekaźnika. Wykorzystam tu tylko jeden, podłączony do portu czwartego.

#include <Wire.h>                                                      // Biblioteka obsługująca magistralę I2C
#include <hd44780.h>                                                   // Biblioteka obsługująca wyświetlacze 44780
#include <hd44780ioClass/hd44780_I2Cexp.h>                             // Dodatek obsługujący wyświetlacze podłączone do ekspandera I2C
hd44780_I2Cexp lcd(0x20, I2Cexp_MCP23008, 7, 6, 5, 4, 3, 2, 1, HIGH);  // Konfiguracja połączeń wyświetlacza LCD

const byte termometr = A2;    // Adres czujnika temperatury.
float temperaturaZmierzona;   // Temperatura w jednostkach rzeczywistych - stopniach Celsiusza.
const byte termostat = A1;    // Adres potencjometru nastawiającego temperaturę oczekiwaną.
float temperaturaNastawiona;  // Temperatura w jednostkach rzeczywistych - stopniach Celsiusza.
const byte przekaznik = 4;    // Adres przekaźnika.

void setup() {
  lcd.begin(16, 2);             // Inicjuj wyświetlacz: 16 kolumn, 2 wiersze
  pinMode(przekaznik, OUTPUT);  // Deklaruj pin przekaźnika jako wyjście.
}

void loop() {
  temperaturaZmierzona = (analogRead(termometr) * 0.125 - 22.0);  // Zmierz temperaturę i przenieś ją do zmiennej temperaturaZmierzona.
  lcd.setCursor(0, 0);                                            // Ustaw kursor na początku wyświetlacza.
  lcd.print("Temp: ");                                            // Wyświetl napis "Temp: ".
  lcd.print(temperaturaZmierzona, 1);                             // Wyświetl temperaturę z dokładnością do jednego miejsca po przecinku.
  lcd.print(" ");                                                 // Wyświetl spację.
  lcd.write(223);                                                 // Wyświetl znak stopnia.
  lcd.print("C  ");                                               // Wyświetl literę C i dwie spacje.

  temperaturaNastawiona = map(analogRead(termostat), 0, 1023, 10, 30);  // Zmierz wartość napięcia ślizgacza potencjometru i przenieś ją do zmiennej temperaturaNastawiona.
  lcd.setCursor(0, 1);                                                  // Ustaw kursor na początku wyświetlacza.
  lcd.print("Term: ");                                                  // Wyświetl napis "Term: ".
  lcd.print(temperaturaNastawiona, 1);                                  // Wyświetl temperaturę z dokładnością do jednego miejsca po przecinku.
  lcd.print(" ");                                                       // Wyświetl spację.
  lcd.write(223);                                                       // Wyświetl znak stopnia.
  lcd.print("C  ");                                                     // Wyświetl literę C i dwie spacje.

  if (temperaturaZmierzona < (temperaturaNastawiona - 0.5)) {  // Jeśli temperatura zmierzona jest mniejsza o pół stopnia od nastawionej, to...
    digitalWrite(przekaznik, HIGH);                            // Włącz przekaźnik.
  }
  if (temperaturaZmierzona > (temperaturaNastawiona + 0.5)) {  // Jeśli temperatura zmierzona jest większa o pół stopnia od nastawionej, to...
    digitalWrite(przekaznik, LOW);                             // Wyłącz przekaźnik.
  }
  delay(250);  // Pętla opóźniająca.
}

Trzeba zatem zadeklarować dobro i napisać blok, który będzie nam przekaźnikiem sterował. Przy czym jest bardzo ważne, by stworzyć tak zwaną histerezę. O co w tym chodzi? Jeśli tak po prostu włączalibyśmy sobie przekaźnik, gdy temperatura będzie niższa od oczekiwanej i wyłączali, gdy będzie wyższa, mogłoby dojść do oscylacji, gdy temperatury będą prawie równe. W przypadku tak dużych obciążeń, jak grzejniki, jest to niekorzystne, prowadzi do szybkiego zużycia przekaźnika i generacji zakłóceń.

Histereza to zjawisko, w którym do zmiany stanu – tutaj – przekaźnika, potrzeba progów oddalonych nieco od siebie. Dlatego pierwszy blok, który będzie włączał przekaźnik, zrobi to dopiero, gdy temperatura zmierzona będzie niższa o pół stopnia od nastawionej. Drugi zaś wyłączy go, gdy temperatura będzie o pół stopnia wyższa.

if (temperaturaZmierzona < (temperaturaNastawiona - 0.5)) {  // Jeśli temperatura zmierzona jest mniejsza o pół stopnia od nastawionej, to...
  digitalWrite(przekaznik, HIGH);                            // Włącz przekaźnik.
}
if (temperaturaZmierzona > (temperaturaNastawiona + 0.5)) {  // Jeśli temperatura zmierzona jest większa o pół stopnia od nastawionej, to...
  digitalWrite(przekaznik, LOW);                             // Wyłącz przekaźnik.
}

Co prawda temperatura będzie regulowana z dokładnością do stopnia, ale żadnych oscylacji i stanów niestabilnych nie napotkamy.

Dobrze byłoby wiedzieć czy przekaźnik jest w danej chwili włączony. Tutaj mam diodę, ale może jej nie być, a na wyświetlaczu marnuje się miejsce.

if (temperaturaZmierzona < (temperaturaNastawiona - 0.5)) {  // Jeśli temperatura zmierzona jest mniejsza o pół stopnia od nastawionej, to...
  digitalWrite(przekaznik, HIGH);                            // Włącz przekaźnik.
  lcd.setCursor(15, 0);                                      // Ustaw kursor na końcu wyświetlacza.
  lcd.print("*");                                            // Wyświetl gwiazdkę.
}
if (temperaturaZmierzona > (temperaturaNastawiona + 0.5)) {  // Jeśli temperatura zmierzona jest większa o pół stopnia od nastawionej, to...
  digitalWrite(przekaznik, LOW);                             // Wyłącz przekaźnik.
  lcd.setCursor(15, 0);                                      // Ustaw kursor na końcu wyświetlacza.
  lcd.print(" ");                                            // Wygaś gwiazdkę.
}

Przesuńmy nieco napisy i na ostatniej pozycji, gdy przekaźnik zostanie włączony, będziemy rysować gwiazdkę. Pozostanie tam do czasu wyłączenia przekaźnika. Po kompilacji możemy sobie kręcić gałką albo ogrzewać i oziębiać sensor, obserwując włączanie i wyłączanie przekaźnika. Coś jednak jest nie tak, gałka ma rozdzielczość jednego stopnia. Czasem to wystarczy, ale wolałbym mieć większą dokładność. Tajemnica mieści się w tej linii:

temperaturaNastawiona = map(analogRead(termostat), 0, 1023, 10, 30);

Mapowanie da nam tu wartości całkowite, a nam przydałyby się ułamkowe. Należy użyć metody jak w bloku powyżej, czyli przeliczania wartości odczytanych z przetwornika na nasz zakres:

temperaturaNastawiona = (analogRead(termostat) * 0.01955 + 10);

Skąd takie kosmate liczby? Mając przedział od zera do 1023 chcemy otrzymać od 10 do 30. Wystarczy więc podzielić 20 (bo tyle wynosi różnica) przez 1023, by dostać współczynnik, do którego trzeba potem dodać dziesięć, by przesunąć zakres o 10 stopni w górę. Wynik jest taki sam, jak w przypadku użycia funkcji map, ale teraz mamy większą rozdzielczość.

I to byłoby na tyle. Można pomyśleć jeszcze o watchdogu, wszak mamy tutaj grzejnik i konsekwencje tegoż, ale o tym już kiedyś pisałem i pominę ten element w tej chwili. Zresztą każdy grzejnik powinien mieć sprzętowego watchdoga, który przepali bezpiecznik w razie jakiejś awarii czy przerwania drożności przepływu powietrza i takich rzeczy powinniśmy pilnować niezależnie. To jednak nie koniec – taki termostat to nic wielkiego. W kolejnym artykule spróbujemy zarządzać nim zdalnie.

Powiązane tematy

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2025 arduino.pl