Progetto Serra Automatica

cicciozuc: gli spazi derivano dalle modifiche errate che tolgo e restano, e poi avere un codice con istruzioni una sotto l'altra mi sembra una gran confusione, di solito uso gli spazi tra fine e inizio di una nuova istruzione

no no cicciozuc non era riferito a te, nella mia risposta non avevo inserito nessuna riga vuota ma sia la preview che il post hanno generato un sacco di righe vuote poi con modify ho riaperto il post e quando l'ho salvato sono sparite :D ...misteri del forum ;)

Patrick_M: nella mia risposta non avevo inserito nessuna riga vuota ma sia la preview che il post hanno generato un sacco di righe vuote poi con modify ho riaperto il post e quando l'ho salvato sono sparite

Normale se usi il "Quick Edit" ... ma è solo un "effetto" del browser, NON del post che, se semplicemente ricarichi la pagina, appare correttamente. Stessa cosa (si vede correttamente) se usi l'editor completo ;)

Guglielmo

gpb01: Normale se usi il "Quick Edit" ... ma è solo un "effetto" del browser, NON del post che, se semplicemente ricarichi la pagina, appare correttamente. Stessa cosa (si vede correttamente) se usi l'editor completo ;)

Guglielmo

ok grazie mi mancava il "ricarichi la pagina"

Chi può darmi un consiglio se questa bozza di sketch è corretta??

Quello che cerco di fare sarebbe il seguente :

Appena i due igrometri superano la soglia di 775 avvia la Pompa per 10000 mills() dopo parte l’input che va al pin A0 della scheda motore ( basta un breve impulso per avviarlo 500 mills() ON/OFF ) e dopo 20000 mills si spegne la Pompa, quest’ultima istruzione ancora non riesco a darla…

Vi posto solo la parte interessata dello sketch

int lettura = A0 ; // Pin analogico a cui è collegato il sensore 1
int lettura1 = A1 ; // sensore 2
const int Pompa = 9 ; //Pin a cui è collegato i rele' per attivare al pompa
const int Motore = 10 ; // Motore
const int dht11 = 11 ; // ventola
int sensorValue = 1008; // Valore del sensore 1 immerso in acqua
int sensorValue1 = 1010; // Valore del sensore 2 immerso in acqua
unsigned long previousMillisPompa=0;
int intervalPompa = 10000;
int PompaState = HIGH; // Elettrovalvola
unsigned long previousMillisMotore=0;
int intervalMotore = 500;
int MotoreState = LOW; // segnale al pin A0 della scheda motore

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

//DHT11 Sensor:
#include "DHT.h"
#define DHTPIN 12     // Sensore collegato al PIN 12
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

//I2C LCD:
#include <Wire.h> // Libreria WIRE
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

// LCD I2C address
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); 


void setup()
{
  delay(1000);
  //I2C LCD
  Serial.begin(9600);
  lcd.begin(20,4);
  Serial.println("Serra Automatica");
 
   pinMode(Pompa,OUTPUT); // Uscita relè pompa
   digitalWrite(Pompa, HIGH); // Stato relè spento

    // PIN 10 al relè - IN2
   pinMode(dht11, OUTPUT); // Uscita relè sensore DHT11
   digitalWrite(dht11, HIGH);

   pinMode(Motore, OUTPUT);
   digitalWrite(Motore, LOW); // Motore

// Avvio sensore DHT11  
  dht.begin();
}

void loop(){
    
// Igrometro 1  
lettura = analogRead(A0);
sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 1 : ");
Serial.print(sensorValue);
Serial.println ("%"); //Stampa a schermo il valore  
    
// Igrometro 2    
lettura1 = analogRead(A1);
sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 2 : ");
Serial.print(sensorValue1);
Serial.println ("%"); //Stampa a schermo il valore    
   
 if ((lettura >= 775)  && (lettura1 >= 775)){
 if ((millis()- previousMillisPompa) >= intervalPompa) {
  if (PompaState == HIGH) {
      PompaState = LOW; //... attiva la pompa
      digitalWrite(Pompa, PompaState);
 previousMillisPompa = millis();
	}
 if ((millis()- previousMillisMotore) >= intervalMotore) {
  if (MotoreState == LOW) {
      MotoreState = HIGH; // avvia il segnale verso la scheda Motore
    digitalWrite(Motore, MotoreState);
    previousMillisMotore = millis();				
        } else  {
  PompaState = HIGH;//.... spegne la pompa
  MotoreState = LOW;// spegne contatto al pin A0 della scheda motore
  }

cicciozuc: Vi posto solo la parte interessata dello sketch

Per poterlo leggere senza (far) perdere tempo deve essere indentato correttamente.

Almeno usare la formattazione automatica CTRL+T o menu Strumenti (che dovrebbero usare tutti prima di postare), ho provato io ma da errore: "troppe parentesi graffe aperte".

Ora, siccome in mancanza di una corretta indentazione tocca mettersi a contare le parentesi per capire la logica, se queste mancano il codice risulta del tutto incomprensibile (e la sua stessa logica potrebbe essere sbagliata, cioè fare qualcosa di diverso da quanto atteso).


Detto ciò, prendiamo la descrizione voluta del funzionamento:

«Appena i due igrometri superano la soglia di 775 avvia la Pompa per 10000 mills() dopo parte l'input che va al pin A0 della scheda motore ( basta un breve impulso per avviarlo 500 mills() ON/OFF ) e dopo 20000 mills si spegne la Pompa»

...convertiamola in qualcosa di più schematico, l'importante è riuscire a determinare in quali situazioni ci possiamo trovare:

Situazione 0:  tutto fermo
   evento -> i due igro superano
   azione -> avvio pompa

Situazione 1: pompa in funzione, attesa 10 sec
   evento -> trascorsi 10 sec
   azione -> avvio impulso motore

Situazione 2: pompa e impulso attivi, attesa 500ms
   evento -> trascorsi 500ms
   azione -> ferma impulso motore

Situazione 3: pompa in funzione, attesa 9.5 sec
   evento -> trascorsi 9.5 sec
   azione -> ferma pompa

...e confrontiamo questo schema con quanto detto in questo post.

La traduzione di tutta la logica diventa semplice e lineare:

if(situazione == 0  
   &&  lettura >= 775  &&  lettura1 >= 775){       // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
}
else if(situazione==1  &&  millis()-tempo>=10000){ // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
}
else if(situazione==2  &&  millis()-tempo >= 500){ // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
}
else if(situazione==3  &&  millis()-tempo>=9500){  // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
}

NOTA: nelle condizioni per l'ordine di precedenza degli operatori del C, prima vengono eseguite le operazioni aritmetiche (-), poi quelle relazionali (==, >=), poi quelle logiche (&&)


Per il corretto funzionamento di un codice strutturato in questo modo è indispensabile che venga eseguito ciclicamente il più rapidamente possibile senza blocchi.

Ad esempio le continue scritture sulla seriale ad ogni ciclo di loop intasano il buffer di trasmissione (di 64 byte) bloccando il loop che comincia ad avanzare a "scatti irregolari" di qualche dieci millisecondi.

Meglio leggere i sensori ogni 5.. 10 secondi (magari alternati) e inviare solo in quel momento i dati seriali, il minimo indispensabile ogni volta.

@Claudio_FF grazie, la tua logica è esattamente quello che dovrei fare e hai descritto tutto in maniera chiara e comprensibile... Ma dimmi per ogni " azione " devo creare un void

void avviaPompa()
digitalWrite(Pompa, LOW);

lo stesso vale per ogni " situazione " ?? Riguardo alle letture dei sensori hai ragione bisogna leggerli ogni 5 o più secondi perché noto che nella seriale le letture sono troppo veloci e questo crea problemi nelle azioni eseguite nel loop.

cicciozuc: per ogni " azione " devo creare un void

A discrezione, come risulta più semplice da leggere e modificare. In genere si crea una funzione per non scrivere codice duplicato in più punti (così basta testare e modificare solo un punto), o per rendere più chiaro il programma suddividendolo in diverse brevi funzioni con compiti specifici. Ad esempio il loop potrebbe essere solo:

void loop(){
    leggiIgrometri();
    leggiFinecorsa();
    leggiDHT();
    logicaPompa();
    logicaMotore();
    logicaVentilatore();
    logicaTrasmissione();
}

Le varie funzioni possono essere strutturate come detto nel post precedente. Ad esempio la logica motore se non sbaglio deve fare solo questo:

Situazione 0:  Appena acceso non so nulla, fermo tutto
    azione -> ferma motore -> go stato 1
     
Situazione 1:  Attendo 3 sec
    evento -> trascorsi 3 sec
    azione -> se fcS chiuso go stato 2
              altrimenti motore indietro -> go stato 5

Situazione 2: attendo comando motore
    evento -> comando motore
    azione -> motore avanti -> go stato 3

Situazione 3: motore acceso avanti
    evento -> chiusura fcD
    azione -> motore fermo -> go stato 4
    
Situazione 4: fermo attesa 3 sec
    evento -> trascorsi 3 sec
    azione -> motore indietro -> go stato 5

Situazione 5: motore acceso indietro
    evento -> chiusura fcS
    azione -> motore fermo -> go stato 2

Quindi basta che la funzione logicaPompa imposti a 1 una variabile 'comandoMotore' per innescare il funzionamento adesso assegnato ad un Arduino a parte.

Stessa cosa per logicaTrasmissione, si setta una variabile (chiamata ad esempio transmitState) e la funzione ogni 200ms spara la stringa seriale via radio... e anche il nano se ne è andato...

Situazione 0:  attesa 200ms
    evento -> trascorsi 200ms
    azione -> se comando trasmissione trasmetti -> ricarica tempo

Qualcosa mi dice che il ragionamento si può estendere anche all'altro ArduinoUNO ;)

L'unica temporizzazione critica che potrebbe restare sarebbe il controllo dei finecorsa durante la lettura (bloccante) del DHT. Basta leggere il DHT raramente (una volta al minuto?) ed evitare la lettura se c'è il motore in movimento.

lo stesso vale per ogni " situazione " ??

Non ho capito la domanda. Vanno sicuramente individuate e gestite tutte le possibili situazioni (le ho chiamate situazioni per semplicità, ma è ovvio che si intendono in generale gli stati del sistema).

Claudio_FF: Non ho capito la domanda. Vanno sicuramente individuate e gestite tutte le possibili situazioni (le ho chiamate situazioni per semplicità, ma è ovvio che si intendono in generale gli stati del sistema).

Capisco il significato di quello che intendi come " situazione "

Claudio_FF: ``` Situazione 0:  tutto fermo   evento -> i due igro superano   azione -> avvio pompa

Situazione 1: pompa in funzione, attesa 10 sec   evento -> trascorsi 10 sec   azione -> avvio impulso motore

Situazione 2: pompa e impulso attivi, attesa 500ms   evento -> trascorsi 500ms   azione -> ferma impulso motore

Situazione 3: pompa in funzione, attesa 9.5 sec   evento -> trascorsi 9.5 sec   azione -> ferma pompa

ma non riesco a dare una istruzione a questo proposito, per me molte di queste funzioni sono nuove rispetto a quello che ho imparato da alcuni mesi a venire, tu cerchi di aiutarmi e questo lo ammiro ma ancora mi mancano certe basi per poter eseguire alla lettera i tuoi consigli.. Questo è una bozza di quello che ho imparato dai tui consigli :

const int Pompa = 9;
const int Motore = 10;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Pompa, LOW);
  digitalWrite(Motore, HIGH);
}

void setup() {
  pinMode(Pompa, OUTPUT);
  pinMode(Motore, OUTPUT);
}

void loop() {
  if (situazione == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
  }
  else if (situazione == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
  }
  else if (situazione == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
  }
  else if (situazione == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
  }

Va bene a parte queste cose:

  • Non hai definito e inizializzato la variabile 'situazione', all'avvio del programma deve valere zero in modo da partire dalla "situazione giusta"
  • È rimasto un refuso nella funzione 'disattivaImpulso' ( la digitalWrite(Pompa, LOW); )
  • Nel setup non ci sono le scritture per impostare i valori iniziali delle uscite.

Tutto quello che c'è nel loop potrebbe essere messo in una funzione 'logicaPompa' separata (solo per non avere un loop troppo lungo difficile da leggere).

Per il resto mi sembrava di aver usato codice contenente solo cose viste negli altri (a parte millis() che è l'oggetto delle modifiche attuali ed eventualmente l'uso di funzioni proprie come sottoprogrammi da chiamare). Eventualmente se specifichi meglio cosa non è chiaro.

Quello che cambia (molto) è la logica di esecuzione, che da strettamente sequenziale/bloccante/monoprocesso, è diventata iterativa/non bloccante/potenzialmente multiprocesso.

ancora non capisco come definire o inizializzare quello che tu chiami " situazione "

Nel setup non capisco quale scritture devo usare per impostare i valori delle uscite

Scusa la mia ignoranza

const int Pompa = 9;
const int Motore = 10;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;
int situazione = 0;
int situazione1 = 0;
int situazione2 = 0;
int situazione3 = 0;

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Motore, HIGH);
}

void setup() {
  pinMode(Pompa, OUTPUT);
  pinMode(Motore, OUTPUT);
  pinMode(lettura, INPUT);
  pinMode(lettura1, INPUT);
  avviaPompa();
  fermaPompa();
  attivaImpulso();
  disattivaImpulso();
}

void loop() {
  lettura = analogRead(A0);
  lettura1 = analogRead(A1);
  if (situazione == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
  }
  else if (situazione == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
  }
  else if (situazione == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
  }
  else if (situazione == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
  }
}

cicciozuc:
ancora non capisco come definire o inizializzare quello che tu chiami " situazione "

‘situazione’ è una normale variabile, come ‘tempo’ o ‘lettura’.
L’hai definita e inizializzata giusta. Deve contenere un valore tra 0 e 3, quindi qualsiasi tipo intero va bene, ma è sufficiente il tipo byte.

Invece le altre tre variabili ‘situazione1-2-3’ qui non servono a niente (a meno che non prevedi di usarle per altre cose).

Nel setup non capisco quale scritture devo usare per impostare i valori delle uscite

Dopo aver detto ai pin come devono funzionare (ingresso, uscita ecc), quelli di uscita vanno portati nel più breve tempo possibile al livello di riposo voluto alla partenza (HIGH o LOW). Bastano delle apposite digitalWrite, ma già che abbiamo le funzioni pronte che lo fanno basta usare quelle, cioè ‘fermaPompa’ e ‘disattivaImpulso’. Invece ‘avviaPompa’ e ‘attivaImpulso’ fanno l’esatto opposto, cioè attivano i relé.

Buone notizie, anche se lo sketch sarà ancora pieno di dimenticanze il sistema funzione come tu hai descritto, ho messo un delay all’inizio del loop perche avevo una lettura nel seriale troppo veloce, se ho fatto correttamente mi resta di inserire il dht11, l’lcd, e la trasmittente (quest’ultima non so proprio come inserirla insieme alle altre istruzioni…

const int Pompa = 9;
const int Motore = 10;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;
int situazione = 0;

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Motore, HIGH);
}

void setup() {
  Serial.begin(9600);

  Serial.println("Serra Automatica");
  pinMode(Pompa, OUTPUT);
  pinMode(Motore, OUTPUT);
  pinMode(lettura, INPUT);
  pinMode(lettura1, INPUT);
  avviaPompa();
  attivaImpulso();
  disattivaImpulso();
  fermaPompa();
}

void loop() {
  delay(5000);
  lettura = analogRead(A0);
  sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 1 : ");
Serial.print(sensorValue);
Serial.println ("%"); //Stampa a schermo il valore  

  lettura1 = analogRead(A1);
  sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 2 : ");
Serial.print(sensorValue1);
Serial.println ("%"); //Stampa a schermo il valore

  if (situazione == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
  }
  else if (situazione == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
  }
  else if (situazione == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
  }
  else if (situazione == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
  }
}

Dammi una tua opinione

Con quel delay(5000) hai vanificato TUTTO quanto detto e fatto finora :)

Lo scopo dell'usare millis è quello di eliminare completamente qualsiasi delay e permettere al loop di girare liberamente alla massima velocità migliaia o decine di migliaia di volte al secondo.

Qualsiasi "ritardo" va fatto esattamente come i ritardi del comando pompa, permanendo per tot millisecondi in una situazione/stato, e poi cambiando stato.

Quindi ripartiamo da capo :) :)

Inoltre hai lasciato l'attivazione dei relé nella setup... >:(


Aggiungo:

Tra il codice del post iniziale e quello del post #23 non capisco più se i relé si attivano con HIGH o LOW. Nelle definizioni iniziali bisogna sempre scriverlo, ad esempio:

const int Pompa = 9;   // rele` pompa  HIGH=spento
const int Motore = 10; // rele` motore HIGH=spento

Le variabili 'lettura' e 'lettura1' sono usate in modo strano, funzionano, ma prima servono a impostare i pin di ingresso (mentre per quelli di uscita si sono usate delle const int), e poi vengono usate per contenere i risultati delle digitalRead.

Lo scopo del dare dei nomi di comodo ai pin (come per le altre define) è per evitare di scrivere i nomi dei pin dentro il programma con il rischio di confusione, quindi è inutile usare delle variabili 'lettura' e 'lettura1' per dare dei nomi a dei pin (che non si intuisce a cosa servano), a maggior ragione se poi quelle variabili vengono usate per altri scopi e nelle digitalRead vengono usati di nuovo i nomi dei pin e non quelli di comodo:

const int SENSORE1 = A0;
const int SENSORE2 = A1;

oppure:

#define  SENSORE1  A0
#define  SENSORE2  A1

e quindi si usano i nomi di comodo:

lettura = analogRead(SENSORE1);
lettura1 = analogRead(SENSORE2);

si hai ragione infatti già ci stavo lavorando sopra, al momento queste sono le correzioni

const int Pompa = 9;
const int Motore = 10;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;
byte situazione = 0;

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Motore, HIGH);
}

void setup() {
  Serial.begin(9600);

  Serial.println("Serra Automatica");
  pinMode(Pompa, OUTPUT);
  fermaPompa();
  pinMode(Motore, OUTPUT);
  disattivaImpulso();
  pinMode(lettura, INPUT);
  pinMode(lettura1, INPUT);
  
  
  
}

void loop() {
  delay(5000);
  lettura = analogRead(A0);
  sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 1 : ");
Serial.print(sensorValue);
Serial.println ("%"); //Stampa a schermo il valore  

  lettura1 = analogRead(A1);
  sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
Serial.print("Umidità terra 2 : ");
Serial.print(sensorValue1);
Serial.println ("%"); //Stampa a schermo il valore

  if (situazione == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
  }
  else if (situazione == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
  }
  else if (situazione == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
  }
  else if (situazione == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
  }
}

Allora, come minimo per l’aiuto che mi stai dando ti meriti un punto Karma peccato che non posso fare di più…

Claudio_FF:
Tra il codice del post iniziale e quello del post #23 non capisco più se i relé si attivano con HIGH o LOW. Nelle definizioni iniziali bisogna sempre scriverlo, ad esempio:

const int Pompa = 9;   // rele` pompa  HIGH=spento

const int Motore = 10; // rele` motore HIGH=spento


per comandare i relè HIGH è = a spento, LOW acceso


> Le variabili 'lettura' e 'lettura1' sono usate in modo strano, funzionano, ma prima servono a impostare i pin di ingresso (mentre per quelli di uscita si sono usate delle const int), e poi vengono usate per contenere i risultati delle digitalRead.
> 
> Lo scopo del dare dei nomi di comodo ai pin (come per le altre define) è per evitare di scrivere i nomi dei pin dentro il programma con il rischio di confusione, quindi è inutile usare delle variabili 'lettura' e 'lettura1' per dare dei nomi a dei pin (che non si intuisce a cosa servano), a maggior ragione se poi quelle variabili vengono usate per altri scopi e nelle digitalRead vengono usati di nuovo i nomi dei pin e non quelli di comodo:
> 
> 
> ```
> const int SENSORE1 = A0;

const int SENSORE2 = A1;


oppure:


#define  SENSORE1  A0
#define  SENSORE2  A1


e quindi si usano i nomi di comodo:


lettura = analogRead(SENSORE1);
lettura1 = analogRead(SENSORE2);

ho fatto come dici tu inserendo

const int SENSORE1 = A0;

const int SENSORE2 = A1;


ma nel loop la variabile " lettura " non viene più riconosciuta, e vedi prima di scrivere qui ho fatto migliaia di prove. L'errore viene in queste due istruzioni 

lettura = analogRead(A0);
  sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
  Serial.print(“Umidità terra 1 : “);
  Serial.print(sensorValue);
  Serial.println (”%”); //Stampa a schermo il valore

lettura1 = analogRead(A1);
  sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
  Serial.print(“Umidità terra 2 : “);
  Serial.print(sensorValue1);
  Serial.println (”%”); //Stampa a schermo il valore


Ho inserito una pausa di 5000mills all'inizio del loop, ho creato una unsigned long pausa e ho inserito una void attesa(),funziona ma quando apro il monitor seriale le letture scorrono veloci per 5 secondi e poi si stabilizza leggendomi ogni 5sec, succede anche la stessa cosa nel momento che si attivano i relè cioè appena si attiva il relè scorre dopo 5 si stabilazza la lettura ed al prossimo relè acceso continua a scorrere... Dimmi se ho sbagliato qualcosa



const int Pompa = 9;
const int Motore = 10;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;
unsigned long pausa = 0;
byte situazione = 0;

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Motore, HIGH);
}
void attesa() {
  delay(5000);
}

void setup() {
  Serial.begin(9600);

Serial.println(“Serra Automatica”);
  pinMode(Pompa, OUTPUT);
  fermaPompa();
  pinMode(Motore, OUTPUT);
  disattivaImpulso();
  pinMode(lettura, INPUT);
  pinMode(lettura1, INPUT);

}

void loop() {
  if (millis() - tempo >= 5000) {
    pausa = millis();
    attesa();
  }
  lettura = analogRead(A0);
  sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
  Serial.print(“Umidità terra 1 : “);
  Serial.print(sensorValue);
  Serial.println (”%”); //Stampa a schermo il valore

lettura1 = analogRead(A1);
  sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
  Serial.print(“Umidità terra 2 : “);
  Serial.print(sensorValue1);
  Serial.println (”%”); //Stampa a schermo il valore

if (situazione == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    situazione = 1;                                // passa a situazione 1
  }
  else if (situazione == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                              // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 2;                                // passa a situazione 2
  }
  else if (situazione == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    situazione = 3;                                // passa a situazione 3
  }
  else if (situazione == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    situazione = 0;                                // passa a situazione 0
  }
}

Riordinato tutto,corretto gli errori che ho inserito nello sketch postato qui sopra e ho inserito le rimanenti istruzioni (dht11 e lcd) ho messo una pausa di 5sec nella lettura degli igrometri e una di 20sec nella lettura del sensore dht11…Mancano solo le istruzioni della trasmittente… Sulla seriale non si vedono scorrere più le letture…

#include <HygrometerSensor.h>
#include <Adafruit_Sensor.h>

const int Pompa = 9;
const int Motore = 10;
const int Ventola = 11;
int lettura = A0;
int lettura1 = A1;
int sensorValue = 1008;
int sensorValue1 = 1014;
unsigned long tempo = 0;
unsigned long pausa = 0;
unsigned long pausadht = 0;
byte verifica = 0;

//DHT11 Sensor:
#include "DHT.h"
#define DHTPIN 12     // Sensore collegato al PIN 12
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

//I2C LCD:
#include <Wire.h> // Libreria WIRE
#include <LiquidCrystal_I2C.h> // Libreria LCD I2C

// LCD I2C address
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void avviaPompa() {
  digitalWrite(Pompa, LOW);
}
void fermaPompa() {
  digitalWrite(Pompa, HIGH);
}
void attivaImpulso() {
  digitalWrite(Motore, LOW);
}
void disattivaImpulso() {
  digitalWrite(Motore, HIGH);
}

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);
  Serial.println("Serra Automatica");

  pinMode(Pompa, OUTPUT);
  fermaPompa();
  pinMode(Motore, OUTPUT);
  disattivaImpulso();
  pinMode(Ventola, OUTPUT);
  pinMode(lettura, INPUT);
  pinMode(lettura1, INPUT);
  // Avvio sensore DHT11
  dht.begin();
}

void loop() {
  if (millis() - pausa >= 5000) {
    lettura = analogRead(A0);
    sensorValue = map (lettura, 1008, 319, 0, 100); // converto il valore analogico in percentuale
    Serial.print("Umidità  terra 1 : ");
    Serial.print(sensorValue);
    Serial.println ("%"); //Stampa a schermo il valore

    lettura1 = analogRead(A1);
    sensorValue1 = map (lettura1, 1010, 215, 0, 100); // converto il valore analogico in percentuale
    Serial.print("Umidità  terra 2 : ");
    Serial.print(sensorValue1);
    Serial.println ("%"); //Stampa a schermo il valore
    pausa = millis();
  }
  if (verifica == 0
      &&  lettura >= 775  &&  lettura1 >= 775) {      // condizione di avvio
    tempo = millis();                              // salva tempo attuale
    avviaPompa();                                  // accende pompa
    verifica = 1;                                // passa a situazione 1
  }
  else if (verifica == 1  &&  millis() - tempo >= 10000) { // se passati 10s
    attivaImpulso();                               // attiva impulso motore
    tempo = millis();                              // salva tempo attuale
    verifica = 2;                                // passa a situazione 2
  }
  else if (verifica == 2  &&  millis() - tempo >= 500) { // se passati 500ms
    disattivaImpulso();                            // disattiva impulso motore
    tempo = millis();                              // salva tempo attuale
    verifica = 3;                                // passa a situazione 3
  }
  else if (verifica == 3  &&  millis() - tempo >= 9500) { // se passati 20s totali
    fermaPompa();                                  // spegne
    verifica = 0;                                // passa a situazione 0
  }

  // Lettura umidità e temperatura del sensore DHT11n
  int h = dht.readHumidity();
  int t = dht.readTemperature();

  // Misura la temperatura e se maggiore di ... gradi attiva relè per accendere la ventola
  if (t >= 25 ) {
    digitalWrite (Ventola, LOW); // Attiva Relè 2
  } else {
    digitalWrite (Ventola, HIGH); // Spegni Relè 2
  }
  if (millis() - pausadht >= 20000) {
    Serial.print("Temp: ");
    Serial.print(t);
    Serial.print("C, Umid: ");
    Serial.print(h);
    Serial.println("%");
    pausadht = millis();
  }

  // impostare cursore sulla prima riga:
  lcd.setCursor(0, 0);
  lcd.print("Temperatura: ");
  lcd.print(t);
  lcd.print("C");

  // imposta cursore sulla seconda riga:
  lcd.setCursor(0, 1);
  lcd.print("Umidita' Aria: ");
  lcd.print(h);
  lcd.print("%");

  // imposta il cursore sulla terza riga:
  lcd.setCursor(0, 2);
  lcd.print("Umid..Terra 1: ");
  lcd.print(sensorValue);
  lcd.print("%");

  // imposta il cursore sulla quarta riga:
  lcd.setCursor(0, 3);
  lcd.print("Umid..Terra 2: ");
  lcd.print(sensorValue1);
  lcd.print("%");
}

Ho creato la logicaMotore che mia ha suggerito @Claudio_FF ho preso lo sketch del motore che utilizzavo prima e ne ho fatto una logica come suggerito in questo post :

Claudio_FF: Le varie funzioni possono essere strutturate come detto nel post precedente. Ad esempio la logica motore se non sbaglio deve fare solo questo:

Situazione 0:  Appena acceso non so nulla, fermo tutto
    azione -> ferma motore -> go stato 1
     
Situazione 1:  Attendo 3 sec
    evento -> trascorsi 3 sec
    azione -> se fcS chiuso go stato 2
              altrimenti motore indietro -> go stato 5

Situazione 2: attendo comando motore     evento -> comando motore     azione -> motore avanti -> go stato 3

Situazione 3: motore acceso avanti     evento -> chiusura fcD     azione -> motore fermo -> go stato 4     Situazione 4: fermo attesa 3 sec     evento -> trascorsi 3 sec     azione -> motore indietro -> go stato 5

Situazione 5: motore acceso indietro     evento -> chiusura fcS     azione -> motore fermo -> go stato 2




Quindi basta che la funzione logicaPompa imposti a 1 una variabile 'comandoMotore' per innescare il funzionamento adesso assegnato ad un Arduino a parte.

A parte che ancora non sò come fare durante il motore in funzione evitare la lettura del sensore dht11

Claudio_FF: L'unica temporizzazione critica che potrebbe restare sarebbe il controllo dei finecorsa durante la lettura (bloccante) del DHT. Basta leggere il DHT raramente (una volta al minuto?) ed evitare la lettura se c'è il motore in movimento.

Vorrei una vostra opinione se questa logicaMotore è corretta perchè se sarebbe così cerco di inserirla in un'unica scheda insieme ai sensori che attualmente funziona bene... Lo sketch del motore che usavo con un'altro arduino è questo :

#define in1 10
#define in2 11
#define fcS 13    //Finecorsa Sinistro ( posizione di reset iniziale )
#define fcD 12    //Finecorsa Destro
#define pin_sensore A0
byte stato_fc =  1 ;

void setup() {
  digitalWrite(in1, HIGH) ;
  digitalWrite(in2, HIGH) ;
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(fcS, INPUT_PULLUP);
  pinMode(fcD, INPUT_PULLUP);
  pinMode(pin_sensore, INPUT_PULLUP);
  while (digitalRead(fcS) == HIGH)  { // legge finecorsa sinistro
    digitalWrite(in2, LOW) ; // avvia motore indietro fino alla posizione iniziale
  }
  digitalWrite(in2, HIGH) ; // motore_stop
}

void loop() {
  if (digitalRead(pin_sensore) == 0 ) { // attende lo start
    delay(100);
    stato_fc = 1 ;
    digitalWrite(in1, LOW) ; // motore_avanti
    while (stato_fc != 0 ) {
      if (digitalRead(fcD) == 0 )   {
        digitalWrite(in1, HIGH); // motore_stop
        stato_fc = 0 ;
      }
    }
    delay(3000);
    stato_fc = 1 ;
    digitalWrite(in2, LOW) ; // motore_indietro
    while (stato_fc != 0 ) {
      if (digitalRead(fcS) == 0 )   {
        digitalWrite(in2, HIGH); // motore_stop
        stato_fc = 0 ;
      }
    }
    delay(100);
  }

}// fine loop

Questo è quello che ho fatto :

const int MotoreAV = 22;
const int MotoreIN = 24;
const int fcS = 26;
const int fcD = 28;
unsigned long tempo = 0;
byte processo = 0;
byte stato_fc =  1 ;
byte comandoMotore = 0;

void fermaMotore() {
  pinMode(MotoreAV, HIGH);
  pinMode(MotoreIN, HIGH);
}
void motoreAvanti() {
  pinMode(MotoreAV, LOW);
}
void motoreIndietro() {
  pinMode(MotoreIN, LOW);
}

void setup() {
  fermaMotore();
  pinMode(MotoreAV, OUTPUT);
  pinMode(MotoreIN, OUTPUT);
  pinMode(fcS, INPUT_PULLUP);
  pinMode(fcD, INPUT_PULLUP);
}

void loop() {
  if (processo == 0 ) {
    fermaMotore();
    processo = 1;
  }
  else if (processo == 1  &&  millis() - tempo >= 3000) {
    tempo = millis();
    while (digitalRead(fcS) == HIGH) {
      processo = 2;
    }
  }
  else {
    motoreIndietro();
    processo = 5;
    } 
 if (processo == 2 && comandoMotore >= 1) {
  comandoMotore = 1;
  stato_fc = 1 ;
  motoreAvanti();
  processo = 5;
 }
 else if (processo == 3 ) {
  while (stato_fc != 0 ) {
    if (digitalRead(fcD) == 0 )   {
      fermaMotore();
      stato_fc = 0 ;
      processo = 4;
    }
   }
 }
  else if (processo == 4 && millis() - tempo >= 3000) {
    tempo = millis();
    stato_fc = 1 ;
    motoreIndietro();
    processo = 4;
  }
  else if (processo == 5 && motoreIndietro) {
    while (stato_fc != 0 ) {
      if (digitalRead(fcS) == 0 )   {
        fermaMotore();
        stato_fc = 0 ;
        processo = 2;
      }
    }
  }
}

Scusa avevo dimenticato di inserire lo skech

Partiamo dagli errori principali del post #35

  • La lettura del DHT non è temporizzata ma viene eseguita ad ogni ciclo di loop.
  • Le scritture su LCD portano anche loro via (molto) tempo, inutile scrivere “ad ogni giro” sempre gli stessi valori.

Errori principali del post #36

  • La struttura if/else if del processo motore è stata spezzata in due tronconi, quindi la logica non è quella voluta.
  • L’else finale del primo troncone viene eseguito sempre se le prime due condizioni risultano false, quindi non verranno mai eseguite porzioni di codice diverse dai casi 0 1 5
  • Anche se non ci ci fosse questo problema, ci sono dei while che bloccano tutto finché il motore è in movimento, quindi è vanificato il motivo per cui si è strutturato il programma in questo modo. Nel mio schema non ci sono while che aspettano qualcosa, solo casi in cui si controlla (ogni pochissimi millisecondi) se qualcosa avviene.
  • Attenzione ai momenti in cui si “ricarica” la variabile tempo, perché è da quel momento in poi che si comincia a misurare il trascorrere del tempo tramite millis()-tempo, mi pare ci siano errori anche in questo senso

Queste cose risultano subito evidenti facendo finta di essere Arduino ed eseguendo a mano il proprio codice, ottimo anche il consiglio di Standardoil qui, anche disegnare un flowchart inizialmente è di grande aiuto per capire se si sta sbagliando qualcosa (se non funziona seguendo il flowchart non funziona neanche dal vero).

Ora, seguendo lo pseudo schema, abbiamo sei casi (ad ogni “giro di loop” deve essere eseguito solo quello indicato dalla variabile di stato ‘processo’):

if(processo == 0){
}
else if(processo == 1){
}
else if(processo == 2){
}
else if(processo == 3){
}
else if(processo == 4){
}
else if(processo == 5){
}

Si tratta di una situazione semplice in quanto ogni caso deve essere sensibile al massimo ad un evento. Aggiungiamo gli eventi esattamente come indicati nello pseudo schema:

if(processo == 0){
}
else if(processo == 1  &&  millis() - tempo >= 3000){
}
else if(processo == 2  &&  comandoMotore == 1){
}
else if(processo == 3  &&  digitalRead(fcD) == FC_PRESS_LEVEL){
}
else if(processo == 4  &&  millis() - tempo >= 3000){
}
else if(processo == 5  &&  digitalRead(fcS) == FC_PRESS_LEVEL){
}

restano da aggiungere solo le azioni tra le parentesi dei casi :wink:
NOTA: come detto prima occhio ai momenti in cui reimposti la variabile tempo, perché è da quel momento che si inizia a contare il tempo.


A parte che ancora non sò come fare durante il motore in funzione evitare la lettura del sensore dht11

Si condiziona la lettura con una variabile flag, che può ad esempio chiamarsi motoreFermo.

if(motoreFermo == 1) ....allora si può procedere con la lettura

Dove si imposta questa variabile? Nel punto da cui si comanda il motore (oltre che all’inizio del programma per partire da una situazione certa, cosa da fare sempre con tutte le variabili di stato).


Visto che c’è un motore (per quanto alimentato a 12V) e dei fine corsa, aggiungerei anche i seguenti controlli:

  • Se due finecorsa chiusi → blocco per guasto finecorsa.
  • Se il finecorsa di partenza non si apre entro tot secondi → blocco per guasto finecorsa o motore bloccato.
  • Se il finecorsa di arrivo non si chiude entro tot secondi → blocco per guasto finecorsa o motore bloccato.

Grazie per i suggerimenti, ci ragiono con calma e cercherò di correggere i miei errori...Volevo dirti e penso che già l'avevi capito che questa logicaMotore appena sarà resa perfettamente funzionante andrà a sostituire il comando attivaImpulso() della logicaPompa...