Skocz do zawartości

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 to post
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 to post
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 to post
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 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

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 to post
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 to post
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 to post
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 to post
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 to post
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 to post
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 to post
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.