Termoregolazione serra

Salve a tutti, sto realizzando un progetto per la "termoregolazione" di una piccola serra suddivisa in tre settori. Nello specifico sono presenti tre aperture sul soffitto comandate da motori complete di finecorsa, un anemometro e un termostato. Nel primo progetto avevo pensato di usare una sola board per far funzionare tutte e tre le finestre, però mi sono accorto che a meno che non avrei sviluppato un super codice, sarebbe stato complicato far muovere le finestre indipendentemente, quindi ho optato per l'utilizzo di tre board magari tipo arduino mini.

Il principio di funzionamento è abbastanza banale:
quando la temperatura scende sotto la soglia impostata il termostato chiude il contatto collegato in ingresso all'arduino e quindi si avvia la chiusura della finestra che deve essere eseguita a step by step (es. 2 secondi di chiusura e 10 di pausa) fino a che il termostato apre il contatto e si innesca lo stesso ciclo ma per l'apertura. Ho ovviato a prevedere una condizione di equilibrio in quanto per l'isteresi che si crea nell'ambiente credo che sarebbe molto difficile che si verificasse.

L'anemometro ha già una sua interfaccia programmabile e quindi viene usato sempre un'ingresso digitale sull'arduino, l'unica cosa da effettuare è la discretizzazione del tempo, cioè deve essere possibile impostare un tempo di intervento con cui far chiudere tutte le finestre (si chiude il contatto arduino rileva, aspetta il tempo impostato e se il vento è ancora presente chiude completamente tutte le finestre.)

Veniamo al dunque, ho già scritto un codice che a grandi linee funziona, dovrei solo riuscire a far funzionare meglio il tutto e a scrivere il pezzo di codice per l'anemometro.

#include <core_build_options.h>
#include <secTimer.h>


 byte termo = 0;          // Ingresso termostato;
 byte fc_open = 1;        // Ingresso finecorsa di apertura;
 byte fc_close = 2;       // Ingresso finecorsa di chiusura;
 byte w_open = 3;         // Relè di apertura;
 byte w_close = 4;        // Relè di chiusura;
 byte wind = 10;          // Ingresso anemometro;
 int work_time = 1;       // Tempo di movimento in secondi;
 int pause_time = 3;      // Tempo di pausa in secondi;
 int wind_delay = 5;      // Tempo attivazione presenza vento. 
 
 unsigned long prev_time_loop = 0;
 unsigned long current_time_loop;
 
 secTimer myTimer;
 
void setup()
{
  pinMode(termo, INPUT);
  pinMode(fc_open, INPUT);
  pinMode(fc_close, INPUT);
  pinMode(w_open, OUTPUT);
  pinMode(w_close, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(wind, INPUT);
  myTimer.startTimer();
}


void loop()
{
  current_time_loop = myTimer.readTimer();
  
  if(current_time_loop - prev_time_loop >= pause_time){
  
    prev_time_loop = current_time_loop;
    
  if(digitalRead(termo) == HIGH && digitalRead(wind) == LOW)
  {
    if(digitalRead(fc_open) == HIGH)
    {  
      digitalWrite(w_open, HIGH);
      delay(work_time * 1000);
      digitalWrite(w_open, LOW);

    }
    else
    {
      digitalWrite(w_open, LOW);
    }
  }
  
  if(digitalRead(termo) == LOW && digitalRead(wind) == LOW)
  {
    if(digitalRead(fc_close) == HIGH)
    { 
      digitalWrite(w_close, HIGH);
      delay(work_time * 1000);
      digitalWrite(w_close, LOW);      
    }
    else
    {
      digitalWrite(w_close, LOW);
    }
  }
  
  } 
}

Sicuramente ho evitato di usare la funzione delay per evitare di mettere in pausa il codice e quindi inibire qualche intervento dei finecorsa o dell'anemometro, e ho usato la libreria secTimer in modo da risolvere il problema dei 49 giorni di millis().

Le mie domande sono:

  • Ovviamente se sto useguendo un ciclo di chiusura/apertura e nello stesso tempo interviene il finecorsa l'uscita rimante alta fino allo scadere del tempo (non sarebbe un grosso problema perchè comunque i finecorsa intervengo anche a livello meccanico) però vorrei capire come sarebbe possibile eliminare questo difetto;

  • Un coniglio per gestire l'anemometro (ho pensato all'uso dell'interrupt);

  • Evitare l'uso del delay anche per il "work_time".

Grazie anticipatamente a chi vorrà aiutarmi.

Ciao.

Per iniziare, se possibile, i pin 0 e 1 utilizzali per ultimi, se proprio non puoi farne a meno.
Sono gli stessi che utilizza la seriale, quindi se vuoi fare del debug via USB, o più semplicemente caricare un'aggiornamento dello sketch, ciò che è collegato potrebbe interferire.

I pin 2 e 3 sono i pin per gli interrupt, quindi se vuoi collegare l'anemometro è meglio tenerli liberi.

Qualunque operazione tu stia facendo, quando l'anemometro rileva troppo vento, le finestre devono chiudersi completamente, giusto?
Quindi l'unico metodo è impostare un interrupt.
Bisogna vedere come è programmato l'anemometro, se da un segnale LOW quando è tutto tranquillo e passa ad HIGH superata la soglia impostata, credo che sia opportuno lavorare sull'interrupt in RISING, al contrario utilizzi il FALLING.

Brado:
Qualunque operazione tu stia facendo, quando l'anemometro rileva troppo vento, le finestre devono chiudersi completamente, giusto?

Si, l'anemometro deve interrompere qualsiasi operazione. Per quanto riguarda il contatto dell'anemometro possiamo lavorare tranquillamente in RISING.

Per effettuare la chiusura totale faccio un ciclo while in cui la condizione si che il finecorsa di chiusura sia sempre a riposo??
Es.

while(fc_close) {
digitalWrite(w_close, HIGH);
}

Dimenticavo, la cosa che mi fa diffidare dall'uso dell'interrupt è che in pratica la rilevazione del vento avviene in tre fasi:

  • la priva rilevazione;
  • aspettare un certo tempo per verificare l'effettiva presenza di vento;
  • chiudere le finestre.

Io credo che in questo modo già al primo rilevamento si attivi l'interrupt che mi fa partire la "temporizzazione", ma comunque abbandonerebbe le operazioni normali, e questa situazione provocherebbe comunque una minima interruzione delle funzioni. Per ovviare a questo problema io avevo pensato di costruire un timer con il vecchio 555 e poi usare un'interrupt, in modo che lascerei la discretizzazione del tempo al di fuori di tutto il codice. Però sinceramente mi scoccia avere un microcontrollore e dover usare molta elettronica "tradizionale".

Grazie per il tuo tempo comunque.

ciao
cosa intendi con

  • aspettare un certo tempo per verificare l'effettiva presenza di vento;

vuoi gestire anche le raffiche di vento?
l'interrupt ti aiuta a fare una misurazione precisa delle velocità del vento

stefa24:
ciao
cosa intendi convuoi gestire anche le raffiche di vento?
l'interrupt ti aiuta a fare una misurazione precisa delle velocità del vento

più o meno si, cerco di spiegarmi meglio. L'anemometro in questione ha già un controller proprietario in cui è possibile settore la velocità, quando viene superata questa soglia i controller chiude il contatto di un relè. L'unica cosa che vorrei poter fare è impostare un tempo di intervento, quindi quando da arduino ho rilevato la chiusura di questo contatto, aspetto un determinato tempo e se dopo essere trascorso questo tempo il contatto dovessere essere ancora chiuso vuol dire che c'è effettiva presenza di vento e quindi devo far chiudere le finestre.

spero di essere stato chiaro e non aver fatto confusione.

si adesso è più chiaro, passando alle finestre come sono motorizzate?

Sono dei motori asincroni trifase, hanno due teleruttori, quindi uno per ogni senso di rotazione (già interbloccati meccanicamente), quindi uso due uscite digitali dell'arduino (ovviamente con un transistor npn e un relè a 12v). Via software ancora non ho implementato l'interblocco per una doppia sicurezza (perchè ovviamente la chiusura contemporanea di tutte e due i teleruttori provocherebbe un corto circuito). Come ho già detto le finestre sono complete di finecorsa.

ciao
se usi gli shift register tipo 74hc595 puoi usare un unico arduino per comandare i teleruttori dei motori, per i fine corsa c'è un integrato, di cui non ricordo la sigla, che ti permette di leggere i fine corsa e collegare lo stato all'interrupt di arduino per interrompere il movimento del motore corrispondente

ciao,
perdonami per quale motivo dovrei usare uno shift register?
Io comando una finestra con ogni arduino, quindi utilizzo solo due uscite.
Per quanto riguarda i finecorsa, se la cosa migliore è utilizzare gli interrupts credo che non ho bisogno neanche di qualche integrato, posso collegarli direttamente e leggerli in "falling".

con lo shift register aumenti le uscite, ma forse con un arduino sei ha posto, per verificare lo stato dei fine corsa c'è un integrato che può leggere lo stato delle uscite e attivare l'interrupt per fermare il motore corrispondente

forse questo può andare bene MCP23S17 o qualcosa di simile

forse questo può andare bene MCP23S17 o qualcosa di simile

forse ti è sfuggito che io uso un arduino per ogni finestra, quindi su ogni scheda ho:

  • ingresso termostato;
  • ingresso finecorsa apertura;
  • ingresso finecorsa chiusura;
  • ingresso anemometro (interrupt);
  • uscita apertura;
  • uscita chiusura.

quindi non ho necessità di dover aumentare le uscite, perciò ti ho chiesto il motivo del 74hc595.

Per quanto riguarda l'integrato per i finecorsa adesso me lo studio un po' e poi vedo.

Grazie intanto

Credo di non avere bisogno neanche di quell'integrato.
Grazie della dritta però, può sempre tornare utile, non lo conoscevo!

forse ti è sfuggito che io uso un arduino per ogni finestra

no non mi era sfuggito ma avevo pensato che volessi risparmiare, appena ho una proposta te la posto

hai guardato gli esempi del blink senza delay, penso che utilizzando il millis() per fare tutti i conteggi di tempo che ti servono

odio gli if, io proverei a utilizzare lo switch...case rendono il programma più leggibile

stefa24:
no non mi era sfuggito ma avevo pensato che volessi risparmiare, appena ho una proposta te la posto

all'inizio avevo intenzione di usare un solo arduino, ma per far funzionare le finestre indipendentemente con un solo codice dovrei creare uno switch con tutte le combinazioni di controllo possibile. Ad esempio che mentre una finestra si sta aprendo l'altra dovrebbe chiudersi, per non parlare del fatto che oltre tutto dovei gestire anche i finecorsa. Per questo ho optato per tre board indipendenti.

La funzione millis() l'ho già usata (praticamente tramite la libreria secTimer).

Mentre per quanto riguarda gli if li ho preferiti ad uno switch perchè se non erro lo switch rallenta di più l'esecuzione del codice ance se considerato gli intervalli di tempo che ho andrebbe benissimo ugualmente.

come hai detto il delay() è bloccante, questo non lo rimuovi?

if(digitalRead(fc_close) == HIGH)
    { 
      digitalWrite(w_close, HIGH);
      delay(work_time * 1000);
      digitalWrite(w_close, LOW);      
    }