Skocz do zawartości

Termostat


karolek55

Pomocna odpowiedź

Jestem w trakcie robienia termostatu, z dwoma czujnikami ds18b20. Ma ten termostat włączać pompkę, jeśli na jednym czujniku temperatura będzie wyższa jak 40 stopni i temperatura na drugim jest poniżej 29 stopni. Jeśli temperatura na drugim czujniku wzrośnie powyżej 29 stopni, pompka ma się  wyłączyć. Udało mi się zrobić działający układ. I moje pytanie jest takie co można ulepszyć w kodzie i czy jest prawidłowo napisany?  Zaznaczam że się powoli zaczynam uczyć programowania.

[code]
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
OneWire oneWire(A5);
DallasTemperature sensors(&oneWire);

float zadana = 29.00f;
float temp_wlaczenia = 40.00f;
float histereza = 1.00f;

void setup() {
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Temp PG:");
 lcd.setCursor(0, 1);
 lcd.print("Temp CO:");
 sensors.begin();
 pinMode(8, OUTPUT);



}

void loop() {
 sensors.requestTemperatures();
 lcd.setCursor(8, 0);
 lcd.print(" ");
 lcd.print(sensors.getTempCByIndex(0));
 lcd.setCursor(8, 1);
 lcd.print(" ");
 lcd.print(sensors.getTempCByIndex(1));
 delay(500);{

if (sensors.getTempCByIndex(1) >= temp_wlaczenia && sensors.getTempCByIndex(0) < zadana - histereza)
  {   digitalWrite(8, HIGH);}

  
  if (sensors.getTempCByIndex(1) <= temp_wlaczenia && sensors.getTempCByIndex(0) >= zadana){
  digitalWrite(8, LOW);}

  if (sensors.getTempCByIndex(0) > zadana){
  digitalWrite(8, LOW);}

   if (sensors.getTempCByIndex(1) < temp_wlaczenia){
  digitalWrite(8, LOW);}}}
  
  

[/code]

 

Edytowano przez karolek55
Link do komentarza
Share on other sites

A spróbuj zamiast czterech ifów zrobić dwa - coś w stylu:
 

if (trzeba_włączyć) włącz;
else if (trzeba_wyłączyć) wyłącz;

Pamiętaj, że jeżeli jakiś warunek został spełniony (czyli grzałka została właśnie włączona/wyłączona) to nie trzeba sprawdzać następnych.

  • Lubię! 2
Link do komentarza
Share on other sites

sensors.requestTemperatures() robi "delay" ~750ms (zależy od ustawienia czujników, tyle standardowo dla 12bitów), więc swój delay możesz wywalić. Lepiej czujniki odczytywać po numerze seryjnym, jest to w przykładach biblioteki, a jak określonego zabraknie zawiesić wykonywanie programu, unikniesz porównywania czegoś do przypadkowej wartości. No i jeśli zakres temperatur szczęśliwie mieści się w zakresie np. 0.01-84.99oC to inne odczyty można określić jako błędne i również zareagować, błędy z czujnikami mogą sugerować temperatury -127;0;85 oC. Jeśli program miałby robić później coś więcej to jednak trzeba go napisać nieco inaczej, dla dwóch temperatur i przekaźnika to obojętne. Np. to "getTempCByIndex(1)" zawsze komunikuje się z czujnikiem DS dokonując odczytu, co zajmuje za każdym razem ~25ms, komunikacja ONEWIRE jest bardzo wolna, lepiej odczytać raz i przypisać do zmiennej, potem użyć X razy już taką zmienną.

Link do komentarza
Share on other sites

Przerobiłem i dodałem adresy czujników, jeśli wyłączenie przekaźnika zrobi się pod jednym "if" układ nie działa poprawnie. Układ będzie pracował  w przedziale temperatur od +15 stopni do 80 stopni.

[code]
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
OneWire oneWire(A5);
DallasTemperature sensors(&oneWire);

DeviceAddress PD = { 0x28, 0xD8, 0x75, 0x95, 0xF0, 0x1, 0x3C, 0xF0 };
DeviceAddress CO = { 0x28, 0xA9, 0xB5, 0x95, 0xF0, 0x1, 0x3C, 0x7D };  


float zadana = 23.00f;
float temp_wlaczenia = 23.00f;
float histereza = 1.00f;

void setup() {
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Temp PG:");
 lcd.setCursor(0, 1);
 lcd.print("Temp CO:");
 sensors.begin();
 pinMode(8, OUTPUT);



}

void loop() {
 sensors.requestTemperatures();
 lcd.setCursor(8, 0);
 lcd.print(" ");
 lcd.print(sensors.getTempC(PD));
 lcd.setCursor(8, 1);
 lcd.print(" ");
 lcd.print(sensors.getTempC(CO));
 {

if (sensors.getTempC(CO) > temp_wlaczenia && sensors.getTempC(PD) < zadana - histereza)
  {   digitalWrite(8, HIGH);}
 
 if (sensors.getTempC(CO) < temp_wlaczenia){
 digitalWrite(8, LOW);}
 
 if (sensors.getTempC(PD) > zadana){ 
  digitalWrite(8, LOW);}}}

[/code]

 

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

No to dodaj sobie np.  float tempCO=sensors.getTempC(CO) i  if, że jeśli tempCO>=85 lub tempCO<=0 (wyłącz przekaźniki, zapal czerwony led awarii, odczekaj 5s, zapisz licznik awarii++ w EEPROM, zresetuj WDT układ), może po resecie czujnik zacznie działać, jak nie, a licznik awarii przekroczy ileś tam zatrzymaj całkiem w while 1 i czekaj na interwencje serwisu. Możesz tu dać reset od jakiegoś przycisku przez WDT, który przy okazji zresetuje licznik awarii w EEPROM.

Przykład użycia WDT

/*
1 s WDTO_1S ATMega
2 s WDTO_2S ATMega
4 s WDTO_4S ATMega
8 s WDTO_8S ATMega
wdt_enable(WDTO_4S);
wdt_disable();
wdt_reset();
 */
#include <avr/wdt.h>

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);
wdt_enable(WDTO_4S);
Serial.println("Program został uruchomiony na nowo.");
}

void loop() {
  // put your main code here, to run repeatedly:
wdt_reset();
static int zmienna=0;
delay(1000);
Serial.print("Program dziala od sekund: ");
Serial.println(zmienna++);
delay(zmienna*100);
}

Nie używaj WDT ze starszymi wersjami NANO/PRO MINI. Najpierw trzeba wgrać nowszy bootloader, taki działający jak w UNO na 115200.

Link do komentarza
Share on other sites

Przerobiłem i dodałem adresy czujników, jeśli wyłączenie przekaźnika zrobi się pod jednym "if" układ nie działa poprawnie. Układ będzie pracował  w przedziale temperatur od +15 stopni do 80 stopni.

[code]
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
OneWire oneWire(A5);
DallasTemperature sensors(&oneWire);

DeviceAddress PD = { 0x28, 0xD8, 0x75, 0x95, 0xF0, 0x1, 0x3C, 0xF0 };
DeviceAddress CO = { 0x28, 0xA9, 0xB5, 0x95, 0xF0, 0x1, 0x3C, 0x7D };  


float zadana = 23.00f;
float temp_wlaczenia = 23.00f;
float histereza = 1.00f;

void setup() {
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Temp PG:");
 lcd.setCursor(0, 1);
 lcd.print("Temp CO:");
 sensors.begin();
 pinMode(8, OUTPUT);



}

void loop() {
 sensors.requestTemperatures();
 lcd.setCursor(8, 0);
 lcd.print(" ");
 lcd.print(sensors.getTempC(PD));
 lcd.setCursor(8, 1);
 lcd.print(" ");
 lcd.print(sensors.getTempC(CO));
 {

if (sensors.getTempC(CO) > temp_wlaczenia && sensors.getTempC(PD) < zadana - histereza)
  {   digitalWrite(8, HIGH);}
 
 if (sensors.getTempC(CO) < temp_wlaczenia){
 digitalWrite(8, LOW);}
 
 if (sensors.getTempC(PD) > zadana){ 
  digitalWrite(8, LOW);}}}

[/code]

 

Link do komentarza
Share on other sites

Poprawiłem kod

[code]
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
OneWire oneWire(A5);
DallasTemperature sensors(&oneWire);

DeviceAddress PD = { 0x28, 0xD8, 0x75, 0x95, 0xF0, 0x1, 0x3C, 0xF0 };
DeviceAddress CO = { 0x28, 0xA9, 0xB5, 0x95, 0xF0, 0x1, 0x3C, 0x7D };  


float zadana = 29.00f;
float temp_wlaczenia = 40.00f;
float histereza = 1.00f;

void setup() {
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Temp PG:");
 lcd.setCursor(0, 1);
 lcd.print("Temp CO:");
 sensors.begin();
 pinMode(8, OUTPUT);



}

void loop() {
 sensors.requestTemperatures();
 lcd.setCursor(8, 0);
 lcd.print(" ");
 lcd.print(sensors.getTempC(PD));
 lcd.setCursor(8, 1);
 lcd.print(" ");
 lcd.print(sensors.getTempC(CO));
 {

if (sensors.getTempC(CO) > temp_wlaczenia && sensors.getTempC(PD) < zadana - histereza)
  {   digitalWrite(8, HIGH);}
 
else { digitalWrite(8, LOW);}}}
  
  
[/code]

Działa nie do końca poprawnie, muszę z histerezą jeszcze pokombinować.

Link do komentarza
Share on other sites

@karolek55 a czemu nie chcesz zrobić tak jak proponowałem?

Przypominam:
 

if (trzeba)włączyć) włącz;
else if (trzeba wyłączyć) wyłacz;

Pamiętaj że "trzeba wyłączyć" to nie to samo co "nie trzeba włączyć", dlatego drugi if w gałęzi else. Ale jeśli sprawdzono że trzeba włączyć, to sprawdzanie że trzeba wyłączyć nie ma już żadnego sensu, prawda?

  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Tak ma to wyglądać? Bo nie jestem pewien.

[code]
if (sensors.getTempC(CO) > temp_wlaczenia && sensors.getTempC(PD) < zadana)
  {   digitalWrite(8, LOW);} 
 
else 
     if (sensors.getTempC(CO) < temp_wlaczenia && sensors.getTempC(PD) > zadana)
{ digitalWrite(8, HIGH);}}} 

[/code]

 

Edytowano przez karolek55
Link do komentarza
Share on other sites

4 godziny temu, ethanak napisał:

Jeśli działa to tak.

Nie działało, ale już mi się udało poprawić kod i już wszystko działa ok łącznie z histerezą.

[code]
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
OneWire oneWire(A5);
DallasTemperature sensors(&oneWire);

DeviceAddress PD = { 0x28, 0xD8, 0x75, 0x95, 0xF0, 0x1, 0x3C, 0xF0 };
DeviceAddress CO = { 0x28, 0xA9, 0xB5, 0x95, 0xF0, 0x1, 0x3C, 0x7D };  


float zadana = 29.00f;
float temp_wlaczenia = 40.00f;
float histereza = 1.00f;

void setup() {
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0, 0);
 lcd.print("Temp PD:");
 lcd.setCursor(0, 1);
 lcd.print("Temp CO:");
 sensors.begin();
 pinMode(8, OUTPUT);



}

void loop() {
 sensors.requestTemperatures();
 lcd.setCursor(8, 0);
 lcd.print(" ");
 lcd.print(sensors.getTempC(PD));
 lcd.setCursor(8, 1);
 lcd.print(" ");
 lcd.print(sensors.getTempC(CO));
 {

if (sensors.getTempC(CO) > temp_wlaczenia && sensors.getTempC(PD) < zadana - histereza)
  {   digitalWrite(8, LOW);} 
 
else 
     if ( sensors.getTempC(CO) < temp_wlaczenia ||  sensors.getTempC(PD) > zadana )
{ digitalWrite(8, HIGH);}}} 
  
  
[/code]

Błąd był przy drugim if źle łączyłem warunki.

Link do komentarza
Share on other sites

No, to jest prawie dobrze.

Ale pomyśl o tym - czy naprawdę trzeba dwa razy odczytywać temperaturę z sensora, nie wystarczy raz? Kiedyś wymyślili coś takiego jak zmienne robocze...

A na przykład:

float tCO = sensors.getTemp(CO);
float tPD = sensors.getTemp(PD);

if (tCO > temp_wlaczenia && tPD < zadana - histereza) {
  	digitalWrite(8, LOW);
} else if (tCO< temp_wlaczenia || tPD > zadana) {
	digitalWrite(8, HIGH);
} 
  
  

(nie wnikam w poprawność warunków).

Przy okazji - ja bym dał jednak histerezę również dla tCO.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.