Skocz do zawartości

Termostat z menu na jednym przycisku UNO


Pomocna odpowiedź

Cześć, chce zrobić termostat, który będzie oparty na dwóch rożnych ekranach które będą przełączane jednym guzikiem. Część, kodu mam napisane jednak doszedłem do momentu w którym nie wiem co może być nie tak. Przyjmę każda pomoc w ruszeniu z miejsca 🙂 Wiem, że podobny wątek był poruszany na forum jednak nie chce zmieniać pierwotnego problemu innego uzytkownika.

Poniżej załączam kod na jakim działam. Część kodu jest napisana prze zemnie a część zapożyczona z gotowego.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "dht.h"
 
LiquidCrystal_I2C lcd(0x3F,20,4);

dht DHT22;
 
#define DHT22PIN 13

int menu =1;   // This variable stores the current Screen number
boolean hasChanged = true;
const int buttonPin = 10;    // the number of the pushbutton pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

unsigned long aktualnyCzas = 0;     // Przypisanie long temperatury i willgotnosci
unsigned long zapamietanyCzas = 0;
unsigned long roznicaCzasu = 0;
 
void setup()
{
  lcd.init();// initialize the lcd
  lcd.backlight();
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
  {
  if (hasChanged == true) {
   
  switch(menu) {
    case 1:
      {
       secondScreen(); 
      }
      break;
   
    case 2:
      {
        fourthScreen();   //temperatura
      }
      break;
   
    case 3:
      {
        fifthScreen(); // wilgotnosc
      }
      break;
      
    case 0:
      {
        
      }
      break;
    }
}
 
    //-------------------------------
    // BEGIN of the switch debouncing code
    int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
 
if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
 
    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
 
      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        hasChanged = true;
        menu++;
      }
    } else {
      hasChanged = false;
    }
  }
  lastButtonState = reading;
  // END of the switch Debouncing code
  // --------------------------------------
  if (menu  > 3){
    menu = 1;
  }
 }

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

void secondScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("  Ekran nr 1 ");
    lcd.setCursor(0,1);
    lcd.print(" na moim menu !! ");
  }

/////////////////////////////////////////////////////// TEMPERATURA //////////////////////////////////////////////////
  
void fourthScreen()
  {
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
    if (roznicaCzasu >= 1000UL) {
  int chk = DHT22.read(DHT22PIN);
 
  zapamietanyCzas = aktualnyCzas;

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Temperatura (C): ");
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature, 2);
  }
 }

/////////////////////////////////////////////////////// WILOGTNOSC ////////////////////////////////////////////////////
  
void fifthScreen()
  {
    aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
    if (roznicaCzasu >= 1000UL) {
  int chk = DHT22.read(DHT22PIN);
 
  zapamietanyCzas = aktualnyCzas;

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Wilgotnosc: ");
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.humidity, 2);
  }
}

Główne problemy to:

1. Menu przełącza się miedzy ekranami, jednak zmienne (temperatury oraz wilgotności) nie są aktualizowane na bieżąco, widać tylko jakby jedną "klatkę" danego odczytu. Dopiero po powrocie do tego samego ekranu wartości jakby się aktualizowały. Chciałbym, żeby dane aktualizowały się na bieżąco. No i jak za szybko kliknę to czasami przeskakuje o 2 ekrany.

2. Chciałbym dodać do tego termostatu, dwoma kolejnymi przyciskami, funkcje regulacji temperatury, by przekaźniki wyłączały się po osiągnięciu założonych wartości.

3. Punkt na którym zależy mi póki co najmniej, optymalizacja kodu oraz ewentualnie dodanie dodatkowych funkcji.

Jestem mega amatorem pod względem optymalizacji, a wiem ze wiele spraw można uprościć, dodając biblioteki. Kurs na Arduino przerobiony, przynajmniej pierwsza część w 100 %, część druga w około 40%.

Dziękuje bardzo za wszelką pomoc. 🙂

Link to post
Share on other sites
(edytowany)

Tak krótko.

Problem pierwszy - program robi dokładnie to co chciałeś, czyli wyświetla nowy ekran tylko wtedy, gdy zmieniła się zmienna menu. Na początek usuń po prostu tego ifa przed switchem i zobacz co się stanie. Wyniknie z tego oczywiście inny problem, ale to już musisz sam zaobserwować. Czyli nie:

if (hasChanged) {
    switch(cośtam) {
      // tu jakieś case i inne mądre wynalazki
    } // koniec switcha
} // koniec ifa

a raczej po prostu:

switch(cośtam) {
  // tu jakieś case i inne mądre wynalazki
} // koniec switcha

Jeśli nic sensownego nie zobaczysz na ekranie - wrzuć po prostu (prowizorycznie) delay(100) na końcu loop.

Co do przeskakiwania o dwa - patrz problem trzeci.

Problem drugi: najpierw zrób działający program (oczywiście rozumiejąc jak on działa), potem będziemy sobie coś do niego dodawać.

Problem trzeci: przerzucenie na biblioteki własnego (czyli w tym przypadku zapożyczonego) kodu to bardzo dobry pomysł. Rozumiem sytuację, kiedy piszesz np. własną funkcję do debouncingu aby zrozumieć jak ona działa - w tym przypadku jest po prostu przekopiowana z innego i wcale nie stanowi szczytowego osiągnięcia sztuki programistycznej (vide przeskakiwanie). Zapoznaj się z biblioteką Bounce2, zastosuj w programie (przy kilku przyciskach kod pozostanie prosty, bez tego będzie się komplikować), wtedy pogadamy o rozbudowie. A przy okazji najprawdopodobniej przestanie przeskakiwać 🙂

A co do kursu - przejrzyj sobie pobieżnie przynajmniej tytuły pozostałych 60%, być może gdzieś tam jest rozwiązanie któregoś z Twoich problemów?

No, do roboty, czekam na problem czwarty wynikły z rozwiązania problemu pierwszego 🙂

 

 

 

Edytowano przez ethanak
  • Lubię! 2
Link to post
Share on other sites

Okej, problem pierwszy, częściowo zażegnany. Po usunięciu "ifa" ekrany się zmieniają i aktualizują na bieżąco wartości, jednak pojawił się problem czwarty, który przewidziałeś niczym z magicznej kuli 🙂 .

Problemem jest  mruganie lub zanikanie tekstu. W momencie dodania delay'u na końcu, tekst z pierwszego ekranu mruga, bez tego delay'a zanika.

Co do biblioteki Bounce2, pobrana i staram się z nią zapoznać na podstawie gotowych przykładów jakie znajdują się w tej bibliotece, jednak wszystkie opierają się na ledzie i nie wiem do końca który z tych przykładów może mieć zastosowanie w moim problemie ? No i dodatkowo część kodu znajdującą sie w loop ma być umieszczona za switchem czy przed ? 🤷‍♂️

 

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

Problemem jest  mruganie lub zanikanie tekstu

Tak, to było przewidziane 🙂

Wyobraź sobie funkcję rysowania ekranu:

void fourthScreen()
{
  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): ");
  }  
  // wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co sekundę
  if (roznicaCzasu >= 1000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature, 2);
  }
}

Zauważ: nie będzie migać i znikać, bo czyścimy ekran tylko raz na początku wejścia w nową pozycję menu

Nie jest potrzebny żaden delay, bo odczyt i wyświetlenie temperatury jest tylko wtedy kiedy trzeba, nie ma czyszczenia całego ekranu, a pętla loop może się kręcić

Pozostaje tylko zmuszenie wyświetlacza, aby czyścił śmieci po poprzednim wyświetleniu temperatury... ale to zadanie domowe 🙂

A co do Bounce2:

Załóżmy, że masz w programie jakiś "przycisk", ładnie zdeklarowany i zainicjalizowany. Czyli możesz napisać np:

void loop()
{
  przycisk.update();
  hasChanged = przycisk.fell();
  if (hasChanged) {
    menu++;
    if (menu > COUNT_MENU) menu = 1;
  }
  // dalej reszta kodu

Przy okazji - lepiej pozycje menu liczyć od zera, wtedy kod się upraszcza:

if (hasChanged) menu = (menu + 1) % COUNT_MENU;

Może być? Mam nadzieję, że to zrozumiałe...

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

Kod poprawiony, troszkę uporządkowany, wygląda on następująco

#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

int menu = 1;  

Bounce przycisk = Bounce();

boolean hasChanged = true;

int COUNT_MENU = 3;

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();
  przycisk.attach(BUTTON_PIN,INPUT_PULLUP); // przypisanie przysku
  przycisk.interval(25);            //  określenie interwałow przycisku
}

void loop()
  {
  przycisk.update();                // wywolanie funkcji przycisku
  hasChanged = przycisk.fell();
  
  if (hasChanged) {
   menu++;
   if (menu > COUNT_MENU) menu = 1;
  }
  
  switch(menu) {
    case 0:
      {
       menu = 1;
      }
      break;
    case 1:
      {
       secondScreen();    // widok głowny
      }
      break;
    case 2:
      {
       fourthScreen();   // temperatura
      }
      break;
    case 3:
      {
       fifthScreen();    // wilgotnosc
      }
      break;
  }
  delay(100);
}

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

void secondScreen()
{
  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");
  }
}

/////////////////////////////////////////////////////// TEMPERATURA //////////////////////////////////////////////////
  
void fourthScreen()
 {
  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)");
  }  
  // wypisujemy temperaturę albo od razu po wyświetleniu menu, albo co sekundę
  if (roznicaCzasu >= 2000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature, 2);
  }
}


/////////////////////////////////////////////////////// WILOGTNOSC ////////////////////////////////////////////////////
  
void fifthScreen()
  {
  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 sekundę
  if (roznicaCzasu >= 2000UL || hasChanged) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.humidity, 2);
  }
}

Temperatura oraz wilgotność aktualizują się prawidłowo co 2 sekundy. Biblioteka Bounce2, również skróciła oraz "rozjaśniła" cały kod. 🙂

Jedynym mankamentem, który domyślam się jest błahy, jest czysty ekran po załadowaniu programu, dopiero po pierwszym kliknięciu przyciskiem pojawia się temperatura i dalej wszystko funkcjonuje prawidłowo.

Próbowałem z dodatkiem default do swatcha oraz podpowiedzianym odliczaniem pozycji menu od zera, jednak nie chciało dobrze to zagrać.

Link to post
Share on other sites
34 minuty temu, lewwus napisał:

Jedynym mankamentem, który domyślam się jest błahy, jest czysty ekran po załadowaniu programu,

Przerzuć wywołanie przycisk.fell() za switcha - wtedy przy pierwszym obrocie pętli dostanie wartość którą mu nadajesz przy inicjalizacji, a dopiero przy następnym będzie reagował na wciśnięcie.

A, przy okazji, ten delay na końcu miał być prowizoryczny, nie powinien być więcej potrzebny!

  • Pomogłeś! 1
Link to post
Share on other sites

Wszystko działa prawidłowo, delay usunięty. 🙂 (przepraszam za brak rozgarnięcia). Dziękuję pięknie za pomoc !

Chciałbym się też dowiedzieć (jeśli możesz wiedzieć), bo nie wiem czy to wina kodu czy samego czujnika DHT22, ale momentami odczyt wilgotności wskazuje -999, jednak po 2 sekundach kiedy ma być wykonany nowy odczyt błąd ten znika.

Dodatkowo wspomniałem na początku, że chciałbym dodać do tego rozwiązania możliwość regulacji temperatury np. w pomieszczeniu poprzez podłączenie przekaźnika, który będzie załączał się i wyłączał w odpowiednim momencie. Myślę, że to jest dobry moment. 🙂

Dodatkowe przyciski zostały zdefiniowane, przekaźnik też. Tak wygląda kod w aktualnej postaci.

#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 9
#define BUTTON_PIN_2 8
#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 = 3;

int zmiennaTemp = 20;

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 przysku
  przycisk.interval(25);           
}

void loop()
  {  
  switch(menu) {
    case 1:
      {
       secondScreen();    // widok głowny
      }
      break;
    case 2:
      {
       fourthScreen();   // temperatura
      }
      break;
    case 3:
      {
       fifthScreen();    // wilgotnosc
      }
      break;
  }
  przycisk.update();                // wywolanie funkcji przycisku
  hasChanged = przycisk.fell();
  
  if (hasChanged) {
   menu++;
   if (menu > COUNT_MENU) menu = 1;
  }
  // załączenie sie przekaznika
  if (DHT22.temperature >= zmiennaTemp){
    digitalWrite(RELAY_PIN, HIGH);
  } 
  else if (DHT22.temperature <= zmiennaTemp){
    digitalWrite(RELAY_PIN, LOW);
  }
}
/////////////////////////////////////////////////////// WIDOK GŁÓWNY /////////////////////////////////////////////////

void secondScreen()
{
  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");
  }
}

/////////////////////////////////////////////////////// TEMPERATURA //////////////////////////////////////////////////
  
void fourthScreen()
 {
  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("Ustawiona"); // wpisanie zmienianej temperatury
    lcd.setCursor(0,3);
    lcd.print(zmiennaTemp);
  }  
  // 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, 2);
  }
// zmiana wartosci załączania sie przekażnika
  przyciskPlus.update();        // przyciski do regulacji temperatury
  przyciskMinus.update();
  
  int wzrostTemp = przyciskPlus.fell();     // zdefiniowanie przycisków
  int spadekTemp = przyciskMinus.fell();
   
  if (wzrostTemp){
      zmiennaTemp++;
      zmiennaTemp = constrain (zmiennaTemp, 10, 50);
      lcd.setCursor(0,3);
      lcd.print(zmiennaTemp);
  }
  else if (spadekTemp){
      zmiennaTemp--;
      zmiennaTemp = constrain (zmiennaTemp, 10, 50);
      lcd.setCursor(0,3);
      lcd.print(zmiennaTemp);
  }
// załączenie sie przekaznika
  /*if (DHT22.temperature >= zmiennaTemp){
    digitalWrite(RELAY_PIN, HIGH);
  } 
  else if (DHT22.temperature <= zmiennaTemp){
    digitalWrite(RELAY_PIN, LOW);
  }*/
}


/////////////////////////////////////////////////////// WILOGTNOSC ////////////////////////////////////////////////////
  
void fifthScreen()
  {
  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);
  }
}

Jako komentarz mam dodane załączanie się przekaźnika w fifthScreen bo zauważyłem, że będąc tylko w nim przekaźnik działa. Przerzuciłem to do loopa, tylko nie wiem do końca czy taka forma jest prawidłowa ? Czy może zamiast

// załączenie sie przekaznika
  if (DHT22.temperature >= zmiennaTemp){
    digitalWrite(RELAY_PIN, HIGH);
  } 
  else if (DHT22.temperature <= zmiennaTemp){
    digitalWrite(RELAY_PIN, LOW);
  }

Zdefiniować jakaś zmienną lub voidem ? Bo w momencie dodania tam kolejnego przekaźnika do wilgotności, to może nie wyglądać estetycznie. Może istnieje jeszcze inna metoda uporządkowania tego ? 🙄

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

Zdefiniować jakaś zmienną lub voidem

CZYM???

Marsz do kursu (albo gdziekolwiek gdzie piszą coś o podstawach C/C++) i zgłosisz się jak będziesz wiedział co znaczy słowo "void". Wybacz, ale bez znajomości podstawowej terminologii po prostu nie jestem w stanie czegokolwiek wyjaśnić.

Przy okazji - w sieci (i na tym forum też) jest od metra przykładów jak się robi termostat. Poczytaj co to histereza, przeanalizuj przykłady i wyciągnij wnioski.

 

Link to post
Share on other sites

Ja jednak dopytam z ciekawości.

@lewwus, a co dokładnie miałeś na myśli pisząc o tym voidzie? Może to tylko jakieś językowe nieporozumienie 😉

Link to post
Share on other sites

Wybaczcie za mój błąd z voidem lub zmienna, nie jestem programista, a to co robię wykonuje hobbystycznie poza godzinami regularnej pracy. Wiem, że mam braki (i to nie małe!), jednak dziękuje za zwrócenie uwagi i odesłanie do dalszej nauki 🙂.

@Treker zgadza się to co miałem na myśli to była osobna funkcja tak jak w przykładzie poniżej.

void loop() {
  .
    .
    .
    // kod własciwy
  regulacjaTemp();
}
 
void regulacjaTemp() {
  // wykonanie czynnosci/ zadania
}

Na przyszłość będę pamiętał i zabieram się za dalsze kształcenie 😉

Link to post
Share on other sites

@lewwus i pamiętaj jeszcze: void do typ (tak jak int, float, bool czy różne inne). Czyli
 

void costam()
{...}
int cosinnego()
{...}

oznaczają odpowiednio "funkcja costam która nie zwraca wyniku" i "funkcja cosinnego która zwraca wynik typu int".

Ja doskonale rozumiem skąd to się bierze: po prostu jak ktoś patrzy na kod, widzi "void setup" i "void loop" i dochodzi do wniosku, że są tam jakieś dwa voidy co się nazywają setup i loop. I tak to jest jak ktoś z  kursów czyta tylko ciekawsze kawałki  🙂 [1]

Wracając do tematu: o histerezie poczytałeś? Wyrzucenie regulacji temperatury do oddzielnej funkcji (np. typu void) to wielce zacny pomysł, poprawia czytelność, zmniejsza prawdopodobieństwo zrobienia błędu i ułatwia poprawki... zaproponujesz funkcję?

[1] Chyba że w kursach o tym nie mówią?

Link to post
Share on other sites

Zanotowane 🙂

Tak, poczytałem o histerezie i dodałem funkcje regulacji temperatury pomiędzy dwoma rożnymi wartościami. Jednak nie jestem do końca co do niej przekonany. 🤷‍♂️ Dokładniej to stany w ktorych włącza lub wyłącza się przekaźnik są odwrotne niż w innych rozwiązaniach, nie wiem czy jest to duży błąd.

Dodatkowo przekaźnik włącza się ponownie po załadowaniu temperatury maksymalnej na ekranie. Wersja z jedną temperaturą (bez histerezy) działa nie ważne jaki ekran wyświetlacz pokazuję.

#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 9
#define BUTTON_PIN_2 8
#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 = 40;

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);           
}

void loop()
  {  
  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;
  }
  przycisk.update();                // wywolanie funkcji przycisku
  hasChanged = przycisk.fell();
  
  if (hasChanged) {
   menu++;
   if (menu > COUNT_MENU) menu = 1;
  }
  // załączenie sie przekaznika
  regulacjaTemperatury();
}
/////////////////////////////////////////////////////// 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");
  }
}

/////////////////////////////////////////////////////// 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) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature, 2);
  }
// zmiana wartosci załączania sie przekażnika
  przyciskPlus.update();        // przyciski do regulacji temperatury
  przyciskMinus.update();
  
  int minTemp1 = przyciskPlus.fell();     // zdefiniowanie przycisków
  int minTemp2 = przyciskMinus.fell();
   
  if (minTemp1){
      minTemp++;
      minTemp = constrain (minTemp, 10, 50);
      lcd.setCursor(0,3);
      lcd.print(minTemp);
  }
  else if (minTemp2){
      minTemp--;
      minTemp = constrain (minTemp, 10, 50);
      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) {
    int chk = DHT22.read(DHT22PIN);
    zapamietanyCzas = aktualnyCzas;
    lcd.setCursor(0,1);
    lcd.print((float)DHT22.temperature, 2);
  }
// zmiana wartosci załączania sie przekażnika
  przyciskPlus.update();        // przyciski do regulacji temperatury
  przyciskMinus.update();
  
  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) && (DHT22.temperature <= maxTemp)){  // 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
if ((DHT22.temperature <= minTemp) && (DHT22.temperature <= maxTemp)){  

I w tym momencie całą histerezę diabli biorą. Masz wyłączyć grzanie jeśli temperatura opadnie poniżej minTemp i włączyć, jeśli wzroście powyżej maxTemp. Jeśli jest pośrodku to nie robisz nic.

 

 

Link to post
Share on other sites

Przecież ten kod dokładnie to robi... chociaż trochę niepotrzebnie sprawdza maxTemp, bo pewnie minTemp <= maxTemp.

  • 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.