Gestione termostato (LM35)

Salve a tutti.

Ho da poco realizzato un semplice termostato che, attravero un sensore di temperatura LM35, controlla la temperatura dell'aria di un rack mediante l'utilizzo di due ventole 12v. Il programma in questione abilta o disabilita l'alimentazione alle ventole tramite l'utilizzo di un relè controllato da un transistor e relativo diodo di protezione, in oltre al superato di un certo valore soglia fa lampeggiare un led ed azionare un buzzer per segnalare il malfunzionameto del sistema.

Purtroppo sorgono alcuni problemi/bug nella compilazione ed costruzione di questo progetto e sono i seguenti:

  • il valore della temperatura rilevata a volte viene falsato salendo in una rilevazione anche di 5 gradi
  • al raggiungimento della temperartura di allarme il suono d'allarme non si ripete cicilicamente (anche se inserito in un loop diverso) fino a quando il delay impostato a 30s (usato per ovviare al problema della temperatura rilevata dal sensore) non fa ripartirre il loop principale
  • il valore della misura non sembra essere nemmeno concordante rispetto al valore fornito da altri strumenti ma differente di circa 3 gradi

Ecco il codice installato all'interno della scheda Arduino UNO:

int TEMP;
int TEMPC;
int TEMPINT = 30;                // temperatura di intervento 
int TEMPALL = 42;                //temperatura di allarme

const int TEMPIN = A0;        //pin collegato al sensore di temperatura
const int X1PIN = 11;          //pin collegato al relè
const int BUZPIN = 13;        //pin collegato al buzzer
const int LEDPIN = 12;        //pin collegato al led 



void setup(){
   pinMode(X1PIN, OUTPUT);
   pinMode(BUZPIN, OUTPUT);
   pinMode(LEDPIN, OUTPUT);
}



void loop(){
  TEMP = ( analogRead(TEMPIN)/1024.0)*5000;
  TEMPC = TEMP/10;

if(TEMPC <= TEMPINT){
  digitalWrite(X1PIN, LOW);
  digitalWrite(LEDPIN, LOW);
}

if(TEMPC >= TEMPINT){
  digitalWrite(X1PIN, HIGH);
  digitalWrite(LEDPIN, HIGH);
}

if(TEMPC >= TEMPALL){
  allTEMP();
}

delay(30000);
}



void allTEMP(){
  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
    delay(200);
  
  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, LOW);
    delay(200);
    
  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
    delay(200);
    
  tone(BUZPIN,2048,200);
  digitalWrite(LEDPIN, LOW);
    delay(200);
  }

In allegato fornisco lo schema elettrico del termostato dove:

  • la tensione VCC di ingresso è di 12v
  • la tensione +5V a valle del regolatore viene collegata ad Arduino direttamente al pin 5V
  • la massa di tutto il circuito è comune
  • le ventole sono collegate alla stessa alimentazione di Arduino ovvero VCC

Spero, grazie all'aiuto del forum, di risolvere questi problemi e riuscire ad implementare nuove funzioni in futuro sia hardware che software.

Ringrazio in anticipo per le risposte fornite

Saluti

schema.pdf (36.4 KB)

Lo sai che nello schema hai commesso più errori di quanti componenti ci sono ?

  1. I due diodi Led, Led1 e Led2, sono montati rovesciati
  2. Il transistor Q1 ha i collegamenti invertiti ( Collettore ed Emittore )
  3. Il diodo sulla bobina del relè è rovesciato
  4. Al buzzer monterei in serie una resistenza
  5. I condensatori C1 e C2 li invertirei, non si monta mai un condensatore di capacità maggiore sull'uscita
    5a) Sempre sul 7805 mancano dei condensatori di disaccoppiamento da 100nF
  6. Tra i pin di uscita di Arduino e le basi dei transistors mancano delle resistenze

La funzione di allarme non cicla. Suona solo 4 volte lampeggiando il led.
Per evitare il blocco dovresti togliere il delay e gestire l'intervallo di lettura della temperatura con millis().

 TEMP = ( analogRead(TEMPIN)/1024.0)*5000;
  TEMPC = TEMP/10;

Qua presumi che i 5V del alimentazione dell'Arduino siano veramente 5,000V.
Non é cosí.
Usa il riferimento interno del ADC.

Ciao Uwe

Grazie mille a tutti per le rapidissime risposte e critiche

Venendo al progetto mi era stato consigliato quanto segue:

brunello22:
Lo sai che nello schema hai commesso più errori di quanti componenti ci sono ?

  1. I due diodi Led, Led1 e Led2, sono montati rovesciati
  2. Il transistor Q1 ha i collegamenti invertiti ( Collettore ed Emittore )
  3. Il diodo sulla bobina del relè è rovesciato
  4. Al buzzer monterei in serie una resistenza
  5. I condensatori C1 e C2 li invertirei, non si monta mai un condensatore di capacità maggiore sull'uscita
    5a) Sempre sul 7805 mancano dei condensatori di disaccoppiamento da 100nF
  6. Tra i pin di uscita di Arduino e le basi dei transistors mancano delle resistenze

Si in effetti me ne sono accorto pure io da solo di alcuni errori che avevo commesso, forse per per la fretta o per la distrazione.
Ad ogni modo ho corretto lo schema elettrico e adesso dovrebbe essere giusto(lo riposto negli allegati). Però c'è una cosa che non mi è ancora chiara, ovvero la funzione dei condesatori di disaccoppiamento. Ho sempre visto (per quanto riguarda la mia esperienza personale) che a seguito del regolatore di tensione venivano montati solo due condesatori il primo di capacità 10 volte maggiore al secondo e nient’altro, ed in internet non ho potuto trovare molto a riguardo.

fratt:
La funzione di allarme non cicla. Suona solo 4 volte lampeggiando il led.
Per evitare il blocco dovresti togliere il delay e gestire l'intervallo di lettura della temperatura con millis().

Per la funzione millis() mi ci è voluto un giorno per studiarne la teoria ma alla fine ne sono venuto a capo, quindi ho modificato lo sketch come segue e anche in questo punto il problema dovrebbe essere risoloto, forse :smiley: .
Ho modificato anche il tipo di alcune variabili portandole da tipo int (troppo ampia come range di valoi) a tipo byte (da 0 a 255).

ecco il codice modificato:

int TEMP;
int TEMPC;
byte TEMPINT = 30;
byte TEMPALL = 42;

const byte TEMPIN = A0;
const byte X1PIN = 11;
const byte BUZPIN = 13;
const byte LEDPIN = 12;

unsigned long MILLISPREC = 0;     
int INTERVAL = 4000;         



void setup(){
  pinMode(X1PIN, OUTPUT);
  pinMode(BUZPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
}


//loop principale
void loop(){
  if (millis() - MILLISPREC > INTERVAL) {
    MILLISPREC = millis();                      
    TEMP = (analogRead(TEMPIN)/1024.0)*5000;
    TEMPC = TEMP/10;
  }

  //in caso di temp bassa spegne le ventole   
  if(TEMPC <= TEMPINT){
    digitalWrite(X1PIN, LOW);
    digitalWrite(LEDPIN, LOW);
  }

  //in caso di temp alta accende le ventole  
  if(TEMPC >= TEMPINT){
    digitalWrite(X1PIN, HIGH);
    digitalWrite(LEDPIN, HIGH);
  }

  //in caso di temp di allarme suona l'allarme 
  if(TEMPC >= TEMPALL){
    allTEMP();
    digitalWrite(X1PIN, HIGH);
  }
}


//Loop di Allarme
void allTEMP(){
  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
  delay(200);

  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, LOW);
  delay(200);

  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
  delay(200);

  tone(BUZPIN,2048,200);
  digitalWrite(LEDPIN, LOW);
  delay(200);
}

uwefed:

 TEMP = ( analogRead(TEMPIN)/1024.0)*5000;

TEMPC = TEMP/10;



Qua presumi che i 5V del alimentazione dell'Arduino siano veramente 5,000V.
Non é cosí.
Usa il riferimento interno del ADC. 
https://www.arduino.cc/en/Reference/AnalogReference

Ciao Uwe

Qui purtroppo ho ancora problemi perchè non riesco a capire il funzionamento di questo AnalogReference.
In poche parole imposto il valore di fondo scala delle entrate analogiche anzichè di 5V lo porto a 1,1V ma questo non porta ad una limitazione della temperatura massima rilevabile con il sensore?
Ho visto in oltre che è possibile tramite il pin Aref ed opportuno partitore di tensione collegato ad esso consente di impostare una tensione di riferimento "custom" alle entrate analogiche nel mio caso dovrei preferire questa operazione per creare una tensione di 5V e non avere limitazioni nella temperatura massima rilevabile.

Ringrazio ulteriolmente tutti per le risposte fornite

saluti

Schema Termostato .pdf (37.5 KB)

In poche parole imposto il valore di fondo scala delle entrate analogiche anzichè di 5V lo porto a 1,1V ma questo non porta ad una limitazione della temperatura massima rilevabile con il sensore?

Sí, cosí limiti la tensione misurabile a 1,1V ovvero 110°C. Mi sembra che ben oltre ai valori che Ti serve misurare. Inoltre il LM35 regge al massimo 100°C o 110°C o 150°C (a secondo della versione: LM35, LM35A o LM35C, LM35CA o LM35D).

Ciao Uwe

uwefed:
Sí, cosí limiti la tensione misurabile a 1,1V ovvero 110°C. Mi sembra che ben oltre ai valori che Ti serve misurare. Inoltre il LM35 regge al massimo 100°C o 110°C o 150°C (a secondo della versione: LM35, LM35A o LM35C, LM35CA o LM35D).

Ciao Uwe

In effeti mi ero confuso non è la tensione di alimentazione del sensore che varia, ma il riferimento del microcontrollore.

Comunque ho modificato il programma e fatto delle prove (aggiungendo nel void setup l' anlog reference e la sucessiva trasmissione del dato via seriale):

int TEMP;
int TEMPC;
byte TEMPINT = 30;
byte TEMPALL = 42;

const byte TEMPIN = A0;
const byte X1PIN = 11;
const byte BUZPIN = 13;
const byte LEDPIN = 12;

unsigned long MILLISPREC = 0;     
int INTERVAL = 4000;         


//operazione da eseguire una sola volta
void setup(){
  pinMode(X1PIN, OUTPUT);
  pinMode(BUZPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
  
  Serial.begin(9600);
  
  analogReference(INTERNAL);
  analogRead(TEMPIN);
}


//loop principale
void loop(){
  if (millis() - MILLISPREC > INTERVAL) {
    MILLISPREC = millis();                      
    TEMP = (analogRead(TEMPIN)/1024.0)*5000;
    TEMPC = TEMP/10;
    
    Serial.println(TEMPC);
  }

  //in caso di temp bassa spegne le ventole   
  if(TEMPC <= TEMPINT){
    digitalWrite(X1PIN, LOW);
    digitalWrite(LEDPIN, LOW);
  }

  //in caso di temp alta accende le ventole  
  if(TEMPC >= TEMPINT){
    digitalWrite(X1PIN, HIGH);
    digitalWrite(LEDPIN, HIGH);
  }

  //in caso di temp di allarme suona l'allarme 
  if(TEMPC >= TEMPALL){
    allTEMP();
    digitalWrite(X1PIN, HIGH);
  }
}


//Loop di Allarme
void allTEMP(){
  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
  delay(200);

  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, LOW);
  delay(200);

  tone(BUZPIN,2048,100);
  digitalWrite(LEDPIN, HIGH);
  delay(200);

  tone(BUZPIN,2048,200);
  digitalWrite(LEDPIN, LOW);
  delay(200);
}

Mi sarei aspettato quindi di trovare un solo dato fuori scala (perchè ho omesso la lettura a vuoto per l'assenstamento ma anche con quel comando in più il risultato è lo stesso) invece la temperatura rilevata e trasmessa raggiunge un valore di 89-100 °C mentre l'ambiente è a 19°C quindi viene interpretata come temperatura di allarme.

Mentre senza il riferimento la temperatura viene letta correttamente e vengono accese e spente le ventole alla temperatura corretta.

Com'è possibile che accada tutto ciò ??
Potrebbe dipendere dal regolatore che non possiede ancora i condesatori di disaccoppiamento? Potrebbero influire sulle letture quando richiamo la funzione per il riferimento?

Grazie

Saluti

Beh, se usi il riferimento interno che è 1.1V, questa formula non è corretta

TEMP = (analogRead(TEMPIN) / 1024.0) * 5000;

a te capire dove

brunello22:
Beh, se usi il riferimento interno che è 1.1V, questa formula non è corretta

TEMP = (analogRead(TEMPIN) / 1024.0) * 5000;

a te capire dove

In effetti è anche un errore propio stupido :grinning: grazie mille per avermelo fatto notare!
Vediamo se ho capito:

Allora la formula che ho implementato nel mio programma è data dalla proporzione:

AnalogRead : 1024 =  X : Vref

Dove:
AnalogRead : E' il valore letto dall'ADC dell' arduino;
1024 : dato dai 10bit dell'ADC di Arduino quindi 210=1024 valori max
X : la tensione in entrata alla porta analogica
Vref: la tensione di riferimento delle porte analogiche che viene presa come fondo scala di norma è di 5000mV (5V)

Per trovare la tensione in mV in entrata sulla porta analogica devo indicare la tensione Vref in mV ed ottengo una risoluzione (R) di:

R = Vref/1024 = 5000/1024 = 4.88mV -> 5mV

Quindi risolvendo la proporzione ottengo la formula per il calcolo della tensione del sensore:

X = (AnalogRead / 1024) * 5000

Poichè da datashet del sensore vedo che l'incremento della tensione d'uscita (S) di quest'ultimo è di 10mV/°C divido la tensione X [mV] per questo valore ed ottengo la temperatura in gradi Celsius.

Con una precisione di lettura (P) della temperatura di:

P = Vref/S 5/10 = 0.5°C

Cambiando il riferimento (Vref) a 1.1V

Ottengo una risoluzione di:

R = 1.1/1024 = 0.00107V = 1.07mV

Ed una precisione di lettura (P) della temperatura di:

P = 1.1/10 = 0.107°C

Alla fine la nuova formula sarà :

TEMP = (analogRead(TEMPIN) / 1024.0) * 1100;
TEMPC = TEMP/10

Che semplificata per usare solo una variabile é:

TEMPC = (analogRead(TEMPIN) / 1024.0) * 110;

Questa dovrebbe essere la formula finale per il calcolo della temperatura con riferimento interno ad 1.1V

Ok, risolta la parte software (spero) ho iniziato il "restauro" :smiley: di questo progetto.
La prima versione era contenuta in una scatola di derivazione molto ingombrante ed antiestetica qunidi la seconda versione l'ho montata in una scatola di metallo e successivamente , ho riassemblato la scheda che supporta i componenti e cambiato anche il relè optando per un modello più compatto poichè adesso lo spazio è davvero contenuto.

Ho sostituito il buzzer con uno più potente ovvero il PKM22EPP-40, e qui nascono i problemi perchè per qualche motivo non suona più oppure lo fa ma molto debolmente. Sucessivamente a tutto ciò ho voluto inserire il tester per misurare la tensione che da in uscita il trasistor ed ho notato che:

  • senza resistenza il trasistor ha una perdita di 1 V rispetto alla tensione in ingresso;
  • con la resistenza da 27Kohm sulla base la tesione in uscita passa da 5V a 2V;
  • togliendo la resistenza da 1kohm non cambia molto la situazione;

Quindi è corretto il valore delle resistenze che ho messo sulla base dei transistor?
Conviene al limite collegare il buzzer direttamente all'arduino che da UNO è passato alla versione NANO?
Non riesco a capire poi perchè il trasistor del relè essendo collegato alla stessa maniera non crea una perdita di tensione cosi alta come il c1815 del buzzer (ho provato anche con altri c1815 ma succede sempre la stessa cosa)

Grazie per le risposte Saluti