Aiuto per programma controllo temperatura

Salve a tutti , chiedo aiuto per risolvere un problema di questo sketch/hardware (in allegato trovate schemi circuito):

Il funzionamento e’ il seguente:

accendo alimentatore, si accendono i led per 6 secondi, poi rimane acceso solo uno ad indicare “io sto scaldando” e poi a seguire al raggiungimento delle temperature 180 190 200 210 220 °c si accendono in serie i vari led associati.

il problema e’ che nella pratica succede che

il led 180°c comincia a lampeggiare perche ci si sta avvicinando alla temperatura poi diventa stabilmente acceso ma comincia a lampeggiare il secondo ed il terzo poi si stabilizza anche il secondo etc etc

questo e’ dovuto dal fatto che il valore di lettura del termistore e’ variabile quindi magari ci restituisce 8 letture 182 che fanno accendere il primo led e due 191 ed ecco che il secondo lampeggia!

per risolvere questo problema ho pensato che si possa fare in logica in questo modo:

invece di far accendere il led alla lettura “diretta” del termistore bisognerebbe farlo accendere alla lettura di una media di valori raccolta in un intervallo di tempo:

quindi per T secondi leggo il termistore e restituisco il valore media Vm , se Vm e’ maggiore di tot allora accendi il led
se il led si e’ accesso allora lascialo acceso ed esegui una nuova lettura del valore Vm e cosi via

in questo modo mi sembra di risolvere.

chiedo il vostro parere in merito valutando eventualmente anche soluzioni hardware, ad esempio mi viene ora in mente che forse si potrebbe risolvere aumentando il delay del loop.

che ne dite?

FTOJLAFI83LGWI4-marco.ino (4.99 KB)

aumentare il dalay… non è mai una buona cosa, nel senso che i delay sono solammente perdite di tempo senza fare nulla. Cosa diversa se usassi un controllo dei tempi per effettuare azioni diverse (utilizzo di millis()).
se non vuoi vedere lampeggi, che tutto sommato sono un “segnale” che la temperatura sta arrivando al valore allora la strada migliore è quella di ritardare l’accensione del led fino a quando (per esempio) per tre volte consecutive ti da il valore prefissato

potrebbe essere una buona strada...quindi in pratica il led si accende solamente quando almeno per n volte consecutive viene restituita una lettura sopra la soglia di riferimento.

Non sono un programmatore e non conosco il linguaggio e la sintassi, riesco piu' o meno a leggere le logiche di funzionamento di uno script...avresti degli esempi gia scritti o indicarmi qualcosa in piu' per far funzionare lo sketch?

be devi aggiungere una variabile che ti serve come contatore, quando inizi il riscaldamento la poni a zero poi appena una lettura raggiunge il primo punto da verificare incrementi la variabile, ripeti il controllo temperatura e l'incremento fino a quando la variabile raggiunge un numero n predefinito, a questo punto accendi il led corrispondente, azzeri la variabile e procedi con il prossimo punto di controllo, nel caso potresti aggiungere una ulteriore flag che ti indica che hai raggiunto il punto di controllo x così da non intervenire più su quel led che dovrà rimanere acceso... fino al ciclo di raffreddamento

un'altra piccola nota, é un problema comune che effettuare due letture di seguito su 2 pin analogici non da dei risultati attendibili ed è esattamente quello che fai tu :

void loop() {
  SetPoint = map(analogRead(ThresholdPin), 0, 1023, 180, 230);
  ActualTemp = double(Thermister(analogRead(ThermistorPin)));
...

per evitare malfunzionamenti è consigliabile ripetere la lettura scartando la prima per cui ti suggerisco di modificare così:

void loop() {
  SetPoint= analogRead(ThresholdPin); //prima lettura da scartare
  SetPoint = map(analogRead(ThresholdPin), 0, 1023, 180, 230); //lettura valida
  ActualTemp = analogRead(ThermistorPin); //prima lettura da scartare
ActualTemp = double(Thermister(analogRead(ThermistorPin))); //lettura valida
...

io farei una cosa così…

/*  Dincer Hepguler 2014
    http://borsaci06.com
    Read preset temperature value from pot at A1
    Command a MOSFET controlled heating system with PID algorithm

   For Reading a 100K thermistor.
  ============================================================

   (Gnd) ---- (100k-Resistor) -------|------- (100K-Thermistor) ---- (+5v)
                                     |
                               Analog Pin 0
  ============================================================


    ADDED LED TEMPERATURE FUNCTION 01/04/2019 by Alessandro


*/

#include <PID_v1.h>
#include <math.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address for a 16x2 line display

#define ThermistorPin 0            //Analog Pin thermistor connected   
#define ThresholdPin 1             //Analog pin temp pot connected
#define HeaterPin 9                //digital PWM pin heater connected

//elenco temperature
#define tmpThr0 0
#define tmpThr180  180
#define tmpThr190  190
#define tmpThr200  200
#define tmpThr210  210
#define tmpThr220  220
// indico quante volte devo controllare la temperatura prima di accendere il led
#define numeroPassaggi 20 // 1 controllo ogni 100 millisecondi quindi in totale 2 secondi

double SetPoint, ActualTemp, Output;
int pin , myPins[] = {7, 8, 10, 11, 12, 13};

//Specify the links and initial tuning parameters
PID myPID(&ActualTemp, &Output, &SetPoint, 2, 5, 1, DIRECT);

//the time we give the sensor to calibrate (10-30 secs according to the datasheet)
int calibrationTime = 10;

double Thermister(int RawADC) {
  double Temp;
  Temp = log(((10240000 / RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp )) * Temp );
  Temp = Temp - 273.15;            // Convert Kelvin to Celcius
  //Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
  return Temp;
}

void InitLeds () {
  for (pin = 0; pin <= 5; pin = pin + 1)
    pinMode( myPins[pin], OUTPUT);
  for (pin = 0; pin <= 5; pin = pin + 1)
    digitalWrite(myPins[pin] , HIGH);
  delay(3000) ;
  for (pin = 0; pin <= 5; pin = pin + 1)
    digitalWrite(myPins[pin] , LOW);
  delay(0) ;
  for (pin = 0; pin <= 5; pin = pin + 1)
    digitalWrite(myPins[pin] , HIGH);
  delay(3000) ;
  for (pin = 0; pin <= 5; pin = pin + 1)
    digitalWrite(myPins[pin] , LOW);
}

void  CheckTmpLeds(double temp , bool Idle) {
  static byte ledNum = 0;  // indicatore ultimo led acceso
  static byte contaPassaggi = 0;
  if (Idle) {
    InitLeds();
    contaPassaggi = 0;  //Per azzerare led e contatore rifare inizializzazione
    ledNum = 0;
  }
  if ((temp >= tmpThr0) && (ledNum < 1)) {
    digitalWrite(7 , HIGH);
    ledNum = 1;
  }
  if ((temp >= tmpThr180) && (ledNum < 2)) {
    if (contaPassaggi >= numeroPassaggi) {
      digitalWrite(8 , HIGH);
      ledNum = 2;
      contaPassaggi = 0;
    } else {
      contaPassaggi++;
    }
  }
  if ((temp >= tmpThr190) && (ledNum < 3)) {
    if (contaPassaggi >= numeroPassaggi) {
      digitalWrite(10 , HIGH);
      ledNum = 3;
      contaPassaggi = 0;
    } else {
      contaPassaggi++;
    }
  }
  if ((temp >= tmpThr200) && (ledNum < 4)) {
    if (contaPassaggi >= numeroPassaggi) {
      digitalWrite(11 , HIGH);
      ledNum = 4;
      contaPassaggi = 0;
    } else {
      contaPassaggi++;
    }
  }
  if ((temp >= tmpThr210) && (ledNum < 5)) {
    if (contaPassaggi >= numeroPassaggi) {
      digitalWrite(12 , HIGH);
      ledNum = 5;
      contaPassaggi = 0;
    } else {
      contaPassaggi++;
    }
  }
  if ((temp >= tmpThr220) && (ledNum < 6)) {
    if (contaPassaggi >= numeroPassaggi) {
      digitalWrite(13 , HIGH);
      ledNum = 6;
      contaPassaggi = 0;
    } else {
      contaPassaggi++;
    }
  }
}
/*
  void TemperatureLeds (double Temp, bool Idle) {
    if (Idle) {
      InitLeds();
    } else {
      if (Temp > TemperatureThreshold0) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , LOW);
        digitalWrite(10, LOW);
        digitalWrite(11, LOW);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
      }
      if (Temp > TemperatureThreshold180) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , HIGH);
        digitalWrite(10, LOW);
        digitalWrite(11, LOW);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
      }
      if (Temp > TemperatureThreshold190) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , HIGH);
        digitalWrite(10, HIGH);
        digitalWrite(11, LOW);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
      }
      if (Temp > TemperatureThreshold200) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , HIGH);
        digitalWrite(10, HIGH);
        digitalWrite(11, HIGH);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
      }
      if (Temp > TemperatureThreshold210) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , HIGH);
        digitalWrite(10, HIGH);
        digitalWrite(11, HIGH);
        digitalWrite(12, HIGH);
        digitalWrite(13, LOW);
      }
      if (Temp > TemperatureThreshold220) {
        digitalWrite(7 , HIGH);
        digitalWrite(8 , HIGH);
        digitalWrite(10, HIGH);
        digitalWrite(11, HIGH);
        digitalWrite(12, HIGH);
        digitalWrite(13, HIGH);
      }
    }
  }
*/
void setup() {
  pinMode(ThresholdPin, INPUT);
  pinMode(HeaterPin, OUTPUT);
  Serial.begin(57600);
  lcd.init();   // initialize the lcd
  lcd.backlight();
  lcd.clear();
  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
  lcd.setCursor(0, 0);
  lcd.print("calibrating....");
  for (int i = 0; i < calibrationTime; i++) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" done");
  Serial.println("SENSOR ACTIVE");
  delay(50);
  SetPoint = analogRead(ThresholdPin);
  SetPoint = map(analogRead(ThresholdPin), 0, 1023, 180, 230);
  ActualTemp = analogRead(ThermistorPin);
  ActualTemp = double(Thermister(analogRead(ThermistorPin)));
  CheckTmpLeds(ActualTemp , 1) ;

  lcd.clear();
  lcd.setCursor(0, 0); //Start at character 0 on line 0
  lcd.print("THRESHOLD  TEMP ");
  lcd.setCursor(3, 1);
  lcd.print(SetPoint);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop() {
  SetPoint = analogRead(ThresholdPin);
  SetPoint = map(analogRead(ThresholdPin), 0, 1023, 180, 230);
  ActualTemp = analogRead(ThermistorPin);
  ActualTemp = double(Thermister(analogRead(ThermistorPin)));
  CheckTmpLeds(ActualTemp , 0) ;
  myPID.Compute();
  analogWrite(HeaterPin, Output);
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(11, 1);
  lcd.print(ActualTemp);
  lcd.setCursor(3, 1);
  lcd.print("     ");
  lcd.setCursor(3, 1);
  lcd.print(SetPoint);

  Serial.print(SetPoint);  Serial.print("     ");
  Serial.println(ActualTemp);  // display
  delay(100);
}

ti ringrazio tantissimo... finche parliamo di logica di funzionamento posso partecipare e mi ci diverto ma poi tradurre in script non è il mio campo e sono davvero sotto zero... grazie mille per aver tradotto quello che proponevi in script... domani provo subito i tuoi suggerimenti e poi ti faccio sapere

ho appena provato a compilarlo ma mi restituisce questo errore (vedi foto allegata).

giusto per dire la mia : o e’ richiamata una funzione che non ho in libreria oppure e’ una variabile non dichiarata …riesco a fare ipotesi ma non riesco a scartarle… :confused:

ti allego schermate errore

ops.... errore mio... ovviamnete :) avevo lasciato le variabili tpmThr180, 190, 200...

e poi nei controlli avevo messo tmpThr 1, 2 ,3 ...

programma corretto riprova ;)

comunque come ti diceva l'ide

"'tmpThr' was not declared in this scope

quindi la variabile in questione non esiste, vuoi perchè è scritta in modo sbagliato o altro il passaggio successivo è quello di verificare appunto cosa doveva esserci scritto nella riga evidenziata ed essendo in questo caso un confronto con una temperatura di riferimento va da se che bisogna controllare le variabili che contengono questa temperature

scusa non avevo salvato le modifiche del programma... prova ora

ora invece mi da questo errore

azz anche nel setup ce n'è uno :)

avendo riscritto la funzione del controllo temperature e avendogli assegnato un nuovo nome è logico che il nome vecchio non lo trovi (la vecchia funzione come vedi è commentata)

semplicemente sostituisci

TemperatureLeds(ActualTemp , 1) ;

con

CheckTmpLeds(ActualTemp , 1) ;

se sei fortunato ora dovrebbe andare... a me ora compila, non lo avevo verificato

però lasciami dire che se vuoi continuare a pacioccare con arduino, dovresti proprio metterti di "buzzo buono" e cominciare a studiare almeno i rudimenti del linguaggio e del funzionamento altrimenti per ogni piccolo errore ti blocchi e non ne esci più

ehhh lo so ti do pienamente ragione...e che fino ra mi sono impegnato in altri campi come torni frese stampanti tre d disegno 3d...laurea in fisica...e a qualcosa bisogna rinunciare :)

lo sketch si compila elo caricato e provato....a primo impatti si vede una stabilizzazione dei led perfetta infatti non c'e' piu' nessun lampeggio pero' ci sono altri problemi, in ordine di accadimento e' successo questo

accendo ed imposto il potenziometro al minimo (180) il d7 e' acceso la temperatura sale, quando arriva a regime si accende il primo led lascio inalterato ed aspetto,dopo circa un minuto con le stesse letture sul monitor seriale si accende il led d11 poi il d12 (la temperatura e' sempre impostata a 180 e viene rilevata 180) strano!!! comincio ad alzare il potenziometro a 190 (il d10 continua a non accendersi) alzo al massimo (230) quando in lettura arriva verso i 215 si accende d13

(al momento i led che hanno funzionato bene per quel che mi riguarda e' d7 e d13) abbasso il potenziometro al minimo(180) la temperatura scende ritorna a stabilizzarsi sui 180 ma i led continuano a rimanere accesi (ovviamnte tranne il d10 che non si e' mai acceso) ora provo a fare un video e poi linko il link

Perché non pensare a una isteresi software?

Supponiamo che le successive letture della temperatura non differiscano di + o - 2 gradi, per cui ad esempio nell’intorno dei 180 tu abbia letture che vanno dai 178 ai 182 gradi. È chiaro che a questo punto il led dei 180 “balla”.

Se tu accendi il led dei 180 gradi quando c’è una PRIMA lettura >= 182 gradi e lo spegni quando cìè una PRIMA lettura <= 178 gradi ottieni una accensione non “ballerina” del led dei 180 gradi, al prezzo di una imprecisione di 4 gradi su 180, pari al 2,2%.

Lo stesso è applicabile alle altre segnalazioni di temperatura.

Ciao,
P.

per darvi un idea di quello che poi dovrei fare per valutare appunto il grado di precisione entro il quale stare, questo apparato verra’ utilizzato per la vaporizzazione di erbe in genere,
quindi il grado di precisione della temperatura puo’ variare tranquillamente di +/- 2,5 °C che per intenderci se invece di essere 180 gradi e’ 185 va bene uguale

vi allego il lavoro fatto in disegno software per mostrarvi quello che sara’ speriamo il lavoro finale

ecco il link se volete vedere la prova pratica.

https://youtu.be/G-2gzlag_Po

abbasso il potenziometro al minimo(180) la temperatura scende ritorna a stabilizzarsi sui 180 ma i led continuano a rimanere accesi (ovviamnte tranne il d10 che non si e' mai acceso)

certamente, non c'è nessuna istruzione che spenga i led ... quello che ho visto io era una funzione per accendere e basta von per verificare anche un abbassamento della temperatura, se così allora va rifatto tutto.... magari semplicemente come dice pgiano anche se il concetto dell'avere n letture costanti è poi lo stesso ;)

comincio ad alzare il potenziometro a 190 (il d10 continua a non accendersi)

veramente dal video si vede che al minuto 2:36 il led d10 (o forse è il led d11, non si capisce) si accende in quanto la temperatura ondeggia molto e per parecchie volte supera il valore 190....

il problema dell'accensione dei led successivi è dato dalle letture non coerenti che si verificano, alcune volte se noti viene letta una temperatura anche superiore ai 300 gradi, siccome il programma non filtra questi risultati impossibili il contatore viene incrementato e quando il numero di passaggi positivi supera il valore stabilito fa accendere il led successivo e ovviamente a quel punto la variabile ledNum viene impostata ad un valore x per cui le if con un valore più basso non vengono più considerate (e i relativi led non si accendono).

devi rivedere il modo in cui viene determinata la temperatura reale usando una media di n letture ed eliminando appunto i risultati che si discostano troppo da questa media. Una volta trovato un valore "corretto" di temperatura allora potrai usare la funzione che stabilisce che led accendere.

nel primo test che avevo fatto il d10 non si era acceso in quelo postato invece si. quello che i led devono fare è dare un riscontro della temperatura se è tot il led associato a quella temperatura lo indica. lo sketch da cui era partita la discussione in sostanza faceva questo... però con i problemi di cui abbiamo parlato. io n9n sono in grado assolutamente di migliorarlo, a titolo logico ho pensato ad una media e sela media è maggiore di tot allora accendi. in questo modo se i valori sballati non sono troppi la cosa funziona. sempre in linea di massima si può aggiungere lo scarto di un valore se si discosta di troppo dal valore impostato dal potenziometro.del tipo, se il potenziometro è impostato su 190 prendi tutti i valori che rilevi che non si discostano piu di 15 gradi poi fai la media poi comparala con i valori dei led e accendi i led che vengono superati dal volore media. all atto pratico non sono in grado di scrivere lo script e qui mi rimetto a voi!