Skocz do zawartości

Termostat z menu na jednym przycisku UNO


lewwus

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 do komentarza
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 do komentarza
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 do komentarza
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

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 do komentarza
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 do komentarza
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 do komentarza
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 do komentarza
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 do komentarza
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 do komentarza
Share on other sites

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 do komentarza
Share on other sites

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.