lettura ritardata 18B20

Ciao a tutti ho allestito una centralina per la gestione dell'acquario, ma ho un problema che non riesco a risolvere, ovvero la osnda ad immersione 18B20 che ad una temperatura stabilita deve far salire un relè per l'accensione di un termoriscaldatore ha letture troppo continue e basta una lieve oscillazione della temperatura per far salire e scendere in continuazione il relè e questo non va bene. Se uso la funzione delay() il tutto si incasina come ben sapere, usando millis() la temperatura stranamente impazzisce, vi posto la sezione del mio programma sperando in un vostro aiuto, grazie in anticipo.

void Temp18B20(){
  sensors.requestTemperatures();
  lcd.setCursor(0, 3);
  lcd.print("T.H2O: ");
  lcd.print (sensors.getTempCByIndex(0));
  int TempH2o=sensors.getTempCByIndex(0);
  
  if(TempH2o < Rison){
  digitalWrite(Riscaldatore,LOW); // Riscaldatore On
  digitalWrite(Alarm,HIGH); // Led Riscaldatore On
  digitalWrite(Ventola, HIGH); //Ventola Off
  digitalWrite(LedVentola, LOW); //led Ventola Off

  }
  else if(TempH2o >=Rison+3){
  digitalWrite(Riscaldatore,HIGH); // Riscaldatore Off
  digitalWrite(Alarm,LOW); // Led Riscaldatore Off
  digitalWrite(Ventola, LOW); //Ventola On
  digitalWrite(LedVentola, HIGH); //led Ventola On
  
  }
  else{
    digitalWrite(Riscaldatore,HIGH); // Riscaldatore Off
    digitalWrite(Alarm,LOW); // Led Riscaldatore Off
    digitalWrite(Ventola, HIGH); //Ventola Off
    digitalWrite(LedVentola, LOW); //led Ventola Off
  
  }
}
void TempDHT(){
     int16_t t = dht.readTemperature(TEMPTYPE); // read temperature
     lcd.setCursor(11,3);
     lcd.print(" T.Air:"); 
     lcd.print(t);// Print temperature
}

Ciao

Ti rispondo con una domanda: cosa succede se la temperatura vale TempH2o+2?

Secondo me c'è un else di troppo.

Ciao
Pippo72

Se la temperatura è maggiore di due gradi alla variabile "Rison", è tutto spento! Ed hai ragione che potrei omettere "Else", io però vorrei cercare di omettere le letture del sensore 18B20 così ravvicinate, mi piacerebbe che la sonda facesse letture ogni 30 secondi per evitare lo sfarfallio dei relè.

Posta il codice che hai sviluppato per l'uso di millis che ti fa "impazziere" le letture, perchè sicuramente c'è un errore nel come hai implementato la cosa visto che non c'è correlazione tra le due cose e, anch'io personalmente, uso millis() e DS18B20 senza problemi. Metti tutto il codice non solo lo stralcio perché l'errore potrebbe essere nella definizione delle variabili o in parti che se nonpostate non consentono l'individuazione dell'errore.
Seconda cosa, la serie di if else che hai codificato non è il modo corretto per definire l'isteresi della temperatura che stai cercando (come ti ha cercato di suggerire pippo72), se la temperatura scende sotto Rison accendi tutto, non appena torna copra Rison spegni tutto causando l'anomalia nei relé che indichi, un possibile modo di implementare la cosa può essere:

currentTempRead <= tempToReach - tempThresold);  
if(sistemaAcceso)
{
  sistemaAcceso = !(temperaturaAttuale >= temeperaturaDesiderata + soglia);
}
else
{
  //sistema spento
  sistemaAcceso = temperaturaAttuale <= temeperaturaDesiderata - soglia;
}
digitalWrite(Riscaldatore,sistemaAcceso );

la soglia la decidi tu (Es. 1 grado, mezzo grado, due gradi, ecc) e se la soglia inferiore deve essere differente dalla solgia sueriore puoi usare due variabili. In questo modo hai un range di temperatire nel quale se il sistema è acceso resta acceso fino a che la temperatura non varca la soglia superiore e resta spento finche non varca la soglia inferiore.
Provo a modificare il codice non millis e i suggerimenti (se vuoi) e postalo se hai problemi

Grazie mi hai dato una gran bella dritta, è da poco che mi cemento seriamente con Arduino e la mia programmazione è ancora grezza. In effetti il comando millis ancora non mi è molto chiaro e lo devo approfondire.

Per quanto riguarda il millis il codice è

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <OneWire.h> 
#include <DallasTemperature.h>
#include "DHT.h"
//************************************//
LiquidCrystal_I2C lcd(0x3F,20,4); // Display  I2C 20 x 4
RTC_DS1307 RTC;
//************Setup a OneWire**************//
#define ONE_WIRE_BUS 2 // pin 2 temperature sensor 18B20
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);
unsigned long readTime;
//************DHT********************//
#define DHTPIN 3 // pin 3 temperature sensor DHT
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define TEMPTYPE 0 //temperature °Celsius
//************Button*****************//
int P1=6; // Button SET MENU'
int P2=7; // Button +
int P3=8; // Button -
//**************Lamp***************//
int Lamp1=9; // pin 9 lamp 1
int Lamp2=10; // pin 10 lamp 2
int Lamp3=11; // pin 11 lamp 3
int Riscaldatore=4;  // pin 4 riscaldatore
int Ventola=5; //pin 5 Ventola raffreddamento
int LedVentola=12; //pin 12 led Ventola on/off
int Alarm=13; // pin 13 led Riscaldatore on/off

//************Variables**************//
int hourupg;
int minupg;
int yearupg;
int monthupg;
int dayupg;
int menu =0;
int setAll =0;
int LampOn1;
int LampOff1;
int LampOn2;
int LampOff2;
int LampOn3;
int LampOff3;
int Rison;
//************************************//
void setup()
{
LampOn1= EEPROM.read(0); // hour lamp 1 on
LampOff1 = EEPROM.read(1); // hour lamp 1 off
LampOn2 = EEPROM.read(2); // hour lamp 2 on
LampOff2 = EEPROM.read(3); // hour lamp 2 off
LampOn3 = EEPROM.read(4); // hour lamp 3 on
LampOff3 = EEPROM.read(5); // hour lamp 3 off
Rison= EEPROM.read(6); //set temp riscaldatore on
  lcd.begin();
  lcd.backlight();
  lcd.clear();
  pinMode(P1,INPUT_PULLUP);
  pinMode(P2,INPUT_PULLUP);
  pinMode(P3,INPUT_PULLUP);
  pinMode(Lamp1,OUTPUT);
  pinMode(Lamp2,OUTPUT);
  pinMode(Lamp3,OUTPUT);    
  pinMode(Riscaldatore,OUTPUT);
  pinMode(Alarm,OUTPUT);
  pinMode(Ventola,OUTPUT);
  pinMode(LedVentola,OUTPUT);
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  sensors.begin();
  dht.begin();


  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  // RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
    // The default display shows the date and time
  int menu=0;
}
 
void loop()
{ 

// check if you press the SET button and increase the menu index
  if(digitalRead(P1)== LOW) 
  delay(15); 
  {
   menu=menu+1;
  }
  if((digitalRead(P2)== LOW)&&(digitalRead(P3)== LOW))  
  delay(15);                                                                                                                                                                    
  {
    lcd.clear();
    SetLamp1On();
    SetLamp1Off();
    SetLamp2On();
    SetLamp2Off();
    SetLamp3On();
    SetLamp3Off();
    SetRison();
    delay(1000);
    lcd.clear();
  }
// in which subroutine should we go?
  if (menu==0)
    {
     DisplayDateTime(); // void DisplayDateTime
     Lamp(); // Lamp control
     Temp18B20(); // tempetature water
     TempDHT(); // // room temperature
          }
  if (menu==1)
    {
    DisplaySetHour();
    }
  if (menu==2)
    {
    DisplaySetMinute();
    }
  if (menu==3)
    {
    DisplaySetYear();
    }
  if (menu==4)
    {
    DisplaySetMonth();
    }
  if (menu==5)
    {
    DisplaySetDay();
    }
  if (menu==6)
    {
    StoreAgg(); 
    delay(500);
    menu=0;
    }
    delay(100);
}
void Temp18B20(){
 
  if(millis() > readTime+60000)
  sensors.requestTemperatures();
  lcd.setCursor(0, 3);
  lcd.print("H2O°C: ");
  lcd.print (sensors.getTempCByIndex(0));
  int TempH2o=sensors.getTempCByIndex(0);
  
  if(TempH2o < Rison){
  digitalWrite(Riscaldatore,LOW); // Riscaldatore On
  digitalWrite(Alarm,HIGH); // Led Riscaldatore On

  }
  else(TempH2o > Rison);{
  digitalWrite(Riscaldatore,HIGH); // Riscaldatore Off
  digitalWrite(Alarm,LOW); // Led Riscaldatore Off
  
  }
 
}
void TempDHT(){
     int16_t t = dht.readTemperature(TEMPTYPE); // read temperature
     lcd.setCursor(11,3);
     lcd.print("Air°C:"); 
     lcd.print(t);// Print temperature
}

La struttura del programam sembra corretta così a prima vista è l'uso di millis che è errato, sia come è scritto l'if (problema overflow) che nel suo uso, quindi il consiglio per capire per capire le basi con cui si usa millis() consiglio prima la lettura di QUESTO post esplicativo, dopo di che lo studio di come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... alla fine il tutto dovrebbe essere più chiaro :slight_smile:

Se ti torna meglio fai un piccolo programma che si occupi solo di leggere la temperatura della sonda a intervalli specificati (60000 nel tuo caso) e stampa i valori sulla seriale, avrai subito il riscontro se se sulla strada giusta o meno (devi veder stampato il valore ogni secondo sulla seriale), avendo tu correttamente gestito la lettura della temperatura in una funzione sarà semplice poi riportare il codice di test nel tuo programma definitivo.
Ti do anche un suggerimento ulteriore, anzi due, il primo leggi con meno frequenza la sonda, settata con la lettura di tutta la precisione come nel tuo programma la lettura impiega circa 700ms, leggere ogni secondo non ti serve, leggi magari ogni dieci secondi e soprattutto quando tutto ti funziona con questa modalità pensa a inserire la possibilità di efefttuare molte letture (5 o 6 o 10 o vedi tu :slight_smile: ) e effettuare la media delle temperature rilevate prima di decidere se accendere/spegnere i relé, in questo modo avrai un comportamento più "calmierato" e eludi sbalzi di temperatura improvvisi che potrebbero causare funzionamenti non desiderati

Grazie mille per il supporto, avevo pensato anche io ad una media di temperature, però questa sonda 18B20 ogni tanto pur essendo collegata in modo corretto con la resistenza da 4K7 mi restituisce una lettura -127 e sballerebbe le medie, tu cosa ne pensi?

if (leggo -127) non considero la lettura per la media?

Giustissimo grazie!

Oltre al giustissimo consiglio di docdoc puoi anche pensare anche di scartare dalle letture il massimo ed il minimo rilevato e mediare gli altri, in modo da escludere anche picchi anomali sia in più che in meno (ovvio valori differenti da -127 che è l'errore)

@fabpolli quello che dici è corretto, ma dipende dal numero di campioni considerati per la media, se faccio poche letture (es. 4 o 5) allora si, un picco in basso o in alto influisce abbastanza sulla media, se ne faccio abbastanza (es. 10 o più) uno spike può risultare poco influente.

Ma più che il massimo ed il minimo scarterei le letture che differiscono dagli altri valori di una quantità non realistica, ossia se parliamo di temperatura di un acquario non è ragionevole pensare che in 10 secondi possa salire la temperatura di più di 1 grado (a meno che non stia facendo pesce bollito, o si sia rotto il termostato del riscaldatore :wink: ) e quindi sono dati non affidabili.

Ad esempio leggendo (valore già convertito in gradi):

L(1)=24.5 ; L(2)=25.1 ; L(3)=24.9, L(4)=30.0 L(5)=25.2

poiché la differenza tra la lettura 3 e la 4 è superiore ad 1 grado, la scarto, quindi userò per il calcolo della media solo gli altri valori, che danno una media di 24.9.
Inoltre non farei la media a gruppi di 5 (o "n") letture, ma mi terrei un vettore delle ultime 5 letture (nel quale non inserire la lettura se il delta assoluto con la lettura precedente supera il valore di variazione massima considerata valida), quindi con una media mobile, il che non costringerebbe ad attendere tutto un lotto di letture per avere il successivo valore medio, ma solamente i primi "n" campioni.

Questo metodo può funzionare anche per i valori anomali -127 ovviamente.

Giustissimo @docdoc il tuo sicuramente è una versione molto performante dell'idea semplice e di base che ho fornito, sia sotto il punto di vista della memoria che della semplicità di codifica. Come ogni algoritmo è applicabile in determinati casi (questo sicuramente lo è) mentre altri casi escludono quest'approccio, come hai evidenziato tu se è lecito che vi siano sbalzi ampi. Avere più strade tra cui scegliere è sempre utile e bello :slight_smile:

Grazie Ragazzi siete tutti molto disponibili e pieni di idee.

Scusate ma ci sto impazzendo, Vi posto quello che ho scritto usando millis, il risultato è che Arduino va in blocco e non capisco il perchè, per favore consigliatemi sul da farsi, grazie.
Ps fra le altre cose non posso neppure implementare un watch dog avendo un menu con pulsanti.

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <OneWire.h> 
#include <DallasTemperature.h>
#include "DHT.h"
//************************************//
LiquidCrystal_I2C lcd(0x3F,20,4); // Display  I2C 20 x 4
RTC_DS1307 RTC;
//************Setup a OneWire**************//
#define ONE_WIRE_BUS 2 // pin 2 temperature sensor 18B20
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);

//************DHT********************//
#define DHTPIN 3 // pin 3 temperature sensor DHT
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define TEMPTYPE 0 //temperature °Celsius
//************Button*****************//
int P1=6; // Button SET MENU'
int P2=7; // Button +
int P3=8; // Button -
//**************Lamp***************//
int Lamp1=9; // pin 9 lamp 1
int Lamp2=10; // pin 10 lamp 2
int Lamp3=11; // pin 11 lamp 3
int Riscaldatore=4;  // pin 4 riscaldatore
int Ventola=5; //pin 5 Ventola raffreddamento
int LedVentola=12; //pin 12 led Ventola on/off
int Alarm=13; // pin 13 led Riscaldatore on/off

//************Variables**************//
int hourupg;
int minupg;
int yearupg;
int monthupg;
int dayupg;
int menu =0;
int setAll =0;
int LampOn1;
int LampOff1;
int LampOn2;
int LampOff2;
int LampOn3;
int LampOff3;
int Rison;
//************************************//
void setup()
{
time=millis();
letturasonda=millis();
LampOn1= EEPROM.read(0); // hour lamp 1 on
LampOff1 = EEPROM.read(1); // hour lamp 1 off
LampOn2 = EEPROM.read(2); // hour lamp 2 on
LampOff2 = EEPROM.read(3); // hour lamp 2 off
LampOn3 = EEPROM.read(4); // hour lamp 3 on
LampOff3 = EEPROM.read(5); // hour lamp 3 off
Rison= EEPROM.read(6); //set temp riscaldatore on
  lcd.begin();
  lcd.backlight();
  lcd.clear();
  pinMode(P1,INPUT_PULLUP);
  pinMode(P2,INPUT_PULLUP);
  pinMode(P3,INPUT_PULLUP);
  pinMode(Lamp1,OUTPUT);
  pinMode(Lamp2,OUTPUT);
  pinMode(Lamp3,OUTPUT);    
  pinMode(Riscaldatore,OUTPUT);
  pinMode(Alarm,OUTPUT);
  pinMode(Ventola,OUTPUT);
  pinMode(LedVentola,OUTPUT);
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  sensors.begin();
  dht.begin();


  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  // RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
    // The default display shows the date and time
  int menu=0;
}
 
void loop()
{ 

// check if you press the SET button and increase the menu index
  if(digitalRead(P1)== LOW) 
  delay(15); 
  {
   menu=menu+1;
  }
  if((digitalRead(P2)== LOW)&&(digitalRead(P3)== LOW))  
  delay(15);                                                                                                                                                                    
  {
    lcd.clear();
    SetLamp1On();
    SetLamp1Off();
    SetLamp2On();
    SetLamp2Off();
    SetLamp3On();
    SetLamp3Off();
    SetRison();
    delay(1000);
    lcd.clear();
  }
// in which subroutine should we go?
  if (menu==0)
    {
     DisplayDateTime(); // void DisplayDateTime
     Lamp(); // Lamp control
     Temp18B20(); // tempetature water
     TempDHT(); // // room temperature
          }
  if (menu==1)
    {
    DisplaySetHour();
    }
  if (menu==2)
    {
    DisplaySetMinute();
    }
  if (menu==3)
    {
    DisplaySetYear();
    }
  if (menu==4)
    {
    DisplaySetMonth();
    }
  if (menu==5)
    {
    DisplaySetDay();
    }
  if (menu==6)
    {
    StoreAgg(); 
    delay(500);
    menu=0;
    }
    delay(100);
}
void Temp18B20(){
   
  if(time> letturasonda+60000);
  sensors.requestTemperatures();
  lcd.setCursor(0, 3);
  lcd.print("H2O°C: ");
  lcd.print (sensors.getTempCByIndex(0));
  int TempH2o=sensors.getTempCByIndex(0);
  letturasonda=millis();
  
  
  if(TempH2o < Rison)
  {
  digitalWrite(Riscaldatore,LOW); // Riscaldatore On
  digitalWrite(Alarm,HIGH); // Led Riscaldatore On

  }
  else(TempH2o > Rison)
  {
  digitalWrite(Riscaldatore,HIGH); // Riscaldatore Off
  digitalWrite(Alarm,LOW); // Led Riscaldatore Off
  
  }
 
}
void TempDHT(){
     int16_t t = dht.readTemperature(TEMPTYPE); // read temperature
     lcd.setCursor(11,3);
     lcd.print("Air°C:"); 
     lcd.print(t);// Print temperature
}

:slight_smile: e time quando lo aggiorni?

if(time> letturasonda+60000);
  sensors.requestTemperatures();
  lcd.setCursor(0, 3);
  lcd.print("H2O°C: ");
  lcd.print (sensors.getTempCByIndex(0));
  int TempH2o=sensors.getTempCByIndex(0);
  letturasonda=millis();

Mi hai messo in crisi...........

A parte che stai continuando ad utilizzare il vecchio codice, il che dimostra che i link che ti avevo passato per studiare il funzionamento di millis o non li hai proprio guardati o comunque li hai solo letti e non studiati, il tuo codice andrà in contro a problemi di overflow quando millis verrà resettato, ma detto questo il problema è nell'if, in quel modo le istruzioni sotto vengono sempre eseguite perché solo la prima è di fatto dentro l'if mente le altre istruzioni sono "fuori" dall'if le hai indentate ma non è python dove l'indentazione determina se un istruzione è dentro l'if o meno, in C ti servono le graffe

Ti rinnovo il consiglio di farti un piccolo programmino che fa solo il controllo sonda ogni tot secondi e di non tentare di integrare subito la funzionalità nel tuo programma vero e proprio finché non avrai compreso millis() alla perfezione, perdi solo tempo e anche se riesci a "farlo funzionare" senza comprendere millis alla prossima sarai d'accapo.

Altra cosa il waitchdoc non va mai implementato per risolvere anomalie di programma (Es. mi si blocca a volte su una determinata funzione, vabbé ci pensa il waitchdog) quelle vanno risolte. Il waitchdog serve per resettare in casi di anomalie transitorie dovute a fattori non riconducibili alla normale operatività del programma/hardware (Es. un interferenza anomala che va a modificare in modo imprevisto qualcosa)

Grazie, no no ho letto tutti gli articoli che mi hai consigliato, ma sono in difficoltà, forse sarò vecchio ma fatico a capire, non Vi disturbo più finchè la cosa non mi sarà chiara, non capisco come mai ho così tante difficoltà con questo cavolo di millis?
Proverò a fare il programma di gestione della 18B20 come mi consigli.