Skocz do zawartości

Termostat z menu na jednym przycisku UNO


Pomocna odpowiedź

if 
  ((DHT22.temperature <= minTemp) && (DHT22.temperature <= maxTemp)){ digitalWrite(RELAY_PIN, LOW); } 

else if (DHT22.temperature >= maxTemp){ digitalWrite(RELAY_PIN, HIGH); }

W takiej formie histereza działa, bo po osiągnięciu tempMax przekaźnik się wyłącza. Włącza się po spadnieciu do tempMin i grzeje do tempMax. 

Problem jaki zauważyłem to, to że działa ona w momencie wyświetlania temp min i max czyli ekran 3.

Nie wiem jak inaczej to ugryźć, może jest jakaś inna droga. 😕

 

 

Link to post
Share on other sites

Dzięki za tyle wiedzy i rad ! 🙂

Jednak nie obyłoby się bez jakich przygód/problemów. Kod poprawiony, przede wszystkim oczyszczona przestrzeń w loopie. Histereza poprawiona, aktualnie wygląda tak

{
  if (DHT22.temperature <= minTemp){  // właczenie sie przkaznika gdy temp otoczenia jest mniejsza od minmalnej temp oraz mniejsza od maksymalnej
    digitalWrite(RELAY_PIN, LOW);
  } 
  else if (DHT22.temperature >= maxTemp){    // wylączenie sie przekaznika gdy jest rowna lub wieksza maksymalnej
    digitalWrite(RELAY_PIN, HIGH);
  }
}

Tak jak napisał @Elvis maxTemp nie jest sprawdzana i przekaźnik również działa prawidłowo !

Zmienna globalna "temperatura" dodana, jednak moje wątpliwości kierują się na zamienianie miejsc w ktorych są odwołania do DHT. Nie wiem jak to do końca zrobić, a dokładniej jak odwołać się do "temperatury" zamiast pełnego odczytu DHT22.

/////////////////////////////////////////////////////// GLOBALNY ODCZYT TEMPERATURY ///////////////////////////////////////////////

void odczytTemperatury(bool force)
{
  if (force || millis() - ostatniOdczyt > 2000UL) { // odczytujemy temperaturę co dwie sekundy
     DHT22.read(DHT22PIN);
     temperatura = (float)DHT22.temperature;
     ostatniOdczyt = millis();
   }
}

/////////////////////////////////////////////////////// TEMPERATURA MIN //////////////////////////////////////////////////
  
void temperaturaMin()
 {
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
  // jeśli menu zostało zmienione, czyścimy ekran i przygotowujemy do wyświetlania
  if (hasChanged) {
   //ukryta część kodu
  }  
  // wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature);
  }

 

Link to post
Share on other sites
8 minut temu, lewwus napisał:

Nie wiem jak to do końca zrobić, a dokładniej jak odwołać się do "temperatury" zamiast pełnego odczytu DHT22

Hm... a najprościej jak się da?

Masz taki fragment:

// wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature);
  }

A co powiesz na:

// wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print(temperatura);
  }

 

  • Lubię! 1
Link to post
Share on other sites

Poprawione !

Wszystko wydaje się działać tak jak trzeba, bez zakłóceń 🙂

Zastanawia mnie tylko jedno, bo zauważyłem lekkie opóźnienie/różnica miedzy działaniem przekaźnika a wyświetleniem temperatury. Jest jakaś recepta na te dolegliwość ? Nie jest to wielki błąd, bardziej bym nazwał to przyczepieniem się do szczegółów 🙂

 

#include <Wire.h>                   // dodanie bibliotek
#include <LiquidCrystal_I2C.h>
#include "dht.h"
#include <Bounce2.h>

LiquidCrystal_I2C lcd(0x3F,20,4);   //przypisanie wspołrzednyc ekranu LCD

dht DHT22;
 
#define DHT22PIN 13                 // zdefiniowanie podłączeń
#define BUTTON_PIN 10
#define BUTTON_PIN_1 8
#define BUTTON_PIN_2 9
#define RELAY_PIN 7

int menu = 1;  

Bounce przycisk = Bounce();         //okreslenie przycisków
Bounce przyciskPlus = Bounce();
Bounce przyciskMinus = Bounce();

boolean hasChanged = true;

int COUNT_MENU = 4;

int minTemp = 20;               // przypisanie wartosci temperatur
int maxTemp = 30;

float temperatura;
int32_t ostatniOdczyt;

unsigned long aktualnyCzas = 0;     // Przypisanie long temperatury i willgotnosci
unsigned long zapamietanyCzas = 0;
unsigned long roznicaCzasu = 0;
 
void setup()
{
  lcd.init();                       // inicjacja ekranu
  lcd.backlight();
  
  pinMode(RELAY_PIN, OUTPUT);    // przypisanie modułu przekaznika
  
  pinMode(BUTTON_PIN_1,INPUT_PULLUP); // przycisk do wzrostu temperatury
  przyciskPlus.attach(BUTTON_PIN_1);  
  przyciskPlus.interval(25);           //interwal
  
  pinMode(BUTTON_PIN_2,INPUT_PULLUP); // przycisk do zmniejszania temperatury
  przyciskMinus.attach(BUTTON_PIN_2); 
  przyciskMinus.interval(25);     
  
  przycisk.attach(BUTTON_PIN,INPUT_PULLUP); // przypisanie przycisku do zmiany menu
  przycisk.interval(25);
  
  odczytTemperatury(true);  //odczyt temperatury
           
}

void loop()
  {
    przycisk.update();  // stan przyciskow, debouncer
    przyciskPlus.update();   
    przyciskMinus.update();

    odczytTemperatury(false); // odczyt temp, niezaleznie w jakim oknie sie znajdujemy

    wyswietl();  //funkcja switch

    hasChanged = przycisk.fell();  // wywolanie funkcji przycisku
  if (hasChanged) {
      menu++;
  if (menu > COUNT_MENU) menu = 1;
  }
    regulacjaTemperatury();  //// załączenie sie przekaznika
}


/////////////////////////////////////////////////////// SWITCH /////////////////////////////////////////////////////

void wyswietl()
{
  switch(menu) {
    case 1:
      {
       menuGlowne();    // widok głowny
      }
      break;
    case 2:
      {
       temperaturaMin();   // temperatura min
      }
      break;
    case 3:
      {
       temperaturaMax();   // temperatura max
      }
      break;
    case 4:
      {
       wilgotnoscOdczyt();    // wilgotnosc
      }
      break;
  }
}

/////////////////////////////////////////////////////// WIDOK GŁÓWNY /////////////////////////////////////////////////

void menuGlowne()
{
  if (hasChanged) {
    lcd.clear();
    lcd.setCursor(4,0);
    lcd.print("STACJA METEO");
    lcd.setCursor(0,2);
    lcd.print("Temperatura ->  1");
    lcd.setCursor(0,3);
    lcd.print("Wilgotnosc ->   2");
  }
}

/////////////////////////////////////////////////////// GLOBALNY ODCZYT TEMPERATURY ///////////////////////////////////////////////

void odczytTemperatury(bool force)
{
  if (force || millis() - ostatniOdczyt > 2000UL) { // odczytujemy temperaturę co dwie sekundy
     DHT22.read(DHT22PIN);
     temperatura = (float)DHT22.temperature;
     ostatniOdczyt = millis();
   }
}

/////////////////////////////////////////////////////// TEMPERATURA MIN //////////////////////////////////////////////////
  
void temperaturaMin()
 {
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
  // jeśli menu zostało zmienione, czyścimy ekran i przygotowujemy do wyświetlania
  if (hasChanged) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Temperatura (C): ");
    lcd.setCursor(17,3);
    lcd.print("(1)");
    lcd.setCursor(0,2);
    lcd.print(">Min.Temp"); // wpisanie zmienianej temperatury
    lcd.setCursor(0,3);
    lcd.print(minTemp);
  }  
  // wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print(temperatura);
  }
  
  int minTemp1 = przyciskPlus.fell();     // zdefiniowanie przycisków
  int minTemp2 = przyciskMinus.fell();
   
  if (minTemp1){
      minTemp++;
      minTemp = constrain (minTemp, 0, 40);
      lcd.setCursor(0,3);
      lcd.print(minTemp);
  }
  else if (minTemp2){
      minTemp--;
      minTemp = constrain (minTemp, 0, 40);
      lcd.setCursor(0,3);
      lcd.print(minTemp);
  }
}

/////////////////////////////////////////////////////// TEMPERATURA MAX /////////////////////////////////////////////////
  
void temperaturaMax()
 {
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
  // jeśli menu zostało zmienione, czyścimy ekran i przygotowujemy do wyświetlania
  if (hasChanged) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Temperatura (C): ");
    lcd.setCursor(17,3);
    lcd.print("(1)");
    lcd.setCursor(0,2);
    lcd.print(">Min.Temp"); // wpisanie zmienianej temperatury
    lcd.setCursor(0,3);
    lcd.print(minTemp);
    lcd.setCursor(10,2);
    lcd.print(">Max.Temp"); 
    lcd.setCursor(10,3);
    lcd.print(maxTemp);
  }  
  // wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print(temperatura);
  }
   
  int maxTemp1 = przyciskPlus.fell();     // zdefiniowanie przycisków
  int maxTemp2 = przyciskMinus.fell();
   
  if (maxTemp1){
      maxTemp++;
      maxTemp = constrain (maxTemp, 10, 50);
      lcd.setCursor(10,3);
      lcd.print(maxTemp);
  }
  else if (maxTemp2){
      maxTemp--;
      maxTemp = constrain (maxTemp, 10, 50);
      lcd.setCursor(10,3);
      lcd.print(maxTemp);
  }
}

/////////////////////////////////////////////////////// WILOGTNOSC ////////////////////////////////////////////////////
  
void wilgotnoscOdczyt()
  {
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
  // jeśli menu zostało zmienione, czyścimy ekran i przygotowujemy do wyświetlania
  if (hasChanged) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Wilgotnosc (RH): ");
    lcd.setCursor(17,3);
    lcd.print("(2)");
  }  
  // wypisujemy wilgotność albo od razu po wyświetleniu menu, albo co 2 sekundy
  if (roznicaCzasu >= 2000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.humidity, 2);
  }
}

/////////////////////////////////////////////////////// REGULACJA TEMP //////////////////////////////////////////////////

void regulacjaTemperatury()
{
  if (DHT22.temperature <= minTemp){  // właczenie sie przkaznika gdy temp otoczenia jest mniejsza od minmalnej temp oraz mniejsza od maksymalnej
    digitalWrite(RELAY_PIN, LOW);
  } 
  else if (DHT22.temperature >= maxTemp){    // wylączenie sie przekaznika gdy jest rowna lub wieksza maksymalnej
    digitalWrite(RELAY_PIN, HIGH);
  }
}

 

Link to post
Share on other sites

Wracam z kolejną zagwozdką, a mianowicie chciałem dodać informacje o stanie przekaźnika, który byłby wyświetlany w menu głównym.

Aktualnie menu główne wygląda tak:

void menuGlowne()
{
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;

  if (hasChanged) { // tekst na menu glownym
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("PARAMETRY");
    lcd.setCursor(16,0);
    lcd.print("Stan");
    lcd.setCursor(0,2);
    lcd.print("Temp.");
    lcd.setCursor(0,3);
    lcd.print("Wilg.");
  }

  if (roznicaCzasu >= 2000UL || hasChanged) {  // wyswietlenie temp i wilgotnosci na menu głownym
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(7,2);
    lcd.print(temperatura);
    lcd.setCursor(12,2);
    lcd.print("C");
    lcd.setCursor(7,3);
    lcd.print(wilgotnosc);
    lcd.setCursor(12,3);
    lcd.print("%");
  }
  
  if (roznicaCzasu >= 2000UL || (wilgotnosc <= minWilg)){
    lcd.setCursor(16,3);
    lcd.print("ON");
  }
  else if (roznicaCzasu >= 2000UL || (wilgotnosc >= maxWilg)){
    lcd.setCursor(16,3);
    lcd.print("OFF");
  }
}

Jednak nie do konca działa to prawidłowo, przy pierwszym uruchomieniu i wyłączeniu przekaźnika jest okej, natomiast później tekst się pokrywa i nie wygląda to tak jak powinno.

Być może zamiast bazować na odczycie wilgotności powinienem odnieść się do samego stanu przekaźnika ?

Link to post
Share on other sites
35 minut temu, lewwus napisał:

chciałem dodać informacje o stanie przekaźnika,

Więc skąd wątpliwości

35 minut temu, lewwus napisał:

zamiast bazować na odczycie wilgotności powinienem odnieść się do samego stanu przekaźnika ?

Moim zdaniem aby pokazać stan przekaźnika należy pokazać stan przekaźnika, ale może mam za słabą wyobraźnię aby wyobrazić sobie inną możliwość... 🙂

Link to post
Share on other sites
10 godzin temu, ethanak napisał:

aby pokazać stan przekaźnika należy pokazać stan przekaźnika

Tak też myślałem 😀

Aktualna wersja jaka przychodzi mi na myśl

.
 // poprzednia część kodu
.
if (digitalRead(RELAY_PIN_W == LOW)){
    lcd.setCursor(16,3);
    lcd.print("ON");
  }
  else if (digitalRead(RELAY_PIN_W == HIGH)){
    lcd.setCursor(16,3);
    lcd.print("OFF");
  }
}

Niestety wyświetla się tylko "ON", po wyłączeniu przekaźnika nie pojawia się stan "OFF".

Link to post
Share on other sites

W takiej wersji jak poniżej ze zmienionymi nawiasami wydaje się działać prawidłowo

if (digitalRead(RELAY_PIN_W) == LOW){
    lcd.setCursor(16,3);
    lcd.print("ON.");
  }
  else if (digitalRead(RELAY_PIN_W) == HIGH){
    lcd.setCursor(16,3);
    lcd.print("OFF");
  }
}

Tylko czy to o to chodziło z tymi nawiasami ? 🙂

Link to post
Share on other sites

Owszem, o to.

A teraz tak:

Ponieważ digitalRead może zwracać albo HIGH, albo LOW, drugi warunek jest w ogóle niepotrzebny.

Czyli mielibyśmy:

if (digitalRead(RELAY_PIN_W) == LOW){
    lcd.setCursor(16,3);
    lcd.print("ON.");
  }
  else { // jeśli nie LOW to na pewno HIGH
    lcd.setCursor(16,3);
    lcd.print("OFF");
  }

Już nieco lepiej (mniej możliwości popełnienia błędu, prawda?)

Ale to jeszcze nic. Ponieważ ustawiasz kursor niezależnie od stanu przekaźnika, uprośćmy to bardziej:

lcd.setCursor(16,3);
if (digitalRead(RELAY_PIN_W) == LOW){
    lcd.print("ON.");
  }
  else {
    lcd.print("OFF");
  }

Co tu można jeszcze wyrzucić... a na przykład coś takiego: sprawdzasz czy pin jest w stanie HIGH. Ponieważ albo jest w stanie niskim (digitalRead zwróci zero) albo wysokim (digitalRead zwróci HIGH, czyli coś innego od zera) można skorzystać tu z faktu, że w C wszystko co nie jest zerem to prawda. Czyli upraszczamy dalej przy okazji pozbywając się niepotrzebnych już nawiasów:


lcd.setCursor(16,3);
if (digitalRead(RELAY_PIN_W)) lcd.print("OFF");
else lcd.print("ON.");

Już coraz lepiej... ale czy można jeszcze skrócić?

A można. Użyjmy operatora trójargumentowego:

lcd.setCursor(16,3);
lcd.print(digitalRead(RELAY_PIN_W) ? "OFF" : "ON.");

I z sześciu linijek plus nawiasy zrobiły się dwie 🙂

 

  • Pomogłeś! 2
Link to post
Share on other sites
(edytowany)
32 minuty temu, ethanak napisał:

operatora trójargumentowego:

?? Nie znałem

[wyr_logiczne] ? [wykonaj to, gdy wyrażenie jest prawdziwe] : [wykonaj to, gdy nieprawdziwe] 

thx

Edytowano przez SOYER
Link to post
Share on other sites
2 minuty temu, SOYER napisał:

?? 

Nie ?? tylko ?:

a ? b : c

Znany również jako "operator warunkowy". Występuje w wielu językach o składni zbliżonej do C (np. PHP, JavaScript i tak dalej).

 

  • Lubię! 1
Link to post
Share on other sites
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.