Arduino Forum

International => Italiano => Generale => Topic started by: karnhack on May 23, 2019, 02:22 pm

Title: Irrigazione automatica
Post by: karnhack on May 23, 2019, 02:22 pm
Salve a tutti. E' da un po che copio codici e progetti online e mi scoraggia molto non riuscire a creare da me piccoli progetti come per esempio quest'ultimo che ho in mente, cioè un irrigazione automatica.
Mi rendo conto che ci sono un sacco di progetti online e vi assicuro che li ho visionati quasi tutti ed ho provato a capirci qualcosa ma ognuno di essi è specifico per un certo utilizzo e quando provo a modificarlo per le mie esigenze mi perdo nel codice e non ci capisco nulla. Vi prego dunque di aiutarmi a capire cosa non capisco... grazie.
Vi espongo il mio progetto dunque:

Materiali:
- Arduino uno (o anche mega)
- TinyRTC
- Relay a 4 stadi
- Elettrovalvola (non ancora comprata)
- Pompa (non ancora comprata)
- Sonda troppopieno
- Driver Pololu per movimentare una pompa peristaltica (forse l'utilizzo di un motore stepper è esagerato)

Tralasciando il fatto che un domani vorrei aggiungere funzioni di rilevamento umidità, temperatura e pioggia, ma per ora preferisco non complicarmi la vita...

In pratica, con questo irrigatore vorrei evitare di annaffiare le piante con l'acqua di rete per evitare che il cloro danneggi i microorganismi presenti nella terra. Quindi ho previsto un bidone che verrà riempito alla fine di ogni annaffiatura e che contiene la pompa che porterà l'acqua alle piante.

In poche parole la logica sarebbe questa: dalle ore hh:mm alle ore hh:mm attivo la pompa (relay1) e innaffio dal bidone. Subito dopo aver innaffiato si apre l'elettrovalvola e il bidone viene riempito nuovamente. Un rilevatore di troppopieno arresterà l'elettrovalvola a bidone riempito.

Per complicarmi la vita vorrei inserire una pompa peristaltica che  una volta al mese prima di innaffiare andrà ad aggiungere all'acqua un po concime liquido e lo mescolerà con un agitatore magnetico ricavato da una ventola. Tutto quì, semplice no? :D

Ora, il mio handicap:

Code: [Select]
/**********************************************************
 * Prova irrigazione
/**********************************************************/

#include <Wire.h>
#include <RTClib.h>
   
#define pinPompa 5
   
int Pompa[] = {13,29,13,30};
   
RTC_DS1307 RTC;
   
void setup() {
  Serial.begin(9600);
  Serial.println( "START" );
   
  Wire.begin();
  RTC.begin();
 
/**********************************************************/
// RTC.adjust(DateTime(2019, 05, 23, 12, 53, 00));
 
/* togliere il commento dalla riga sopra quando si vuole impostare l'ora
nel modulo rtc, inserire data e ora attuale, formato: (yyyy,mm,dd,hh,mm,ss).
Una volta impostata l'ora ricommentare la riga e ricaricare lo sketch.  */
/**********************************************************/
 
   
   pinMode( pinPompa,OUTPUT );

   
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
   
   digitalWrite( pinPompa,LOW );

 }
   
void loop() {
  if ( RTC.isrunning()) {
    DateTime now = RTC.now();
   
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
   
    int _hour   = now.hour();
    int _minute = now.minute();
 
    // Avvio Pompa
    if ( Pompa[0] <= _hour && _hour <= Pompa[2] && Pompa[1] <= _minute && _minute <= Pompa[3] ) {
      digitalWrite( pinPompa,HIGH );
    } else { digitalWrite( pinPompa,LOW ); }
    }
}


Ovviamente ho scopiazzato qua e la e tra l'altro non funziona neanche bene perchè funziona al contrario... in pratica dovrebbe accendersi alle 13,29 e spegnersi alle 13,30 mentre in questo lasso di tempo si spegne. Non a caso non sono riuscito a capire la variabile che si occupa dell'accensione:
Code: [Select]
  if ( Pompa[0] <= _hour && _hour <= Pompa[2] && Pompa[1] <= _minute && _minute <= Pompa[3]

Ne uscirò?
Title: Re: Irrigazione automatica
Post by: karnhack on May 23, 2019, 03:41 pm
Per forza di cose visto che non la capivo ho dovuto sostituire l'ultima variabile con questo
Code: [Select]
/**********************************************************
 * Prova irrigazione
/**********************************************************/

#include <Wire.h>
#include <RTClib.h>
   
#define pinPompa 5
   
   
RTC_DS1307 RTC;
   
void setup() {
  Serial.begin(9600);
  Serial.println( "START" );
   
  Wire.begin();
  RTC.begin();
 
/**********************************************************/
// RTC.adjust(DateTime(2019, 05, 23, 12, 53, 00));
 
/* togliere il commento dalla riga sopra quando si vuole impostare l'ora
nel modulo rtc, inserire data e ora attuale, formato: (yyyy,mm,dd,hh,mm,ss).
Una volta impostata l'ora ricommentare la riga e ricaricare lo sketch.  */
/**********************************************************/
   
   pinMode( pinPompa,OUTPUT );
   
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
   
   digitalWrite( pinPompa,HIGH );
   
 }
   
void loop() {
  if ( RTC.isrunning()) {
    DateTime now = RTC.now();
   
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();

    if( now.hour()==15 && now.minute()==36) {
      digitalWrite( pinPompa,LOW );
    } else { digitalWrite( pinPompa,HIGH ); }
    }
}


Ed ho dovuto invertire i pin HIGH con LOW altrimenti funzionava al contrario (probabilmente perchè il relay che uso è normalmente chiuso?). Ora mi rimane di capire se posso impostare una durata in secondi dall'avvio del relay
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 23, 2019, 05:29 pm
Salve a tutti. E' da un po che copio codici e progetti online e mi scoraggia molto non riuscire a creare da me piccoli progetti come per esempio quest'ultimo che ho in mente, cioè un irrigazione automatica.
Bisogna vedere se è una questione di impostazione logica/pianificazione o di poca conoscenza della semantica e della sintassi del linguaggio di programmazione, o del mettere insieme le due cose.

Quote
quando provo a modificarlo per le mie esigenze mi perdo nel codice e non ci capisco nulla.
Il codice è la trascrizione per una macchina di un'idea o modello mentale. Modificare il codice senza aver capito l'idea di chi lo ha pensato raramente porta a qualcosa di funzionante.

Quote
Vi prego dunque di aiutarmi a capire cosa non capisco
Ecco una sfida interessante...


Quote
In pratica, con questo irrigatore vorrei...
Qui hai descritto il dominio del problema in senso astratto, bene, è chiaro.

Quote
In poche parole la logica sarebbe questa: dalle ore hh:mm alle ore hh:mm attivo la pompa (relay1) e innaffio dal bidone. Subito dopo aver innaffiato si apre l'elettrovalvola e il bidone viene riempito nuovamente. Un rilevatore di troppopieno arresterà l'elettrovalvola a bidone riempito.
...vorrei inserire una pompa peristaltica che  una volta al mese prima di innaffiare andrà ad aggiungere all'acqua un po concime liquido e lo mescolerà con un agitatore magnetico ricavato da una ventola.
Qui hai descritto la logica in modo più schematico, benissimo, è già chiara, il modello mentale di cui parlavo parte da qui. Perché si tratta adesso di trovare un modo per "descriverla" usando gli strumenti messi a disposizione dalla macchina (ingressi/uscite hardware, istruzioni usabili ecc)... e non copiando o adattando cose scritte da altri che pensavano a logiche diverse (quello che hanno scritto gli altri va bene per vedere come hanno affrontato un singolo sottoproblema). In particolare è importante riuscire a ragionare per fasi di funzionamento, in tutto quello che hai descritto ne vedo almeno quattro o cinque ben precise... ci si può anche dare un nome, anzi, meglio farlo il prima possibile. Quando avrai identificato le fasi puoi chiederti: "in questa fase a quale evento devo prestare attenzione?", e successivamente: "quando avviene quell'evento quali azioni devo compiere? Ed eventualmente, se è il caso, in quale nuova fase di funzionamento mi dovrò trovare?". Prova a buttare giù uno schema su carta di fasi, eventi, azioni, prima in italiano, poi si vede come tradurlo in arduinese.


Quote
Ovviamente ho scopiazzato qua e la e tra l'altro non funziona neanche bene perchè funziona al contrario... in pratica dovrebbe accendersi alle 13,29 e spegnersi alle 13,30 mentre in questo lasso di tempo si spegne. Non a caso non sono riuscito a capire la variabile che si occupa dell'accensione:
Code: [Select]
 if ( Pompa[0] <= _hour && _hour <= Pompa[2] && Pompa[1] <= _minute && _minute <= Pompa[3]
Non funziona al contrario, porta alta l'uscita nell'intervallo previsto (purché non sia a cavallo tra due ore altrimenti può sbagliare), ma il modulo relè funziona a logica negativa, cioè il relé si attiva quando l'uscita di Arduino (ingresso del modulo) è bassa. Come hai già visto è bastato invertire HIGH con LOW.

Per il resto quale parte non è chiara nell'espressione logica che hai quotato?

Quote
Ne uscirò?
Mah  :)


Per quanto riguarda il controllo dei periodi orari, meglio lavorare con i minuti, in questo modo basta evitare un periodo a cavallo della mezzanotte:
Code: [Select]
int adesso = now.hour()*60 + now.minute();  // tempi da 0 a 1439 minuti
int inizio = Pompa[0]*60 + Pompa[1];
int fine   = Pompa[2]*60 + Pompa[3];

// Comando Pompa, no orari a cavallo della mezzanotte!!!
if ((adesso >= inizio) && (adesso < fine))
{
        digitalWrite(PINPOMPA, RELEACCESO);
}
else
{
        digitalWrite(PINPOMPA, RELESPENTO);
}
Title: Re: Irrigazione automatica
Post by: maubarzi on May 23, 2019, 06:22 pm
Ottimo il suggerimento di @Claudio_FF che dice di scriverlo prima in italiano.
Aggiungo un suggerimento ulteriore, pensalo per essere interpretato da uno che ti rema contro e che alla minima frase ambigua sceglierà la strada opposta a quella che pensi tu.
Quindi cerca di essere il più preciso possibile e il più chiaro possibile.
A costo di essere super elementare. Ad es. se dici di scrivere una cosa assicurati prima che ci siano il foglio e la penna e che la penna scriva, non so se hai capito cosa intendo...
Se riesci a fare questo, poi si tratterà solo di tradurre il tutto in C++ e puoi farlo un pezzo per volta chiedendo e imparando.
Pensa semplice e vedrai che ne uscirai.
Title: Re: Irrigazione automatica
Post by: karnhack on May 23, 2019, 07:09 pm
Ragazzi, innanzitutto grazie perché questo è proprio il tipo di aiuto che cercavo. Seguo con interesse i vostri consigli e stasera cercherò di fare uno schema. Per ora vi ringrazio per l'incoraggiamento.
Title: Re: Irrigazione automatica
Post by: karnhack on May 24, 2019, 12:39 pm
Ho provato a fare uno schema di funzionamento... mentre ragionavo sulla fase 4 mi è venuta in mente la firma di @Claudio_FF  "if non è un ciclo" infatti non so se è corretto come ho fatto io. Che ne dite può andare lo schema logico?

(https://i.postimg.cc/VLHQ5gNz/irrigazione.jpg)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 24, 2019, 05:40 pm
'if' non è un ciclo perché è una decisione/ramificazione. I cicli sono 'while' 'do while' e 'for'. È che spesso scrivono qualcosa come "non mi funziona il ciclo if" :) Ma naturalmente non vuol dire che non si possa usare un 'if' in modo ciclico per valutare ripetutamente delle condizioni, anzi, ma la ripetizione è appunto creata con un' istruzione di ciclo come 'while' o 'for' e non con l' 'if' in se stesso.

Detto ciò, direi che la scomposizione in fasi è grosso modo la stessa che avevo pensato. Hai disegnato una via di mezzo tra un diagramma di flusso e un diagramma funzionale sequenziale. Questo è come lo avevo pensato (avevo scomposto la concimazione in due fasi diverse):

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309683)

Nel tuo diagramma di differente c'è la fase 'input' che non mi è chiara, mentre io davo per scontato un funzionamento ciclico automatico, magari iniziante con la fase riempimento.

Le condizioni di passaggio da una fase all'altra (eventi) che ho scritto in rosso corrispondono ai rombi decisionali (if) del tuo schema. Vuol dire che l'intera sequenza logica si potrebbe gestire con soli sei 'if' principali, ma dipende dalla struttura/codifica che si vuole implementare.

1) Se il programma deve fare solo questo e non anche altre cose "in parallelo", allora può bastare dettagliare meglio ogni singolo blocco sotto forma di diagramma di flusso completo. Se il diagramma prevede solo blocchi di istruzioni sequenziali, ramificazioni 'if' e ripetizioni 'while'/'for' la traduzione in C è in pratica uno a uno, e restano solo i dettagli sintattici. Le varie durate possono essere realizzate con la funzione 'delay'.

2) Se invece si vuole scrivere un programma più "generale", che potrebbe nel frattempo fare anche altre cose, allora servono una struttura e ragionamento diversi, più affini al concetto di ciclo di scansione di un PLC (le operazioni vengono portate avanti in cicli/passaggi successivi e i ritardi sono realizzati con la permanenza in una fase per un certo numero di cicli fino al riconoscimento di un evento).

La prima via sembra più semplice da affrontare perché la sequenza delle istruzioni corrisponde esattamente al pensiero: faccio questo, poi questo e poi quest'altro. La seconda invece è un po' più tecnica e interessante, perché tante cose si riescono a fare solo con questa, ed è più facilmente modificabile per aggiungere o togliere funzionalità senza stravolgere o ripensare tutto.

Comunque direi che la logica c'è, adesso va dettagliata e tradotta in macchinese...
Title: Re: Irrigazione automatica
Post by: karnhack on May 24, 2019, 06:20 pm
Nel tuo diagramma di differente c'è la fase 'input' che non mi è chiara, mentre io davo per scontato un funzionamento ciclico automatico, magari iniziante con la fase riempimento.
E' che non sapevo da dove iniziare quindi ho pensato di partire dall'inserimento dei dati.
Pensando meglio al progetto mi sono accorto che sarebbe opportuno tenere conto dei mesi non solo per quanto riguarda la concimazione ma anche per avere diversi orari di innaffiatura in base al mese. Per esempio gestendo i "tempi" di innaffiatura mese per mese durante le 4 stagioni (climaticamente parlando), d'estate potrei annaffiare di sera dopo una giornata di sole cocente, mentre d'inverno potrei annaffiare la mattina per evitare gelate notturne.

Mi piace che sei partito dal riempimento, ci avevo pensato ma pensavo di complicarmi le cose, invece dal tuo schema sembra semplice e logico fare così.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 24, 2019, 06:41 pm
E' che non sapevo da dove iniziare quindi ho pensato di partire dall'inserimento dei dati.
Che però è una macrofunzione decisamente complessa. Alla fine dovrebbe popolare una matrice di dati mese->ora, che per semplicità si può anche già scrivere a mano nel programma, poi a complicare c'è sempre tempo.

Piuttosto vedrei utili altre funzionalità manuali... che so, scarico del bidone senza riempimento successivo, ciclo di annaffiatura (e/o concimazione) manuale, interruzione dell'operazione in corso... e altro a fantasia. Basta aggiungere fasi ed eventi (e pulsanti :D). Si può anche aggiungere una segnalazione di allarme se il rabbocco va in timeout (guasto al sensore di pieno o mancanza di acqua) ecc.

Come idea, se si indica la fase attualmente attiva con un valore contenuto in una variabile (ad esempio di nome... uhmm... 'fase'), nel loop ad ogni giro si può semplicemente chiamare una funzioncina diversa per ogni fase. Successivamente aggiungere o togliere fasi è immediato e non bisogna stravolgere nessun lungo codice.
Title: Re: Irrigazione automatica
Post by: karnhack on May 24, 2019, 07:46 pm
Che però è una macrofunzione decisamente complessa. Alla fine dovrebbe popolare una matrice di dati mese->ora, che per semplicità si può anche già scrivere a mano nel programma, poi a complicare c'è sempre tempo.
Sono assolutamente d'accordo a semplificare la cosa, anche perchè altrimenti rischierei di avere solo gli schemi in mano e senza una riga di codice. Anche per quanto riguarda pulsanti,  lcd ed altro per ora eviterei per lo stesso motivo che ho citato sopra.

Si può anche aggiungere una segnalazione di allarme se il rabbocco va in timeout (guasto al sensore di pieno o mancanza di acqua) ecc.
Potrei anche utilizzare una valvola galleggiante (meccanica, tipo quella del wc) sopra al sensore, così nel caso di guasto del sensore comunque non strasborda.

Ora però da dove comincio? mi riferisco all'arduinese...
Title: Re: Irrigazione automatica
Post by: Maurotec on May 24, 2019, 08:19 pm
Quote
Ora però da dove comincio? mi riferisco all'arduinese...
Hai iniziato bene quando ti sei concentrato a fare accendere o spegnere la pompa, penso che debba continuare da questi dettagli, uno preso in modo isolato.

Ora se sai già che la pompa si dovrà accendere e spegnere in base ad una serie di condizioni potresti pensare di creare una funzione dal nome gestisciPompa (waterPumpManage). All'interno della funzione farai i test con le if (<condizioni>), dove <condizioni> sono variabili globali.

Code: [Select]


void pumpManage() {

    if( now.hour()==15 && now.minute()==36) {

      digitalWrite( pinPompa,LOW );

    } else {

       digitalWrite( pinPompa,HIGH );
    }
}    


Così intanto riduci la quantità di righe di codice all'interno del loop e sai dove andare a guadare quando si presenta un problema con la pompa.

Ciao.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 24, 2019, 09:27 pm
O ecco, ero giù a prendere pizze... e poi prova te a spiegare a un'amica totalmente non tecnica che non guardi la TV perché passi il tempo libero su questo forum "inutile" :smiley-mr-green:

E torniamo a noio... si, l'idea è di scomporre in piccole funzioni (che alla fine possono corrispondere alle fasi).

Tra l'altro partendo dallo schema delle fasi viene particolarmente naturale/facile procedere top-down lasciando i dettagli alla fine (e l'intero programma può essere scritto quasi tutto in italiano).

Ora... "da dove comincio" dipende anche da cosa si sa.

Come detto prima ci sono vari modi per procedere. Quello focalizzato sulle fasi secondo me è il più generale e adattabile a ogni tipo di progetto, sia single task che multi task.

Ma occorrono delle basi sintattiche...

Io comincerei con lo scrivere le due funzioni obbligatorie vuote. Definirei una variabile globale 'fase' per indicare la fase di funzionamento attuale, e la inizializzerei al valore della prima fase che voglio attiva all'accensione (il valore associato ad ogni fase è naturalmente una convenzione, e se a questi valori diamo dei nomi, ad esempio con define, diventa tutto molto più chiaro).

Poi nel loop scriverei un selettore (if/else if o switch) che in base al valore di questa variabile richiami una funzione o un'altra, e quindi scriverei tutte queste funzioni vuote.

Così c'è già l'ossatura per tutta la logica.

Adesso dentro le funzioni vanno scritte le operazioni da svolgere e i test (controllo eventi) per vedere se è ora di cambiare fase. Per cambiare fase basta semplicemente scrivere nella variabile 'fase' il valore della nuova fase attiva e terminare la funzione tornando al selettore.

Tutto questo è arabo e torniamo indietro, o continuiamo?

Diamo per buono questo schema fasi?

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309777)
Title: Re: Irrigazione automatica
Post by: Maurotec on May 24, 2019, 10:31 pm
Quote
Adesso dentro le funzioni vanno scritte le operazioni da svolgere e i test (controllo eventi) per vedere se è ora di cambiare fase. Per cambiare fase basta semplicemente scrivere nella variabile 'fase' il valore della nuova fase attiva e terminare la funzione tornando al selettore.

Tutto questo è arabo e torniamo indietro, o continuiamo?
Tradotto in codice,

Code: [Select]

#define PH_START 0
#define PH_RUN  1
#define NEXT_PHASE( ph ) ph = ph+1
byte currentPhase = PH_START;

void helloPrint() {
    serial.println("Hello Word!");
    NEXT_PHASE(currentPhase);  // passa alla prossima fase
    // currentPhase = PH_RUN;      // fase scelta in modo arbitrario
}

void setup() {
    serial.begin(57600);
}

void loop() {
    switch (currentPhase) {
    case PH_START:
        helloPrint();
        break;
    case PH_RUN:
        // rimane in questa fase fino a che non modifichiamo la il contenuto della variabile
        // currentPhase.
        break;
    }   // end switch currentPhase
}   //end loop



Si tratta solo di un esempio per fare capire cosa intende @claudio con define.

Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 11:24 am
Innanzitutto ringrazio tutti e due per il tempo dedicato. Rispondendo a @ Claudio_FF non è arabo ma è Bergamasco (senza offesa ovviamente)  :smiley-sweat:
Da quello che capisco  dall'esempio di @Maurotec si definiscono prima le fasi, nell'esempio PH_START, PH_RUN e NEXT_PHASE e poi con il void loop si avvia il ciclo che passa sequenzialmente da una fase all'altra finchè non viene fermato dalla stringa break;.
Poi ci sono tante piccole cosette che mi sfuggono per esempio

Code: [Select]

#define PH_START 0
#define PH_RUN  1
#define NEXT_PHASE( ph ) ph = ph+1
byte currentPhase = PH_START; // byte (valore da 0 a 255) trasforma currentPhase in PH_START che ha valore 0 ????

void helloPrint() {
    serial.println("Hello Word!");
    NEXT_PHASE(currentPhase);  // qui mi perdo... NEXT_PHASE sarebbe PH_START che è 0 + 1 e dunque stiamo avviando la PH_RUN??
    // currentPhase = PH_RUN;      //invece qui contrariamente alla riga sopra non stiamo usando una logica variabile (passatemi il termine) ma stiamo semplicemente dicendo che la fase attuale è 1
}

void setup() {
    serial.begin(57600);
}

void loop() {
    switch (currentPhase) { // qui si inizia il flusso partendo da currentPhase che è 0
    case PH_START:  // mi pare di capire che qui si descrivono i vari flussi:
        helloPrint(); // flusso 1 stampa Hello Word
        break;        //  blocca il flusso
    case PH_RUN:  // questo è Bergamasco...
        // rimane in questa fase fino a che non modifichiamo la il contenuto della variabile
        // currentPhase.
        break;
    }   // end switch currentPhase
}   //end loop



Ho commentato le stringhe in modo da rendere visibile le lacune o meglio ancora le lagune nella quale sono immerso. Ne usciro?  :smiley-small:
Title: Re: Irrigazione automatica
Post by: maubarzi on May 25, 2019, 12:01 pm
Cerco di tradurtelo un pelino:

Code: [Select]

#define PH_START 0 // PH_START verrà sostituito con 0 prima della compilazione
#define PH_RUN  1 // PH_RUN verrà sostituito con 1 prima della compilazione
#define NEXT_PHASE( ph ) ph = ph+1 // NEXT_PHASE(ph) verrà sostituito con l'istruzione ph = ph + 1 prima della compilazione;
// Questo:
byte currentPhase = PH_START; // byte (valore da 0 a 255) trasforma currentPhase in PH_START che ha valore 0 ????
//diventa
byte currentPhase = 0; // Che è il valore di partenza all'avvio o al reset di Arduino.

void helloPrint() {
    serial.println("Hello Word!");
    // questo:
    NEXT_PHASE(currentPhase);  // qui mi perdo... NEXT_PHASE sarebbe PH_START che è 0 + 1 e dunque stiamo avviando la PH_RUN??
    // diventa;
    currentPhase = currentPhase + 1;
    // Questo invece è un esempio se si vuole impostare un valore fisso e diventerebbe: currentPhase = 1;
    // currentPhase = PH_RUN;      //invece qui contrariamente alla riga sopra non stiamo usando una logica variabile (passatemi il termine) ma stiamo semplicemente dicendo che la fase attuale è 1
}

void setup() {
    serial.begin(57600);
}

void loop() {
// Lo switch è un test che analizza il valore currentPhase ed esegue il case con lo stesso valore e tutti i successivi fino a quando non trova il break;
    switch (currentPhase) { // qui si inizia il flusso partendo da currentPhase che è 0
    case 0:
        helloPrint(); // flusso 1 stampa Hello Word e aumenta di 1 currentPhase, quindi lo fa diventare uguale a 1 e al prossimo giro di loop verrà eseguito il case 1
        break;        //  blocca il flusso, più precisamente fa uscire dallo switch saltando i case successivi. Se non lo metti esegue anche il case 1
    case 1:
        // rimane in questa fase fino a che non modifichiamo la il contenuto della variabile:
        // currentPhase. esatto!
        break;
    }   // end switch currentPhase
}   //end loop

Ho chiarito un po' di più o aumentato solo la confusione?
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 12:02 pm
Ok, allora ci sono innanzitutto delle grosse lagune con le basi del C :)

Se lo switch non è chiaro,  meglio prima vedere questo confronto con un if del tutto equivalente, è solo una struttura decisionale scritta in altro modo. Entrambi i codici eseguono solo 'istruzioni_a' o solo 'istruzioni_b' a seconda del valore della variabile 'x'. Se il valore della variabile non corrisponde a nessuno dei test precedenti vengono eseguite 'istruzioni_c'.

Code: [Select]
switch (x)
{
    case 20:
        ...istruzioni_a...
    break;
    
    case 30:
        ...istruzioni_b...
    break;

    default:
        ...istruzioni_c...
    break;
}

Code: [Select]
if (x == 20)
{
    ...istruzioni_a...
}
else if (x == 30)
{
    ...istruzioni_b...
}
else
{
    ...istruzioni_c...
}


Detto ciò con le define crei dei nomi di comodo/etichette, quindi scrivere un valore o il nome creato con la define è la stessa cosa, perché alla compilazione nei punti dove hai scritto i nomi questi verranno sostituiti con i valori. Quindi si:
Code: [Select]
byte currentPhase = PH_START;
è esattamente come scrivere:
Code: [Select]
byte currentPhase = 0;
Ma la prima forma è più chiara perché non serve andare in cerca di (o ricordarsi) cosa voglia dire lo zero. E questo è un consiglio sempre valido: evitare di cospargere il codice di numerini che non è chiaro cosa rappresentano, ad esempio la riga seguente è una scrittura su un pin di uscita, ma non abbiamo alcuna idea sulla funzione del pin, e neppure se vuol dire che quello che vi è collegato lo stiamo accendendo o spegnendo (ad esempio se è un relé in logica negativa lo stiamo spegnendo, ma senza commenti e schemi tocca tirare a indovinare):
Code: [Select]
digitalWrite(3, HIGH);
Invece la riga seguente è chiarissima, sappiamo che stiamo accendendo e anche cosa. È sufficiente scrivere all'inizio del codice le define coerenti con i collegamenti hardware e con i livelli HIGH o LOW presenti sui pin di ingresso o voluti sui pin di uscita:
Code: [Select]
digitalWrite(POMPA, LIVELLOACCESO);


NEXTPHASE è una macro, concetto più avanzato che personalmente non avrei introdotto in questo esempio, di fatto opera sempre con una sostituzione ed è come se scrivessi:
Code: [Select]
currentPhase = currentPhase + 1;


Code: [Select]
currentPhase = PH_RUN;   //invece qui contrariamente alla riga sopra
non stiamo usando una logica variabile (passatemi il termine) ma stiamo
semplicemente dicendo che la fase attuale è 1

Esatto. Tra l'altro i valori sono del tutto convenzionali, una fase può essere la 50 e quella successiva la 25, per cui l'incremento di 1 della fase ha senso solo nei casi specifici di una sequenza lineare, che so... le fasi notte alba giorno tramonto di un presepio... ma vedi ben che dopo il tramonto non basta incrementarla, va riportata al valore di notte.

E per concludere grazie, se non mi fossi fermato a rispondere a questo post adesso sarei in bicicletta sotto la pioggia :D :D :D
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 12:37 pm
@Claudio_FF devo dire che hai il dono della chiarezza, senza nulla togliere allo sforzo che gli altri stanno facendo per farmi capire.
Purtroppo le mie lacune sono aggravate dal fatto che non ho studiato la materia in giovane età e che non comprendo bene l'inglese, lingua con cui sono scritte la maggior parte delle guide che si trovano in giro.
Detto questo, vorrei provare a buttare giù un po di righe guardando gli esempi finora esposti, tralasciando per ora l'RTC e concentrandomi sulle funzioni delle cosiddette fasi... sempre che questo modo di procedere non mi incasini ancora di più le cose.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 02:43 pm
tralasciando per ora l'RTC e concentrandomi sulle funzioni delle cosiddette fasi... sempre che questo modo di procedere non mi incasini ancora di più le cose.
In un normale diagramma di flusso le fasi di funzionamento ci sarebbero comunque, solo che sarebbero "embeddate" e implicite nella la sequenza delle istruzioni invece di essere esplicite. Anche se non sembra in realtà con le fasi esplicite le cose si semplificano, ci si accorge di questo appena si vuole modificare qualcosa o aggiungere qualche funzionalità (soprattutto fare qualcosa in multitasking).

Per l'RTC... se scrivi una funzioncina 'leggi_rtc' fittizia che restituisce un orario fittizio a te comodo, il fatto di non usare l'RTC reale è ininfluente per il resto del programma. Poi basta modificare solo quella funzione per leggere l'RTC vero.

Ogni sforzo fatto per comprendere la struttura di questo progetto diventa strada spianata per qualsiasi altro progetto futuro.

Ora quello che c'è da dettagliare meglio è a cosa prestare attenzione in ogni fase, e quali azioni svolgere in quel caso.

Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 02:47 pm
Anche se non ho fatto chissà che sono già contento di non aver scopiazzato qua e la. Intanto allego i progressi e rinnovo la mia gratitudine per gli aiuti

Code: [Select]
#include <Wire.h>
#include <RTClib.h>

#define POMPA 5 // definisce il pin della pompa
#define ELETTROVALVOLA 6
#define TROPPOPIENO A0 // ??? devo ancora capire come funziona il sensore del troppopieno (contatto aperto-chiuso) ???

int ACCESO = LOW; // sostituisce la logica del pin (LOW/HIGH) con il termine ACCESO/SPENTO per una migliore comprensione della fuzione
int SPENTO = HIGH;

RTC_DS1307 RTC;

void setup() {
  pinMode(POMPA, OUTPUT); // imposta il pin (POMPA) come output
  pinMode(ELETTROVALVOLA, OUTPUT);
  pinMode(TROPPOPIENO, INPUT);

  digitalWrite(POMPA, SPENTO); // all'avvio di arduino spegne la pompa
  digitalWrite(ELETTROVALVOLA, SPENTO);
 
/***************************RTC e WIRE**************************/
  Serial.begin(9600);
  Serial.println( "START" );
   
  Wire.begin();
  RTC.begin();

//  RTC.adjust(DateTime(2019, 05, 23, 12, 53, 00)); // decommentare per regolare ora e data (yyyy,mm,dd,hh,mm,ss)

  if (! RTC.isrunning()) {
    Serial.println("RTC non è attivo!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
}






void loop() {
  if ( RTC.isrunning()) {
    DateTime now = RTC.now();
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
    }
}
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 04:07 pm
Per quanto riguarda il controllo dei periodi orari, meglio lavorare con i minuti, in questo modo basta evitare un periodo a cavallo della mezzanotte:
Code: [Select]
int adesso = now.hour()*60 + now.minute();  // tempi da 0 a 1439 minuti
int inizio = Pompa[0]*60 + Pompa[1];
int fine   = Pompa[2]*60 + Pompa[3];

Mi dite gentilmente a che servono i numeri nelle parentesi quadre?

Title: Re: Irrigazione automatica
Post by: Maurotec on May 25, 2019, 04:16 pm
Quote
Mi dite gentilmente a che servono i numeri nelle parentesi quadre?
Siamo messi male. :)
Si chiamano array (o vettori) link (https://ennebi.solira.org/c-lang/pag22.html)

Code: [Select]

int ACCESO = LOW;

Anche qui serve studiare i tipi di variabile.
più corretto è,
Code: [Select]

const byte acceso = LOW;

Mentre per le macro (preprocessore C) corretto è,
Code: [Select]

#define ACCESO LOW



Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 04:21 pm
Siamo messi male. :)
Quoto in pieno! grazie per il link!
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 05:14 pm
Ecco ora mi sono arenato... se switch è l'ora attuale, nel mio caso ADESSO, però ADESSO viene ricavato da
Code: [Select]
now.hour()*60 + now.minute();  // tempi da 0 a 1439 minuti
come faccio a prelevare anche il mese senza superare i 1439 minuti? c'è un operatore che non sia + e che mi permette di farlo? Allego il codice
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 05:35 pm
Per gli array la sintesi è questa:

-Una variabile è una scatoletta che può contenere un valore.
-Un array è una fila di scatolette ciascuna identificata da un indice (che parte da 0 per la prima)

Ho scritto Pompa[n] perché nel codice del primo post gli orari di inizio e fine sono contenuti in un array di quattro posizioni:
Code: [Select]
int Pompa[] = {13, 29, 13, 30};
e per ottenere i valori bisogna indicare non solo la variabile array, ma anche quale delle sue scatolette:

       .----.----.----.----.
Pompa  | 13 | 29 | 13 | 30 |
       '----'----'----'----'
Indici   0    1    2    3

Per il resto il fatto che tu stia in qualche modo parlando di switch legato alla variabile 'adesso' e di sommare il mese mi fa temere qualcosa di brutto brutto, ma magari non è così :) Prima di pensare a come codificarla, non mi è chiaro come vorresti usare l'informazione del mese, perché il mese ce l'hai già in chiaro con now.month()
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 05:48 pm
Te l'ho già detto che hai il dono della chiarezza?  :)

Ho capito anche io dopo aver fatto la domanda che stavo facendo una cavolata... poi aggiungendo il MESE col metodo a scatoletta (vettore, array) mi sono reso conto che posso verificare quella condizione in un altro modo.

Code: [Select]
int MESE[] = {3,5,7,9,11};  // (GEN 1, FEB 2, MAR 3, APR 4, MAG 5, GIU 6, LUG 7, AGO 8, SET 9, OTT 10, NOV 11, DIC 12)

Però ora mi sono arenato di nuovo con sto benedetto switch, in quanto arduino mi restituisce un errore incomprensibile tipo
Code: [Select]
Prova:102:1: error: stray '\302' in program.

In pratica sto provando a fare così ma mi da errore:

Code: [Select]
switch (ADESSO)
    {
      case RIEMPIMENTO:
      // istruzioni a
      break;

      case RIPOSO:
      // istruzioni a
      break;

      case CONCIMAZIONE:
      // istruzioni a
      break;

      default:
      if ((ADESSO >= INIZIO) && (ADESSO < FINE))
      {
       digitalWrite(PinPOMPA, ACCESO);
      }
      else
      {
       digitalWrite(PinPOMPA, SPENTO);
      }
      break;
    }


Allego il codice nel caso vogliate dare un occhiata al casino che sto facendo  :D
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 05:59 pm
No scusa, nessun errore, avevo copiato ed incollato qualche carattere invisibile dal tuo esempio! FUNZIONA!!!  :D  :D
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 06:05 pm
No no, l'errore c'è, ed è quello che temevo :)

Lo switch deve funzionare in base al valore della variabile di fase, non del valore orario... Di fatto con lo switch hai scritto l'equivalente esatto di questo if... un sacco di condizioni che non risulteranno mai vere, o meglio, risulteranno vere solo a mezzanotte, a mezzanotte e un minuto, a mezzanotte e due minuti ecc, mentre per tutto il resto del tempo viene eseguito solo l'else:

Code: [Select]
if (ADESSO == RIEMPIMENTO)
{
    // istruzioni a
}
else if (ADESSO == RIPOSO)
{
    // istruzioni a
}
else if (ADESSO == CONCIMAZIONE)
{
    // istruzioni a
}
else
{
    if ((ADESSO >= INIZIO) && (ADESSO < FINE))
    {
        digitalWrite(PinPOMPA, ACCESO);
    }
    else
    {
        digitalWrite(PinPOMPA, SPENTO);
    }
}

Di solito nella parte default dello switch non c'è bisogno di scrivere nulla. Avviene tutto nei case (o nelle funzioni richiamate dai case). Ed è all'interno dei case che si controlla il valore dell'orario decidendo cosa fare.

Code: [Select]

      case RIPOSO:  // attendo l'orario, e in quel momento passo a fase irrigazione
          if (in_orario())
          {
              accendi_pompa();
              fase = IRRIGAZIONE;
          }
      break;

      case IRRIGAZIONE:  // attendo la fine orario, e in quel momento passo a riempimento
          if (!in_orario())
          {
              spegni_pompa();
              apri_valvola();
              fase = RIEMPIMENTO;
          }
      break;

Se scrivi tante piccole funzioncine (come accendi_pompa, in_orario ecc) hai l'intera logica scritta in italiano.

In maiuscolo andrebbero scritte solo le costanti, in modo da distinguerle dalle variabili minuscole.
Title: Re: Irrigazione automatica
Post by: Maurotec on May 25, 2019, 06:31 pm
Quanta fretta ma dove corri.. https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwju47j4ibfiAhVQyKQKHRtABHUQyCkwAHoECAoQBQ&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DYoBuv7HR-Fw&usg=AOvVaw34Sz9Sb-XmZdDvDzkl9Xsd (https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwju47j4ibfiAhVQyKQKHRtABHUQyCkwAHoECAoQBQ&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DYoBuv7HR-Fw&usg=AOvVaw34Sz9Sb-XmZdDvDzkl9Xsd)

Freno a mano tirato su.
Esistono delle convenzioni che se rispettate permettono al programmatore di ricavare informazioni in un solo colpo di occhio. Ad esempio se per convenzione scriviamo le macro tutte in maiuscolo e le variabili in minuscolo abbiamo il seguente vantaggio, cioè osservando una piccola porzione di codice di un programma che conta 10000 righe sappiamo che PH_START è un macro, mentre phStatus è una variabile. Ovviamente possiamo modificare il valore di una variabile ma non di una macro.

Stessa potenza c'è nell'uso del tipo di variabili, come dire se uso il tipo int vuole dire che mi serve contenga anche valori negativi. Quando so a priori che la variabile non conterrà mai valori negativi il tipo corretto è byte, uint8_t, uint16_t, uint32_t, boolean ecc, in sostanza tutti tipi senza segno.

Quote
No no, l'errore c'è, ed è quello che temevo :)
Che vuoi fare l'ebbrezza di avere scritto qualcosa che funziona senza copiare da alla testa. :)

PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?

Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 06:46 pm
Che vuoi fare l'ebbrezza di avere scritto qualcosa che funziona senza copiare da alla testa. :)
E' stato breve ma intenso, il momento di gloria intendo...
Già non funziona più, appena ho tirato fuori il codice da default:

Non capisco una cosa però, a parte quello che mi avete detto. Lo switch richiede che il case sia dichiarato... si ma in che modo? facendo delle prove avevo messo dei numeri a caso e funzionava lo stesso:
Code: [Select]
#define RIEMPIMENTO 0 // perchè 0?
#define RIPOSO 1 // perchè 1?
#define CONCIMAZIONE 2 // perchè 2?
#define IRRIGAZIONE 3
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 06:58 pm
facendo delle prove avevo messo dei numeri a caso e funzionava lo stesso:
Dal post #11: «il valore associato ad ogni fase è naturalmente una convenzione»
Dal post #15: «Tra l'altro i valori sono del tutto convenzionali»

Al punto che dandogli dei nomi con 'define' o con 'const byte' ci possiamo dimenticare dei valori... purché siano tutti diversi l'uno dall'altro.
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 07:03 pm
Dal post #11: «il valore associato ad ogni fase è naturalmente una convenzione»
Dal post #15: «Tra l'altro i valori sono del tutto convenzionali»
Mi fai paura, ma sei umano o un BOT?  :o
Che memoria! :smiley-surprise:
Title: Re: Irrigazione automatica
Post by: karnhack on May 25, 2019, 07:33 pm
Lo switch deve funzionare in base al valore della variabile di fase, non del valore orario... Di fatto con lo switch hai scritto l'equivalente esatto di questo if... un sacco di condizioni che non risulteranno mai vere, o meglio, risulteranno vere solo a mezzanotte, a mezzanotte e un minuto, a mezzanotte e due minuti ecc, mentre per tutto il resto del tempo viene eseguito solo l'else
[/code]
Ok quindi se ho capito bene la tua indicazione il problema sta in
Code: [Select]
switch (ADESSO)
Quindi dovrei lavorare a cascata? cioè partire dalla fase1, verificarla e poi passare alla fase 2 ecc.

Dunque in poche parole dovrei partire dalla fase RIEMPIMENTO e interrogare la valvola se aperta o chiusa? è aperta, bene allora riempi e passa alla fase 2 RIPOSO.
Nella fase RIPOSO vado a interrogare l'RTC in attesa che la data o l'ora coincidano oppure solo l'orario per le operazioni quotidiane, etc. etc. fino alle fasi successive.

Ma quindi la X di "switch (x)" non deve essere un fattore comune a tutte le fasi? è questo che non capisco...
La X può essere legata solo alla lettura del sensore troppopieno della fase RIEMPIMENTO? Non so se mi sono spiegato.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 25, 2019, 08:13 pm
Quindi dovrei lavorare a cascata? cioè partire dalla fase1, verificarla e poi passare alla fase 2 ecc.
Si, in ogni situazione esegui solo un pezzo del programma, quello relativo alla situazione corrente identificata dalla variabile fase. Quando ci sono le condizioni, ad esempio quando nella fase riempimento trovi che il sensore pieno si è chiuso, modifichi le uscite e passi alla situazione/fase seguente (seguente in senso logico, non necessariamente di numero). Al prossimo giro del programma verrà eseguito il nuovo pezzo di codice relativo alla nuova fase e così via.

Quote
Nella fase RIPOSO vado a interrogare l'RTC in attesa che la data o l'ora coincidano oppure solo l'orario per le operazioni quotidiane, etc. etc. fino alle fasi successive.
Esatto.

La variabile 'x' degli esempi del post #15 contiene il numero della fase corrente, e serve per eseguire solo il pezzo di codice di quella fase. Che poi lo fai con switch o con if poco importa.
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 01:12 am
ci sto sbattendo la testa da un po ma non ne esco, forse ho dichiarato male le fasi
Code: [Select]
byte faseAttuale=RIEMPIMENTO;
int fase=0;


fatto sta che non riesco a passare da una fase all'altra. Per il momento stavo provando a passare dal RIEMPIMENTO ad IRRIGAZIONE giusto per capire, ma non va

Code: [Select]
switch (faseAttuale)
    {
      case RIEMPIMENTO:
      if(analogRead(pinTroppopieno) >= 1000) {
        digitalWrite(pinElettrovalvola,ACCESO);
      }
      else
      {
        digitalWrite(pinElettrovalvola,SPENTO);
        fase = IRRIGAZIONE;
      }
      delay(1000);
      //fase = IRRIGAZIONE; // ho provato anche qui
      break;

      case RIPOSO:  
       // istruzioni a  
      break;

      case CONCIMAZIONE:
      // istruzioni a
      break;

      case IRRIGAZIONE:
       digitalWrite(pinPompa,ACCESO);
      break;
      
      default:
      break;
    }
    }
}
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 26, 2019, 01:20 am
Hai dichiarato due diverse variabili.
Lo switch (cioè quale caso viene eseguito) è controllato da 'faseAttuale' che rimane invariata, mentre tu modifichi 'fase' che non viene usata da nessuna parte.

La logica all'interno dei case può essere più semplice:
(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309883)

Per aggiungere la concimazione basta aggiungere un else if nella fase riposo, che avvia peristalsi e agitatore, e passa alla concimazione.
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 11:08 am
Pero non mi spiego come mai una cosa che funzionava ieri non funziona oggi...
La lettura di A0 ieri oscillava tra 1023 e 1010 senza nessun voltaggio, oggi invece oscilla da tra i 310 e i 270 sempre a vuoto. Se invece gli do 5V simulando il contatto dell'acqua oscilla tra 0 e 1023. Ho bruciato qualcosa? ho provato anche un altro pin e fa uguale

Code: [Select]
case RIEMPIMENTO:
        if (analogRead(pinTroppopieno) >= 1000) {
          digitalWrite(pinElettrovalvola, ACCESO);
         
        }
        else
        {
          digitalWrite(pinElettrovalvola, SPENTO);
         
        }
        delay(500);
        fase = RIPOSO;
        break;


Oltre al mistero citato sopra, ho un altro problema, cioè appena viene fatta la lettura di A0 avviene la condizione pinTroppopieno >= 1000) e passa immediatamente all'altra fase senza attendere la condizione inversa, quindi in poche parole l'elettrovalvola rimane accesa. Ho provato ad inserire un delay senza successo, ho provato anche millis ma va in errore.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 26, 2019, 11:32 am
La lettura di A0 ieri oscillava tra 1023 e 1010 senza nessun voltaggio, oggi invece oscilla da tra i 310 e i 270 sempre a vuoto.
Nessun pin di ingresso deve restare scollegato, altrimenti leggendolo ottieni valori casuali. Il perché del ieri così e oggi pomì sta nel fatto che quell'ingresso ieri aveva accumulato più cariche elettrostatiche, e non essendo collegato a niente non potevano essere "smaltite" da nessuna parte.

Quote
appena viene fatta la lettura di A0 avviene la condizione pinTroppopieno >= 1000) e passa immediatamente all'altra fase senza attendere la condizione inversa
Certo, perché è esattamente quello che gli hai detto di fare, infatti la modifica alla variabile fase avviene al di fuori di ogni condizione, quindi sempre e subito alla prima esecuzione di quel case, invece dovrebbe avvenire solo nella condizione voluta.

Quote
Ho provato ad inserire un delay senza successo, ho provato anche millis ma va in errore.
I tentativi alla cieca non portano da nessuna parte. Se vuoi che un programma faccia quello che vuoi  bisogna imparare a pensare con la stessa logica di esecuzione di Arduino... fai finta di essere Arduino ed esegui tu il programma che hai scritto. Se tra la tua esecuzione mentale simulata e quella di Arduino qualcosa non coincide, vuol dire che c'è qualcosa di non compreso ed è inutile andare avanti se prima non ci si chiarisce le idee. Purtroppo non c'è altra strada (a parte farsi scrivere i programmi dagli altri).
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 11:47 am
I tentativi alla cieca non portano da nessuna parte. Se vuoi che un programma faccia quello che vuoi  bisogna imparare a pensare con la stessa logica di esecuzione di Arduino... fai finta di essere Arduino ed esegui tu il programma che hai scritto. Se tra la tua esecuzione mentale simulata e quella di Arduino qualcosa non coincide, vuol dire che c'è qualcosa di non compreso ed è inutile andare avanti se prima non ci si chiarisce le idee. Purtroppo non c'è altra strada (a parte farsi scrivere i programmi dagli altri).
Credo di sapere come fare ma è l'ignoranza del linguaggio C che mi rende difficile l'attuazione.

Se potessi parlargli gli direi leggi il pin A0 che sarà < X , apri la valvola, attendi che diventi >X e poi passa la fase  Y
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 26, 2019, 12:16 pm
Se potessi parlargli gli direi leggi il pin A0 che sarà < X , apri la valvola, attendi che diventi >X e poi passa la fase  Y
Basta formalizzarlo con la logica disponibile (se, finché):

finchè pin A0 < X:

   apri valvola

chiudi valvola
fase Y

La traduzione è uno a uno (mi rifaccio al codice postato prima perché non so cosa significano i valori letti da A0... una funzioncina chiamata 'troppo_pieno' che ritorna vero o falso sarebbe molto più chiara sempre per il fatto che i numeri sparsi qua e la non è immediatamente evidente cosa rappresentano):
Code: [Select]
while (analogRead(pinTroppopieno) >= 1000)
{
    digitalWrite(pinElettrovalvola, ACCESO);
}
digitalWrite(pinElettrovalvola, SPENTO);
fase = RIPOSO;

Certo questo snatura un po' lo schema del post #34, perché con la struttura a fasi le attese sono già contemplate nel fatto che una fase rimane attiva finché non avviene un evento che la fa cambiare:

Se fase RIEMPIMENTO:
    Se troppopieno:
        chiudi valvola
        fase RIPOSO


Che si traduce sempre uno a uno:
Code: [Select]
case RIEMPIMENTO:
    if (analogRead(pinTroppopieno) < 1000)
    {
        digitalWrite(pinElettrovalvola, SPENTO);
        fase = RIPOSO;
    }
break;


La funzioncina per il troppo pieno può essere semplicemente:
Code: [Select]
bool troppo_pieno()
{
    if (.....) { return true; }
    return false;
}

E quindi le condizioni dei due esempi sopra si semplificano e diventano chiare:
Code: [Select]
while (!troppo_pieno()) // finche' non e` troppo pieno

if (troppo_pieno())     // se e` troppo pieno
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 02:30 pm
Al momento ho risolto così e sembra funzionare

Code: [Select]
switch (fase)
    {
      case RIEMPIMENTO:
      if (analogRead(pinTroppopieno) >= 50) {  //soglia di prova
          digitalWrite(pinElettrovalvola, ACCESO);
          delay(1000);
        }
        while (analogRead(pinTroppopieno) <= 5) //soglia di prova
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }
        fase = RIPOSO;
        break;


tralasciano per ora le soglie del voltaggio in ingresso che sto tenendo molto basse per il problema esposto nel post #36 (cariche elettrostatiche) e che spero di risolvere acquistando un sensore di livello acqua (per ora sto facendo le prove con i cavetti dupont simulando contatto e apertura).
Colgo l'occasione per ringraziarti dell'aiuto anche perchè stamattina ho avuto un calo di autostima e stavo per buttare tutto dalla finestra  :smiley-mr-green:
Title: Re: Irrigazione automatica
Post by: Maurotec on May 26, 2019, 05:43 pm
La fase di riempimento può essere divisa in più fasi.
1° Controlla se la vasca è vuota, se lo è passa alla fase successiva il cui nome potrebbe essere RIEMPIMENTO_START. Mentre se la vasca è piena si salta RIEMPIMENTO_START.

La fase RIEMPIMENTO_START si limita ad alimentare l'elettrovalvola e passa alla fase successiva che ha il compito di verificare quando la vasca è piena, quando lo è si va alla fase successiva, fintanto che non lo è si rimane in questa fase.

Le fasi o stati possono statiche o dinamiche, tutto ciò che è statico lo si sa prima e lo si può definire ad esempio tramite un array.  Lo switch case è solo un modo di implementare la macchina a stati finiti ma noi per semplificare lo riteniamo essere l'unico modo. Quando una applicazione richiede due macchine a stati una dinamica e una statica servono ad esempio due switch case e quindi due variabili indipendenti.

La suddivisione evita ad esempio la necessità di questo while
Code: [Select]

while (analogRead(pinTroppopieno) <= 5) //soglia di prova
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }


Hai serial.print usalo, per evitare che stampi sempre sempre la stessa stringa serve una variabile che mantiene il valore della fase precedente.

Quote
fai finta di essere Arduino ed esegui tu il programma che hai scritto.
Non ti calare troppo nella parte altrimenti rischi di non uscirne e rimarrai arduino per sempre. :)

Ciao.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 26, 2019, 06:54 pm
Quote
il problema esposto nel post #36 (cariche elettrostatiche) e che spero di risolvere acquistando un sensore di livello acqua (per ora sto facendo le prove con i cavetti dupont simulando contatto e apertura).
Il problema si risolve con una normalissima resistenza di pull-up o pull-down da 1..10k come per leggere qualsiasi pulsante. Non ho però ancora capito se il contatto di troppo pieno deve dare un livello alto o basso, e neppure perché lo vuoi leggere con analogRead invece di digitalRead... devi leggere un contatto o un potenziometro?

Quote
Al momento ho risolto così e sembra funzionare
Il codice che hai scritto secondo me fa questo:

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309947)

Giusto degli esempi... cosa succede se la lettura vale 2?
Cosa succede se  dopo un secondo lettura vale 40?
Cosa succede se dopo un secondo lettura vale 100?

Il programma prima che su Arduino deve funzionare correttamente su carta... e naturalmente le prove reali non si possono fare con ingressi fluttuanti di cui non si è sicuri che livello abbiano.

Quote
stamattina ho avuto un calo di autostima e stavo per buttare tutto dalla finestra  :smiley-mr-green:
Hai detto tu: «Vi prego dunque di aiutarmi a capire cosa non capisco», quindi nessun errore verrà abbonato  ;D  :smiley-twist:





Quote
La suddivisione evita ad esempio la necessità di questo while
È quello che ho cercato di evidenziare con lo schema post #34, la valvola viene già aperta nella fase precedente, e rimane solo da controllare se è stato raggiunto il troppo pieno, senza bisogno di nessun while di attesa... la struttura a fasi è fatta proprio per questo, ma ammetto che inizialmente può essere difficile capire l'ordine in cui avvengono le cose per cui si cerca di procedere nel solito modo sequenziale scrivendo codice bloccante (che in questo specifico caso comunque problemi non ne da).

Quote
Non ti calare troppo nella parte altrimenti rischi di non uscirne e rimarrai arduino per sempre.
:smiley-mr-green:  :smiley-mr-green:  :smiley-mr-green:
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 07:46 pm
Il problema si risolve con una normalissima resistenza di pull-up o pull-down da 1..10k come per leggere qualsiasi pulsante. Non ho però ancora capito se il contatto di troppo pieno deve dare un livello alto o basso, e neppure perché lo vuoi leggere con analogRead invece di digitalRead... devi leggere un contatto o un potenziometro?
 :smiley-mr-green:  :smiley-mr-green:  :smiley-mr-green:
All'inizio pensavo di fare una cosa semplicissima e cioè due fili d'acciaio posti uno di fianco all'altro, uno preleva i 5v da arduino l'altro va a finire in A0, quindi l'acqua avrebbe fatto da contatto aperto/chiuso... ma non sapevo delle cariche elettrostatiche. Come infatti le prime "quote" che avevo messo erano 0 e 1023 quindi:

Code: [Select]
case RIEMPIMENTO:
      if (analogRead(pinTroppopieno) = 1023) {   
          digitalWrite(pinElettrovalvola, ACCESO);
          delay(2000);
        }
        while (analogRead(pinTroppopieno) <= 0)
        {
        digitalWrite(pinElettrovalvola, SPENTO);
        }


Poi dopo aver constatato che il mondo ideale non è quello reale, ho pensato di andare a controllare i valori aggiungendo la riga:

Code: [Select]
int sensorValue = analogRead(A0);
      Serial.println(sensorValue, DEC);


Fatto questo mi sono accorto che con i contatti aperti c'erano delle oscillazioni notevoli da 100 a 1023 circa ed ho inserito un valore di "sicurezza" cioè >=50 per verificare che la variabile funzionasse. Stessa cosa ho fatto con i contatti chiusi... mi sono tenuto largo ed invece di mettere 0 ho messo <=5. Ma li ho messi solo come valore di prova pensando che i sensori di pioggia/acqua (che non ho è che dovrò comprare) abbiano la resistenza che li protegge dalle cariche elettrostatiche e che quindi, successivamente, col sensore in mano avrei poi stabilito i valori di soglia reali.

Il codice che hai scritto secondo me fa questo:

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309947)

Mi sa che hai ragione

Hai detto tu: «Vi prego dunque di aiutarmi a capire cosa non capisco», quindi nessun errore verrà abbonato  ;D  :smiley-twist: 
La mia condizione attuale è che per la prima volta sto maneggiando codice C o arduinese, non so neanche se c'è una vera differenza. La pazienza e la buona volontà c'è, però mi trovo difronte a diverse difficoltà:
- Non conosco l'elettronca
- Non conosco gli operatori Arduino
- Se vado a leggermi le guide ho comunque difficoltà a capirle a causa di terminologie che per me indicano tutt'altra cosa se non addirittura nulla (array, macro, boolean ecc). Dunque per comprendere una spiegazione impiego il doppio del tempo  perchè non ho riferimenti e tutto i nomi usati sono per lo più sconosciuti.

Sono d'accordo e non voglio abbonato nessun errore, però quello che ti chiedo ovviamente ringraziandoti per la cortesia e la pazienza, è di non darmi tutti gli strumenti in mano perché altrimenti mi perdo e mi scoraggio. Dammi quello che è strettamente necessario per ora e lavoriamo su quelli perché se mentre cerco di padroneggiare l' IF entra lo SWICH col CASE, poi entra BOOL non ne esco... ovviamente non è una pretesa, ci mancherebbe altro, quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.

@Maurotec questo è anche il motivo per cui non ti ho fatto la domanda:
PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?

Vi ringrazio ancora
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 26, 2019, 08:24 pm
All'inizio pensavo di fare una cosa semplicissima e cioè due fili d'acciaio posti uno di fianco all'altro, uno preleva i 5v da arduino l'altro va a finire in A0, quindi l'acqua avrebbe fatto da contatto aperto/chiuso... ma non sapevo delle cariche elettrostatiche.
Come detto nel post #41 il problema c'è solo se l'ingresso è lasciato scollegato, metti una R da 10k verso massa e hai risolto. Con i due fili di acciaio piuttosto avresti il problema dell'elettrolisi, basta mettere nell'acqua i poli di una batteria 9V per vederla. Vediamo come sono questi sensori.

Per quanto riguarda gli strumenti ho cercato di proporre la struttura minima base generale per risolvere tutti i problemi una volta per sempre. Se seguivi paro paro lo schema post #34 avevi già finito ;) Ogni rettangolo è un case, e dentro ai case una o due righe di programma (non credo si possa fare molto di meno e soprattutto così flessibile e modificabile). Il case RIEMPIMENTO l'ho già scritto completo nel post #38. Se non piace lo switch c'è sempre la corrispondente forma a soli 'if' nel post #15.



Quote
PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?
https://forum.arduino.cc/index.php?topic=583927.msg3980712#msg3980712 (https://forum.arduino.cc/index.php?topic=583927.msg3980712#msg3980712)
Title: Re: Irrigazione automatica
Post by: Maurotec on May 26, 2019, 10:31 pm
Quote
Dammi quello che è strettamente necessario per ora e lavoriamo su quelli perché se mentre cerco di padroneggiare l' IF entra lo SWICH col CASE, poi entra BOOL non ne esco... ovviamente non è una pretesa, ci mancherebbe altro, quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.
Mi metto nei tuoi panni, so perfettamente cosa intendi, purtroppo noi abbiamo conoscenza di tutti gli strumenti offerti dal linguaggio e inevitabilmente tendiamo ad usare il martello per piantare e la pinza per afferrare.
Però è anche vero che se al momento disponi del solo cacciavite se serve lo usi pure a mo di martello. :)

Le conseguenze al momento non sono evidenti, ti voglio a capirci qualche cosa quando il numero delle variabili arriva a 50, più le costanti, più le funzioni, più gli switch, più gli if ecc, se poi usiamo pure i tipi di variabile a caso non sarà più possibile introdurre modifiche al codice senza comprometterne il funzionamento.

Quote
- Non conosco l'elettronca
- Non conosco gli operatori Arduino
- Se vado a leggermi le guide ho comunque difficoltà a capirle a causa di terminologie che per me indicano tutt'altra cosa se non addirittura nulla (array, macro, boolean ecc). Dunque per comprendere una spiegazione impiego il doppio del tempo  perchè non ho riferimenti e tutto i nomi usati sono per lo più sconosciuti.
Quote
quello che ho capito in due giorni non l'avevo capito in due anni di copia e incolla.
Posso girare la frittata, dicendo che hai perso due anni a copiare ed incollare senza ottenere quello che desideravi. Rigirandola nuovamente dico che è andata così solo perché non hai trovato un programma che con poche modifiche si adattava alle tue necessità. :)

Ma ora la situazione (STATO corrente) è questa: sei disposto a studiare quello che serve al fine di crearti la tua applicazione, nonostante alle volte tu possa trovarti nello stato "CARENZA_DI_AUTOSTIMA", in conseguenza di ciò hai anche previsto un CASE  BUTTARE_TUTTO_DALLA_FINESTRA, CASE che fino a questo momento non hai deciso di eseguire. :) 

Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on May 26, 2019, 11:13 pm
La colpa è sempre dell'ignoranza, nel senso di ignorare le cose e l'unico modo per uscirne è cercare di capire...
Siccome il mio problema attuale sono un botto di termini che non ricordo, ho trovato un link (http://polinienrico.altervista.org/index.php?option=com_content&view=article&id=57&Itemid=66) che mi sono stampato ed in una paginetta semplifica le istruzioni standard di arduino. Sembra una cavolata ma mi sta schiarendo parecchio le idee perchè con un colpo d'occhio riesco a collocare termini che a memoria non ricorderei. Tra l'altro cercare sul web a volte complica la vita invece di risolvere i problemi. Ora sono stanco ma domattina non vedo l'ora di mettermi al lavoro.
Se voi non mi mollate io non mollo! Siete avvisati!  Grazie per la comprensione e Buonanotte    :smiley-mr-green:
Title: Re: Irrigazione automatica
Post by: Maurotec on May 27, 2019, 12:23 am
Occhio che quella guida contiene qualche errore, si spera migliori.

Uno di questi è: insigned che non esiste, come pure Insigned.

Il linguaggio C/C++ prevede una "istruzione" per dare un nome a piacere ad un tipo di dato predefinito.
L'istruzione in questione è typedef.
Il termine istruzione in questo caso è ambiguo.

I tipi predefiniti in C sono:
char
int
long
long long
float
double

Questi sono tutti tipi con segno (signed) anche se non è specificato prima.
Per i primi 4 si può specificare unsigned, cioè:
unsigned char
uinsigned int
unsigned long
unsigned long long

Grazie alla "istruzione" typedef arduino ha ridefinito il tipo unsigned char dandogli il nome byte.
In poche parole dentro al codice delle librerie c'è,
Code: [Select]

typedef unsigned int word;
typedef bool boolean;
typedef uint8_t byte;

Ecco che spunta uint8_t, già visto prima ma anche word

Pertanto usare bool al posto di boolean è equivalente.
Come pure uint8_t al posto di unsigned char o ancora byte

Evidentemente si fa prima a scrivere byte che unsigned char

Per finire uint8_t è disponibile fino a 64 al posto di 8, cioè uint16_t, uint32_t e uint64_t
tutti senza segno, basta non digitare la u per averli con segno.

Ecco che la potenza del linguaggio anziché semplificare complica, ma aumenta la flessibilità.

PS: Spero che questo tu possa digerirlo senza puntare gli occhi verso la finestra :D
Title: Re: Irrigazione automatica
Post by: Standardoil on May 27, 2019, 07:13 am
Comunque comodo, nonostante i problemini elencati, e altri ancora, come flush() che non lavora più come dedcritto
Poi però è necessario imparare a consultare il reference, proprio per queste ragioni
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 01:01 pm
Ecco cosa ho combinato:

Code: [Select]
switch (fase)
    {
      case RIEMPIMENTO_START:
        if (analogRead(pinTroppopieno) == 0) {  
          digitalWrite(pinElettrovalvola, SPENTO); // se il contatto è chiuso lascialo chiuso
          }
        else
          {
          digitalWrite(pinElettrovalvola, ACCESO);  // altrimenti apri l'elettrovalvola
          }
        fase = RIEMPIMENTO_STOP;  // e vai alla fase RIEMPIMENTO_STOP
        break;
      case RIEMPIMENTO_STOP:
        if (analogRead(pinTroppopieno) == 1023) {  
          digitalWrite(pinElettrovalvola, ACCESO); // se il contatto è aperto lascialo aperto
        }
        while (analogRead(pinTroppopieno) == 0) // finchè il contatto è chiuso
        {
        digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola
        }
        fase = RIPOSO;  // e vai alla fase RIPOSO
        break;


in realtà nel "case RIEMPIMENTO_STOP" la prima lettura è inutile perchè se è passato a questa fase è perchè  il contatto è aperto, però ho bisogno che ripeta questa lettura finchè poi si verifica la condizione while.
Per quanto riguarda ==1023 e ==0 per ora non avendo la resistenza da 10K li ho messi così, ma mi riserverò di andare a verificare i valori e gli operatori di comparazione 8)  dopo che avrò la resistenza
Che ne dite può andare o punto la finestra?....

Con i due fili di acciaio piuttosto avresti il problema dell'elettrolisi
https://forum.arduino.cc/index.php?topic=583927.msg3980712#msg3980712 (https://forum.arduino.cc/index.php?topic=583927.msg3980712#msg3980712)
Per quanto riguarda l'ossidazione da elettrolisi ho pensato ad un altra via, la via asciutta... Siccome ho intenzione di mettere una valvola meccanica a galleggiante come sistema di sicurezza, a sto punto la userò anche per tenere sospeso e fuori dall'acqua il contatto aperto chiuso.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 28, 2019, 01:32 pm
Risposta breve: ci stiamo infognando come non previsto. Forse ho dato troppe cose per scontate.

Per la risposta lunga tocca attendere la sera.

Intanto medita su cosa fa quel while e sul perchè è paragonabile a un buco nero... finchè contatto chiuso chiudi valvola... e rimani sempre li perchè il CICLO while non termina mai FINCHÉ il contatto continua a restare chiuso.
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 01:46 pm
Ma se sposto la FASE RIPOSO dentro la parentesi {} del while non dovrei risolvere uscendo dalla fase RIEMPIMENTO_STOP?
Code: [Select]

while (analogRead(pinTroppopieno) == 0) // finchè il contatto è chiuso
        {
        digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola
        fase = RIPOSO; // e vai alla fase RIPOSO
        }
        break;
Title: Re: Irrigazione automatica
Post by: Maurotec on May 28, 2019, 02:49 pm
Quote
Ma se sposto la FASE RIPOSO dentro la parentesi {} del while non dovrei risolvere uscendo dalla fase RIEMPIMENTO_STOP?
No, purtroppo non basta impostare la variabile fase = RIPOSO per passare al CASE RIPOSO. Non funziona perché il while ripete in ciclo tra { e } fintanto che la condizione viene valutata vera.

Quote
Che ne dite può andare o punto la finestra?....
IF (FINESTRA == APERTA)
    Butta();
ELSE
    OPEN(FINESTRA);
    Butta();
 :D
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 02:59 pm
 8)

Code: [Select]
switch (fase)
    {
      case RIEMPIMENTO_START:
        if (digitalRead(pinTroppopieno) == 1) {   
          digitalWrite(pinElettrovalvola, SPENTO); // se il contatto è chiuso lascia l'elettrovalvola chiusa
          }
        while (digitalRead(pinTroppopieno) == 0)
          {
          digitalWrite(pinElettrovalvola, ACCESO);  // altrimenti apri l'elettrovalvola
          }
        fase = RIEMPIMENTO_STOP;  // e vai alla fase RIEMPIMENTO_STOP
        break;
      case RIEMPIMENTO_STOP:
        digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola
        fase = RIPOSO; // e vai alla fase RIPOSO
        break;
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 28, 2019, 05:36 pm
L'ultimo codice almeno funziona :) Però stai ragionando in modo procedurale e non sfruttando (i vantaggi del)la logica a fasi, anzi, la bypassi completamente trasformandola di nuovo in procedurale puro.

Quindi è del tutto inutile tenere in piedi lo switch, la variabile fase ecc... il tuo codice funzionerebbe ugualmente scrivendolo così nel loop:

Code: [Select]
if (digitalRead(pinTroppopieno) == 1) {  
  digitalWrite(pinElettrovalvola, SPENTO); // se il contatto è chiuso lascia l'elettrovalvola chiusa
  }
while (digitalRead(pinTroppopieno) == 0)
  {
  digitalWrite(pinElettrovalvola, ACCESO);  // altrimenti apri l'elettrovalvola
  }
digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola

Siccome il primo if è ridondante, allora basterebbe:
Code: [Select]
while (digitalRead(pinTroppopieno) == 0)
  {
  digitalWrite(pinElettrovalvola, ACCESO);  // altrimenti apri l'elettrovalvola
  }
digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola

Poi diamo anche a quegli uni e zeri un significato comprensibile come già fatto per le uscite, e rendiamo i commenti coerenti con le istruzioni:
Code: [Select]
while (digitalRead(pinTroppopieno) == APERTO) // finche' contatto aperto
{
    digitalWrite(pinElettrovalvola, ACCESO);  // valvola aperta
}
digitalWrite(pinElettrovalvola, SPENTO);      // poi chiudila

Se abbandoniamo la logica a fasi allora si torna all'algoritmo "classico"... solo da tradurre sintatticamente C. In rosso il riempimento, in verde il riposo, arancio la concimazione, blu irrigazione...

peristalsi off
agitatore off
pompa off
ripeti:
    finché contatto aperto
        valvola aperta
    valvola chiusa
    finché non orario e non mese:
        nulla
    se mese:
        peristalsi on
        agitatore on
        pausa
        peristalsi off
        agitatore off
    pompa on
    pausa
    pompa off

Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 06:23 pm
L'ultimo codice almeno funziona :) Però stai ragionando in modo procedurale e non sfruttando (i vantaggi del)la logica a fasi, anzi, la bypassi completamente trasformandola di nuovo in procedurale puro.

Quindi è del tutto inutile tenere in piedi lo switch, la variabile fase ecc...
Il fatto è che non avendo ancora padroneggiato e sudato sull'IF...ELSE...WHILE non capisco appieno i vantaggi dello switch. Poi non pensavo neanche si potesse partire dal while ma credevo fosse indispensabile partire sempre con if... per questo motivo ho agito in modo coatto facendo :

Code: [Select]
case RIEMPIMENTO_STOP:
        digitalWrite(pinElettrovalvola, SPENTO); // allora spegni l'elettrovalvola
        fase = RIPOSO; // e vai alla fase RIPOSO


Ho aggiunto una fase chiamata PRIMA_ACCENSIONE perchè altrimenti incasino la cosa, mi spiego.
La prima volta che avvierò l'irrigatore, dopo aver riempito il contenitore ho bisogno che l'acqua decanti per 24h. Se vado a mettere questa funzione che serve solo al primo avvio nella fase RIPOSO poi dopo aver innaffiato non potrò ripetere il ciclo ritornando su RIPOSO.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 28, 2019, 07:05 pm
non avendo ancora padroneggiato e sudato sull'IF...ELSE...WHILE non capisco appieno i vantaggi dello switch
Post #15, lo switch è solo un 'if/else if' scritto in altro modo, quindi il problema secondo me non è lo switch, ma la struttura logica e come avviene l'esecuzione.

Quote
Poi non pensavo neanche si potesse partire dal while ma credevo fosse indispensabile partire sempre con if
Appunto, ogni passo avanti tocca farne tre indietro. La programmazione, la struttura, l'idea di cosa usare vengono prima della codifica. Questo è quello che intendo dicendo che il programma prima deve funzionare su carta. E di quali cose è formato? Solo da sequenze, ramificazioni (if), ripetizioni (while) combinate come si vuole.

Quote
La prima volta che avvierò l'irrigatore, dopo aver riempito il contenitore ho bisogno che l'acqua decanti per 24h. Se vado a mettere questa funzione che serve solo al primo avvio nella fase RIPOSO poi dopo aver innaffiato non potrò ripetere il ciclo ritornando su RIPOSO
A questo serve la chiara separazione in fasi. Lo switch è solo un if per eseguire ad ogni giro di loop il solo codice della fase attualmente attiva. Ma nella fase vanno messe istruzioni congruenti con il significato della fase stessa. RIEMPIMENTO_STOP sarebbe una non fase, ma se ci sono altre fasi che io non vedo per cui diventa utile non posso saperlo  ;)
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 09:22 pm
RIEMPIMENTO_STOP l'ho eliminato, anzi sostituito con PRIMA_ACCENSIONE dove dovrò impostare un ritardo di 24H rispetto all'ora attuale e per il momento vedo solo due vie salvo un vostro consiglio.
La prima via è la più semplice, sempre che funzioni
Code: [Select]
delay(86400000);
Ma non credo mi stiate dedicando il vostro tempo per fare le cose alla meno peggio, e per questo vi ringrazio.

La seconda via che mi viene in mente è quella sfruttare la EEPROM di arduino, quindi dovrei procedere includendo la libreria, poi successivamente leggere l'RTC e scrivere sulla EEPROM l'ora ed i minuti
Code: [Select]
int ORE = now.hour();
    int MINUTI = now.minute();

Poi dovrei mettere un delay di 60 sec in modo da far passare 1 minuto per non trovarmi alla stessa ora mentre va a fare il confronto

Infine sempre che questa cosa sia fattibile dovrei porre una condizione:
Se ora e minuti dell'RTC == ora e minuti dell'EEPROM (passa alla fase successiva)

Ora però, sempre che questa sia la via da seguire, ho un problema (Houston)
Nel codice di inizializzazione (void setup) l'RTC non è ancora avviato pertanto non saprei proprio dove andare a prendere le ore ed i minuti da scrivere sull'eeprom

Code: [Select]
EEPROM.write(ORE,MINUTI);

Ho evitato di fare prove perchè so che la EEPROM ha un numero di scritture limitate quindi vorrei evitare di fare danni prima di capire sequesta via è fattibile. :smiley-mr-green:

Oppure posso scrivere sull'EEPROM direttamente dalla fase PRIMA_ACCENSIONE ?
Title: Re: Irrigazione automatica
Post by: maubarzi on May 28, 2019, 09:32 pm
L'RTC, una volta impostata l'ora, continua ad andare senza problemi, gli basta solo la sua batteria tampone.
In genere lo inizializzi nel setup e all'esecuzione successiva tiri via tutto perchè non serve reinizializzarlo ogni volta.
Lo puoi fare anche solo con uno sketch che fa solo quello.
Poi, invece, potresti aver la necessità di correggere l'ora, ogni tanto, perchè qualcosa sballa sempre. Quindi devi pensare a come fare. Magari con dei pulsanti per fare le variazioni come nei normali orologi digitali.

Per la EEPROM, sopporta decine di migliaia (se non centinaia di migliaia) di cicli di scrittura, quindi qualche prova non fa grossi danni.
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 09:44 pm
L'RTC, una volta impostata l'ora, continua ad andare senza problemi, gli basta solo la sua batteria tampone.
In genere lo inizializzi nel setup e all'esecuzione successiva tiri via tutto perchè non serve reinizializzarlo ogni volta.
Lo puoi fare anche con uno sketch che fa solo quello.
Poi, invece, potresti aver la necessità di correggere l'ora, ogni tanto, perchè qualcosa sballa sempre. Quindi devi pensare a come fare. Magari con dei pulsanti per fare le variazioni come nei normali orologi digitali.

@maubarzi forse non hai seguito lo svolgersi del "progetto", cmq ti ringrazio per l'interesse e ti aggiorno.
L'RTC è impostato correttamente, ora ho necessità di prendere l'ora e impostare un evento (che poi sarebbe uno switch ad un case successivo) a 24 ore di distanza.
Devo capire questa cosa come si può fare e per ora stavo pensando di utilizzare la EEPROM evitando così di perdermi in complicati calcoli matematici. Allego il progetto.

PS Scusa, ho notato solo dopo che eri presente sin dai primi post  :-[
Title: Re: Irrigazione automatica
Post by: maubarzi on May 28, 2019, 11:02 pm
Tranquillo, rispondevo a queste due cose:
Nel codice di inizializzazione (void setup) l'RTC non è ancora avviato pertanto non saprei proprio dove andare a prendere le ore ed i minuti da scrivere sull'eeprom
Ho evitato di fare prove perchè so che la EEPROM ha un numero di scritture limitate quindi vorrei evitare di fare danni prima di capire sequesta via è fattibile. :smiley-mr-green:
Sulla prima avevo capito che non avevi ancora inizializzato l'RTC con un orario buono, se invece non hai ancora inizializzato l'oggetto basta invertire le istruzioni nel setup e inizializzarlo prima di fare altro.

Sulla seconda ti rassicuravo sul fatto che potevi fare tranquillamente prove con la EEPROM perchè i limiti di riscrittura sono ben ampi da sopportare qualche test a vuoto.

L'attesa delle 24h mi sa che è abbastanza critica, e scrivere sulla EEPROM mi pare una buona idea anche per proteggerti da anomalie quali riavvii o spegnimenti non previsti.
Dovessero capitare, non perderesti il conteggio del tempo di attesa.
Sarebbero poche scritture al mese e quindi nessun problema per la durata delle EEPROM

Quando fai la prima accensione, ti potresti salvare data e ora di ripartenza, sommando 24 ore alla data/ora in cui fai questa prima accensione.
Poi, prima di ogni annaffiatura verifichi se è passata questa data/ora e solo se è passata procedi con l'annaffiatura.

Questo test lo puoi fare in due punto a seconda di come ti trovi meglio.
1) prima di cambiare stato. E quindi verifichi periodicamente la condizione e quando si verifica cambi stato.
2) dopo il cambio stato per decidere se far partire l'operazione del nuovo stato oppure non ancora.
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 11:27 pm
Sto facendo delle prove per vedere se riesco scrivere e leggere nella eeprom, in pratica nel void loop ho inserito
Code: [Select]

    int ORE = now.hour();
    int MINUTI = now.minute();
    ... // tralasciando il resto del codice per semplificare
    Serial.println(EEPROM.read(ORE), DEC);
    Serial.print(':');
    Serial.println(EEPROM.read(MINUTI), DEC);
    delay(1000);


Poi in un cambio di stato ho inserito (giusto come prova, non ha nessun senso ma voglio provare a scrivere l'eeprom,  e leggerla)

Code: [Select]
case PRIMA_ACCENSIONE:
        EEPROM.write(ORE, MINUTI);
        fase = RIPOSO; // cambio di stato
        break;

        case RIPOSO:
        digitalWrite(pinPompa, ACCESO); // l'accensione del relay indica che lo stato PRIMA_ACCENSIONE è stato eseguito
        break;



Però per l'ora che mi ritrovo sul monitor seriale sono le 26:160  :o
Title: Re: Irrigazione automatica
Post by: karnhack on May 28, 2019, 11:59 pm
Però per l'ora che mi ritrovo sul monitor seriale sono le 26:160  :o
Mi cito da solo... probabilmente l'eeprom era scritta da prima ecco perchè avevo numeri completamente sballatii. Ho cancellato l'EEPROM tramite un esempio presente nella libreria esempi "eeprom_clear" ed ora va un pochino meglio in quanto segna le 55:0 dove 55 sono i minuti ( che sono corretti anche se nella posizione delle ore)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 29, 2019, 07:00 am
Sto facendo delle prove per vedere se riesco scrivere e leggere nella eeprom
La EEPROM è come un array di 1024 byte.

Quando vuoi scrivere un byte specifichi in quale (indirizzo da 0 a 1023) e cosa (valore da 0 a 255).
Code: [Select]
EEPROM.write(indirizzo_del_byte, valore);
Quando vuoi leggere un byte specifichi da quale (indirizzo da 0 a 1023).
Code: [Select]
mio_byte = EEPROM.read(indirizzo_del_byte);

Quindi capisci ben che un codice come questo non ha alcun senso logico... qui punti il byte di indirizzo ORE (quindi una cella di memoria dalla 0 alla 23) e ci scrivi il valore di MINUTI:
Code: [Select]
EEPROM.write(ORE, MINUTI);
Mentre qui leggi un byte dall'indirizzo minuti, cioè da una cella compresa tra 0 e 59:
Code: [Select]
Serial.println(EEPROM.read(MINUTI), DEC);

Quote
ora va un pochino meglio in quanto
In informatica le cose non possono andare "un pochino meglio", o vanno esattamente come si vuole, o sono sbagliate. Se sono sbagliate si studia da zero il singolo argomento, in questo caso come scrivere e leggere un valore nella/dalla EEPROM. Poi si applica la conoscenza della EEPROM (come scrivere e leggere un byte da una cella di memoria di indirizzo ben preciso) alla logica che si vuole realizzare. Ho l'impressione che siano di nuovo tentativi alla cieca (tra l'altro non ho capito perché vuoi usare la EEPROM).
Title: Re: Irrigazione automatica
Post by: karnhack on May 29, 2019, 11:18 am
Ho l'impressione che siano di nuovo tentativi alla cieca (tra l'altro non ho capito perché vuoi usare la EEPROM).
Perchè mi sembrava la via più semplice... a dire il vero la via più semplice è quella del delay di 86400000 millesimi, anche perchè della precisione in questo caso non so che farmene, mi serve solo per rimandare il prossimo stato e far decantare l'acqua. Certo che se va via la luce è un "problema", ma neanche troppo grande, a meno che non collego arduino ad una batteria tampone ma non ne vale la pena secondo me.
Poi ho pensato che essendoci la EEPROM potevo sfruttarla ed ho fatto dei tentativi... alla cieca è vero.
Però le ultime 6 ore fino alle 2 di notte le ho passate a cercare informazioni sulla eeprom, a guardare gli sketch di esempi eeprom di arduino ecc ecc. la volontà di studiare c'è stata, ma se devo essere sincero mancano i manuali.
Su internet è un casino perchè ognuno ha il suo metodo e dice la sua, chi fa esempi cosi 0X00 chi colì e sai bene che per fare una ricerca decente devi sapere cosa cerchi e usare i termini giusti altrimenti è un mare di lucciole.

Scusa lo sfogo  :smiley-sweat:
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 11:27 am
... ma se devo essere sincero mancano i manuali.
Tieni, ecco una buona guida che offre oltretutto vari spunti e semplificazioni ;)

NON usa la libreria di Arduino, ma quella di base <avr/eeprom.h> (https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html) (su cui quella di Arduno è costruita) che si trova in AVR libc (https://www.nongnu.org/avr-libc/user-manual/modules.html), libreria automaticamente sempre inclusa dall'IDE di Arduino ;)

Guglielmo
Title: Re: Irrigazione automatica
Post by: zoomx on May 29, 2019, 11:50 am
Ci sarebbe anche la memoria I2C contenuta nel modulo RTC.
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 12:00 pm
Ci sarebbe anche la memoria I2C contenuta nel modulo RTC.
In effetti ... visto che usa il DS1307 ...

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310369)


... dall'indirizzo 0x08 a 0x3F (58 bytes) è tutta memoria a disposizione dell'utente per salvarci quello che si vuole :)

Guglielmo
Title: Re: Irrigazione automatica
Post by: zoomx on May 29, 2019, 12:18 pm
Oltre alla memoria contenuta nell'RTC sul modulo TinyRTC c'è montata una memoria I2C.
Title: Re: Irrigazione automatica
Post by: maubarzi on May 29, 2019, 12:25 pm
La EEPROM ha senso per salvare informazioni che resistano al riavvio, si rileggono nel setup e poi si lavora in memoria, a meno che le informazioni non siano proprio tante da non stare in memoria e allora si usa come appoggio per le cose meno usate.
Io la avevo intesa così quando ti ho incoraggiato sulla EEPROM.
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 12:45 pm
Oltre alla memoria contenuta nell'RTC sul modulo TinyRTC c'è montata una memoria I2C.
... quella mi sembra un'inutile complicazione ! ::)

Considera che lui ha già (a gratis) le chiamate per leggere e scrivere nella memoria del DS1307, difatti la libreria RTClib, che lui usa, include i seguenti metodi:

Code: [Select]
uint8_t readnvram(uint8_t address);
void readnvram(uint8_t* buf, uint8_t size, uint8_t address);
void writenvram(uint8_t address, uint8_t data);
void writenvram(uint8_t address, uint8_t* buf, uint8_t size);

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on May 29, 2019, 12:49 pm
La EEPROM ha senso per salvare informazioni che resistano al riavvio, si rileggono nel setup e poi si lavora in memoria, a meno che le informazioni non siano proprio tante da non stare in memoria e allora si usa come appoggio per le cose meno usate.
Io la avevo intesa così quando ti ho incoraggiato sulla EEPROM.
A me serve solo ritardare una fase di 24 ore, tutto qui. Siccome la fase RIPOSO sarà quella che deciderà quando perchè irrigare ho bisogno che questo delay di 24ore sia isolato, altrimenti ci sarà sempre un ritardo di 24 ore prima di ogni irrigazione.
Per questo motivo  ho inserito una fase PRIMA_ACCENSIONE con lo scopo di creare un ritardo di 24 ore solo alla prima accensione, e mai più.

Code: [Select]
switch (fase)
    {
      case RIEMPIMENTO_START:
        // riempie il contenitore e l'acqua dovrà decantare 24 ore
        fase = PRIMA_ACCENSIONE; 

      case PRIMA_ACCENSIONE:
        // aspetta 24 ore (decantazione)
        break;
       
      case RIPOSO:
        // attende la condizione su base mensile ed oraria
        break;

      case CONCIMAZIONE:
        // se il mese rientra nella condizione inserisce il concime nel contenitore altrimenti passa alla fase IRRIGAZIONE
        break;

      case IRRIGAZIONE:
      // Irriga e a fine operazione ritorna alla fase RIPOSO
      break;


Come ho detto precedentemente un delay di 86400000 millesimi basterebbe, ma avendo il TinyRTC stavo cercando altre vie. Mi è venuta in mente l'EEPROM ma io ignoro il 99% delle vie possibili quindi può essere una stupidaggine bella e buona usarla
Title: Re: Irrigazione automatica
Post by: zoomx on May 29, 2019, 02:18 pm
... quella mi sembra un'inutile complicazione ! ::)
Ricorda che quei 56 byte non sono in flash ma alimentati a batteria, quella dell'RTC.
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 02:25 pm
Ricorda che quei 56 byte non sono in flash ma alimentati a batteria, quella dell'RTC.
Che si spera sia sempre carica (durano anni) e che comunque serve SOLO se manca l'alimentazione al modulo.
Considera che se gli si scarica ... addio anche a data/ora ... e quindi ;)

Guglielmo
Title: Re: Irrigazione automatica
Post by: zoomx on May 29, 2019, 02:26 pm
Considera che se gli si scarica ... addio anche a data/ora ... e quindi ;)
E questo è anche vero!
Title: Re: Irrigazione automatica
Post by: karnhack on May 29, 2019, 02:32 pm
Però fatemi capire la differenza perché ora sto facendo delle prove... sul mio RTC c'è scritto "TinyRTC I2C Module" quindi con cosa sto lavorando con RTC o con I2C? Nello sketch precedente ho impostato l'ora dell'RTC con
Code: [Select]
RTC.adjust(DateTime(2019, 05, 28, 23, 10, 00)); // decommentare per regolare ora e data (yyyy,mm,dd,hh,mm,ss)


Ora provando a scrivere sulla ram dell'RTC richiamando la libreria WIRE noto che i due orari sono diversi quindi sono un po confuso... questo è l'esempio che mi ha confuso:
Code: [Select]
#include <Wire.h> //include la libreria I2C

void setup()
{
Serial.begin(9600); //inizializza la seriale

Wire.begin(); //inizializza libreria

Wire.beginTransmission(0x68); //attiva la comunicazione con il DS1307 all'indirizzo RTC 0x68
Wire.write((byte)0x00); //il primo byte stabilisce il registro iniziale da scrivere i SECONDI da 0x00 a 0x59
Wire.write((byte)0x10); //il secondo byte specifica il tempo  MINUTI da 0x00 a 0x59
Wire.write((byte)0x80 | 0x10); //il terzo byte specifica il tempo  da 0x00 a 0x24
Wire.endTransmission();
}

void loop()
{
Wire.beginTransmission(0x68); //inizializza la trasmissione
Wire.write((byte)0x00); // partendo dall'indirizzo 0x00
Wire.endTransmission();

Wire.requestFrom(0x68, 3); //richiedo 3 byte dal dispositivo con indirizzo 0x68
byte secondi = Wire.read(); //recupero 1 byte dei secondi
byte minuti = Wire.read(); //recupero 1 byte dei minuti
byte ora = Wire.read(); //recupero i 1 byte delle ore

Serial.print("Orario corrente: ");
Serial.print(ora, HEX);
Serial.print(":");
Serial.print(minuti, HEX);
Serial.print(":");
Serial.println(secondi, HEX);
Serial.println();

delay(1000);
}
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 02:58 pm
O usi la libreria o accedi direttamente al modulo ...
... inutile fare entrambe le cose (senza, per di più, sapere esattamente quello che si sta facendo).  La libreria accede al modulo attraverso il bus I2C, ma quello è un problema di collegamento "fisico", non di sofware.

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on May 29, 2019, 03:03 pm
O usi la libreria o accedi direttamente al modulo ...
... inutile fare entrambe le cose (senza, per di più, sapere esattamente quello che si sta facendo).  La libreria accede al modulo attraverso il bus I2C, ma quello è un problema di collegamento "fisico", non di sofware.

Guglielmo
E se sapevo esattamente quello che stavo facendo ti pare che ero qui ad elemosinare aiuto? senza offesa.
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 03:07 pm
E se sapevo esattamente quello che stavo facendo ti pare che ero qui ad elemosinare aiuto? senza offesa.
... ma appunto t'ho detto di usare la libreria e, almeno per il moento, lasciar stare altri metodi ;)

La libreria ti mette a disposizione tutto quello che ti serve (inclusi i metodi per salvare/leggere dati nella ram del DS1307).

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on May 29, 2019, 03:13 pm
Quindi se ho capito bene per dialogare con l'RTC uso la libreria RTClib... il fatto che nella maggior parte degli sketch venga inclusa anche la wire è per dialogare col monitor seriale arduino che usa l'I2C
Ok ci riprovo, grazie
Title: Re: Irrigazione automatica
Post by: maubarzi on May 29, 2019, 03:47 pm
Se non vi dispiace, mentre continuate le discussioni sugli aspetti di dettaglio, vorrei tornare sulla struttura di base per cercare di fare un po' di ordine, in primis, nella mia testa.
Fatto questo, si potrebbero iniziare ad inserire nel posto giusto i vari dettagli così da veder concretizzarsi qualcosa e mantenere l'entusiasmo.

Personalmente partirei dal diagramma del post 6 che riporto qui:
(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=309683)
Anche io metterei al primo posto la fase di riempimento, per essere sicuri di non fare un giro a vuoto a causa di una qualche anomalia, ad es. un riavvio imprevisto o il primo avvio di stagione con bidone ancora vuoto.
Poi, visto che hai già in mente di aggiungere successivamente rilevamento di umidità, temperatura e pioggia, scarterei l'ipotesi 1 di programma cablato e puramente sequenziale e passerei direttamente alla opzione 2 che è più flessibile e se fatta bene non è poi tanto più complicata. Parlo delle due opzioni numerate in rosso nel post 6.

Da questo schema passerei a quello qui sotto che dettaglia ulteriormente alcune cose e si presta meglio ad una mappatura 1:1 con gli stati della possibile macchina a stati finiti.
Alcune cose le ho schematizzate come fasi (in particolare le due fasi stand-by...) appunto per una migliore traducibilità finale, poi è una questione di scelte, per cui se non piace discutiamone o pattumiamo pure ;)
(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310387)
Da qui si potrebbe già scrivere lo scheletro del programma che verrebbe tipo quello qui sotto scritto in pseudo C misto ad italiano.
Come si vede ho creato lo switch case e mappato tutto in funzioni che dovranno contenere il codice di dettaglio.
In questo modo ogni funzione isola un aspetto del problema che può essere trattato e approfondito da solo.

Code: [Select]

#define START 0 // Prima fase, che abbiamo anche all'avvio di Arduino.
#define RIEMPIMENTO 1
#define RIPOSO 2
#define STAND_BY_CONCIMAZIONE 3
#define CONCIMAZIONE 4
#define AGITAZIONE 5
#define STAND_BY_IRRIGAZIONE 6
#define IRRIGAZIONE 7

byte fase = START;
void setup() {
  inizializzazioni varie.
}

void loop() {
  // PREMESSA: il loop dovrà girare al massimo della velocità!!!

  // Qui raccogliamo dati che useremo in seguito come l'ora, i valori dei pulsanti delle sonde, dei troppo pieno, della temperatura, umidità ecc.
  letturaComandiESensoriVari();

  // Inizziamo con la gestione della macchina a stati finiti.
  switch(fase) {
    case START:
      faseStart();
      break;
    case RIEMPIMENTP:
      faseRiempimento();
      break;
    case RIPOSO:
      faseRiposo();
      break;
    case STAND_BY_CONCIMAZIONE:
      verificaNecessitaConcimazione();
      break;
    case CONCIMAZIONE:
      faseConcimazione();
      break;
    case AGITAZIONE:
      faseAgitazione();
      break;
    case STAND_BY_IRRIGAZIONE:
      verificaNecessitaIrrigazione();
      break;
    case IRRIGAZIONE:
      faseIrrigazione();
      break;
  }
  visualizzazioneDatiSuDisplay();
}

void letturaComandiESensoriVari() {
  // Come già indicato sopra, qui ci andranno tutte le rilevazioni del caso opportunamente temporizzate per non farle proprio ad ogni giro di loop.
}

void faseStart() {
  if (verificaTroppoPieno()) {
    // Passiamo alla fase successiva.
    fase++;
  } else {
    // Saltiamo alla fase specifica.
    fase = STAND_BY_CONCIMAZIONE;
  }
}

boolean verificaTroppoPieno() {
  // Leggiamo il sensore o i sensori per verificare se il serbatoio è pieno.
  if (il serbatoio è pieno) {
    return true;
  } else {
    return false;
  }
}

void faseRiempimento() {
  // Attiviamo pompe e ciapini vari per iniziare il riempimento tenendo sempre sott'occhio il sensore del troppo pieno per bloccare tutto appena la cisterna è piena.
  if (cisterna piena) {
    if (pompa accesa) {
      // Il test rende più tollerante il codice da eventuali malfunzionamenti che fanno arrivare qui a pompa ancora spenta, ad es. è fallito il test della fase precedente. Meglio non dare queste cose per scontato, anche se dovrebbero esserlo ;)
      spegni pommpa se accesa
    }
    fase++
  } else if (pompa spenta) {
    accendiamo la pompa
  } else {
    if (timeout pompa accesa) {
      spegni pompa
      salva errore per notifica
      fase++;
    }
  }
}

void faseRiposo() {
  // Attendiamo le 24h.
  if (sono passate le 24h) {
    fase++;
  }
}

void verificaNecessitaConcimazione() {
  // Analizziamo i dati dell'RTC letti a inizio loop per vedere se è ora di concimare.
  if (è ora di concimare) {
    // Passiamo alla fase successiva che è quella di concimazione.
    fase++;
  } else {
    // Passiamo alla fase di verifica dell'orario di irrigazione.
    fase = STAND_BY_IRRIGAZIONE;
  }
}

void faseConcimazione() {
  // Attiviamo tutte le cose che servono per la concimazione.
  // Sulla falsariga della faseRiempimento.
  // E' da verificare che ci sia stata almeno una irrigazione dall'ultima concimazione. Per evitare di farla doppia ad es. a causa di un mese piovoso che non fa irrigare mai.
  ...
  if (tutto finito e fatto bene) {
    fase++;
  }
}

void faseAgitazione() {
  // Attiviamo tutte le cose che servono per l'agitazione.
  // Sulla falsariga della faseRiempimento e faseConcimazione.
  ...
  if (tutto finito e fatto bene) {
    fase++;
  }
}

void verificaNecessitaIrrigazione() {
  // E' arrivata l'ora di irrigare?
  // Possiamo anche verificare altre condizioni per evitare di irrigare, ad es. se sta piovendo.
  // In base alle condizioni rilevate, possiamo impostare un nuovo tempo di attesa prima di irrigare nuovamente.
  if (è ora di irrigare) {
    fase++;
  } else {
    // Cicliamo tra queste due condizioni per poter far partire quella che scade per prima anche in base ad eventuali contrattempi.
    fase = STAND_BY_CONCIMAZIONE;
  }
}

void faseIrrigazione() {
  // Attiviamo tutte le cose che servono per l'irrigazione.
  // Sulla falsariga della faseRiempimento, faseConcimazione e faseAgitazione.
  ...
  if (tutto finito e fatto bene) {
    // Ripartiamo dalla prima fase in modo da permettere il riempimento della cisterna.
    fase = START;
  }
}

void visualizzazioneDatiSuDisplay() {
  // Operazione da temporizzare opportunamente per non fare aggiornamenti ad ogni giro di loop ma solo quando serve.
  // Si potrebbe usare una variabile booleana da mettere a true dentro le altre funzioni se ci sono modifiche ai dati da visualizzare.
  if (c'è qualche novità da visualizzare) {
    // scrivi su display tutti i dati da visualizzare.
  }
}
Title: Re: Irrigazione automatica
Post by: gpb01 on May 29, 2019, 04:29 pm
Quindi se ho capito bene per dialogare con l'RTC uso la libreria RTClib...
La Wire la devi lasciare, viene usata anche dalle altre librerie (... che spesso se la includono per conto loro) per parlare con qualunque cosa sia collegato al bus I2C (sensori, RTC, ecc. ecc.).  Semplificado possiamo dire che ha il compito di interfacciare il bus fisico ed i suoi segnali con il software.

Se vai a vedere, la tua RTClib, nel file RTClib.cpp la prima cosa che fa è proprio:

Code: [Select]
#include <Wire.h>
#include "RTClib.h"

... perché la usa per parlare con il RTC ;)

Guglielmo
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 29, 2019, 05:35 pm
Ora provando a scrivere sulla ram dell'RTC richiamando la libreria WIRE....
Code: [Select]

....
Wire.beginTransmission(0x68); //attiva la comunicazione con il DS1307 all'indirizzo RTC 0x68
Wire.write((byte)0x00); //il primo byte stabilisce il registro iniziale da scrivere i SECONDI da 0x00 a 0x59
Wire.write((byte)0x10); //il secondo byte specifica il tempo  MINUTI da 0x00 a 0x59
Wire.write((byte)0x80 | 0x10); //il terzo byte specifica il tempo  da 0x00 a 0x24
Wire.endTransmission();

Manca il byte di indirizzamento:

Code: [Select]
Wire.beginTransmission(0x68);  //attiva la comunicazione con il DS1307 all'indirizzo RTC 0x68
Wire.write((byte)0x00);        //il primo byte stabilisce il registro iniziale su cui scrivere
Wire.write((byte)0x00);        //il secondo specifica i SECONDI da 0x00 a 0x59 (scritti nel registro 0)
Wire.write((byte)0x10);        //il terzo byte specifica i MINUTI da 0x00 a 0x59 (scritti nel registro 1)
Wire.write((byte)0x80 | 0x10); //il quarto byte specifica le ORE da 0x00 a 0x24 (scritte nel registro 2)
Wire.endTransmission();

La libreria RTClib accede all'RTC usando la WIRE esattamente come stai provando a fare, ma permette un accesso a livello più alto (leggi comodo) senza doversi occupare dei registri dell'RTC e della conversione BCD dei valori. In altre parole i valori nell'RTC sono memorizzati in formato BCD, e se non si effettua una conversione alle 20 leggi 32, alle 12 leggi 18 ecc.


Quote
Mi è venuta in mente l'EEPROM ma io ignoro il 99% delle vie possibili quindi può essere una stupidaggine bella e buona usarla
Se serve mantenere un'informazione anche in caso di mancanza alimentazione/reset non solo è una buona idea ma anche indispensabile. Poi come emerso successivamente l'RTC ha anche lui uno spazio utile (56 byte di RAM) per salvare qualche dato utente. E a seconda del modulino RTC può esserci anche un'ulteriore EEPROM esterna, quindi posti dove salvare le cose ce ne sono in esubero :D

Ma allora oltre a un semplice orario va salvata anche qualche informazione sulla fase in corso, in modo che all'accensione/reset la si possa rileggere e riconoscere, per scegliere il comportamento opportuno.



vorrei tornare sulla struttura di base per cercare di fare un po' di ordine, in primis, nella mia testa.
Mi sono un po' perso anch'io... nel senso che non mi è più totalmente chiara la sequenza (se non sbaglio le 24 ore si dovrebbero aspettare solo al primissimo giro), e non è ancora chiaro come gestire il momento di concimazione più o meno in corrispondenza dell'irrigazione, avevo pensato a una cosa del genere... che prevede anche dei rabbocchi se il bidone perde un po'...
Code: [Select]
case RIPOSO:
    if      (tempo_di_concimare()) { fase = CONCIMAZIONE; }
    else if (ora_di_irrigare())    { fase = IRRIGAZIONE;  }
    else if (!troppo_pieno())      { fase = RIEMPIMENTO;  }
break;

Poi per contare i tempi delle fasi avevo pensato a una funzione 'trascorso'...
Code: [Select]
bool trascorso(unsigned long secondi)
{
    return (millis() - inizio) >= (secondi * 1000);
}

...e "ricaricare" il tempo in 'inizio' ogni volta che la fase cambia, quindi appena dopo lo switch:
Code: [Select]
// ricarica tempo se fase cambiata
if (fase != fase_prec) { fase_prec = fase;  inizio = millis(); }

Dopo di che nelle fasi si può controllare il tempo semplicemente con:
Code: [Select]
if (trascorso(TEMPO_CONCIMAZIONE)) ...
Da notare poi che ragionando per fasi non serve neppure scrivere le varie digitalWrite nei case o nelle funzioni, perché le fasi corrispondono già ai relé da accendere.... nella fase irrigazione acceso solo il relé pompa, in quella riposo nessuno ecc. Quindi le digitalWrite si possono mettere tutte alla fine... se si usa il bistrattato ternario sono quattro righe di numero.
Title: Re: Irrigazione automatica
Post by: karnhack on May 30, 2019, 10:47 am
Se non vi dispiace, mentre continuate le discussioni sugli aspetti di dettaglio, vorrei tornare sulla struttura di base per cercare di fare un po' di ordine, in primis, nella mia testa.
Mi sono un po' perso anch'io... nel senso che non mi è più totalmente chiara la sequenza (se non sbaglio le 24 ore si dovrebbero aspettare solo al primissimo giro), e non è ancora chiaro come gestire il momento di concimazione più o meno in corrispondenza dell'irrigazione ... ...
Occhio che stiamo perdendo pezzi e cioè il post #70. Lo schema è questo sempre se va bene

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310525)

Nel codice ho inserito questo:
Code: [Select]
/*********IMPOSTAZIONE TEMPI Ora Irrigazione E CONCIMAZIONE*********/

int OraIrrigazione[] = {18, 22, 18, 23, 0, 0, 0, 0}; // Ora inizio estivo, ora fine estivo, Ora inizio invernale, ora fine invernale

/***************************************************************/


Praticamente pensavo ad una cosa del genere: è inverno se Mese è Gennaio, Febraio ecc  altrimenti è estate.
Se è estate l'orario è inizio hh[ 0 ] mm[ 1 ] fine hh[ 2 ] mm[ 3 ]
Se è inverno l'orario è inizio hh[ 4 ] mm[ 5 ] fine hh[ 6 ] mm[ 7 ]
Title: Re: Irrigazione automatica
Post by: karnhack on May 30, 2019, 12:57 pm
Al momento ho fatto così per ricavare l'orario e la stagione per quanto riguarda la fase RIPOSO (inserisco solo il codice utile a questa fase)

Code: [Select]

int orario_start = 2;
int orario_stop = 3;
int stagione = 4;
int INVERNALE = 5;
int ESTIVO = 6;

...

int OraIrrigazione[] = {18, 22, 18, 23, 0, 0, 0, 0}; // Ora inizio estivo, ora fine estivo, Ora inizio invernale, ora fine invernale
...

int MESE = now.month();
int INIZIO_ESTIVO = OraIrrigazione[0] * 60 + OraIrrigazione[1];
int FINE_ESTIVO = OraIrrigazione[2] * 60 + OraIrrigazione[3];
int INIZIO_INVERNALE = OraIrrigazione[4] * 60 + OraIrrigazione[5];
int FINE_INVERNALE = OraIrrigazione[6] * 60 + OraIrrigazione[7];

...

    int GENNAIO = now.month() == 1;
    int FEBBRAIO = now.month() == 2;
    int MARZO = now.month() == 3;
    int APRILE = now.month() == 4;
    int MAGGIO = now.month() == 5;
    int GIUGNO = now.month() == 6;
    int LUGLIO = now.month() == 7;
    int AGOSTO = now.month() == 8;
    int SETTEMBRE = now.month() == 9;
    int OTTOBRE = now.month() == 10;
    int NOVEMBRE = now.month() == 11;
    int DICEMBRE = now.month() == 12;

...

 case RIPOSO:
      if ((MESE=GENNAIO) || (MESE=FEBBRAIO) || (MESE=NOVEMBRE) || (MESE=DICEMBRE))
      {
        stagione = INVERNALE;
        orario_start = INIZIO_INVERNALE;
        orario_stop = FINE_INVERNALE;
      }
      else
      {
        stagione = ESTIVO;
        orario_start = INIZIO_ESTIVO;
        orario_stop = FINE_ESTIVO;
      }
        break;
Title: Re: Irrigazione automatica
Post by: karnhack on May 30, 2019, 02:37 pm
Considera che lui ha già (a gratis) le chiamate per leggere e scrivere nella memoria del DS1307, difatti la libreria RTClib, che lui usa, include i seguenti metodi:

Code: [Select]
uint8_t readnvram(uint8_t address);
void readnvram(uint8_t* buf, uint8_t size, uint8_t address);
void writenvram(uint8_t address, uint8_t data);
void writenvram(uint8_t address, uint8_t* buf, uint8_t size);

Guglielmo
@gpb01 Hai un link con esempi? non saprei come usare questo suggerimento

ed ecco che è arrivato il momento della domanda di @Maurotec :)
PS: lo so, la domanda è; da dove spuntano fuori uint8_t, uint16_t ecc?
Title: Re: Irrigazione automatica
Post by: maubarzi on May 30, 2019, 03:13 pm
Occhio che stiamo perdendo pezzi e cioè il post #70. Lo schema è questo sempre se va bene...
Hai distinto solo l'orario di partenza in base alla stagione, giusto?
Questa cosa non necessariamente va schematizzata come uno stato specifico.
Si può fattorizzare dentro una funzione che ti ritorna l'orario di irrigazione giusto in base alla stagione.
Il flusso resta inalterato e dentro questa funzione isoli la logica che restituisce l'orario giusto.

Isoli il problema e lo confini un un posto ben preciso che puoi modificare agilmente in momenti successii mantenendo inalterata la complessità di tutto il resto. Ho spiegato meglio cosa intendo con il termine "fattorizzare".

Invece si potrebbe inglobare il suggerimento di @Claudio_FF che potrebbe semplificare lo schema, intendo questo suggerimento:
Code: [Select]
case RIPOSO:
    if      (tempo_di_concimare()) { fase = CONCIMAZIONE; }
    else if (ora_di_irrigare())    { fase = IRRIGAZIONE;  }
    else if (!troppo_pieno())      { fase = RIEMPIMENTO;  }
break;

Title: Re: Irrigazione automatica
Post by: karnhack on May 30, 2019, 03:23 pm
Invece si potrebbe inglobare il suggerimento di @Claudio_FF che potrebbe semplificare lo schema, intendo questo suggerimento.
@Maurotec scusa mi stai dicendo questa cosa perchè hai visto i post #82 e #83 ?

Perche altrimenti non ho capito...  io intendevo inserire il suggerimento che tu hai citato subito dopo aver ricavato stagione e orari
Code: [Select]
case RIPOSO:
      if ((MESE=GENNAIO) || (MESE=FEBBRAIO) || (MESE=NOVEMBRE) || (MESE=DICEMBRE))
      {
        stagione = INVERNALE;
        orario_start = INIZIO_INVERNALE;
        orario_stop = FINE_INVERNALE;
      }
      else
      {
        stagione = ESTIVO;
        orario_start = INIZIO_ESTIVO;
        orario_stop = FINE_ESTIVO;
      }

// Va ancora avviato !
        break;
Title: Re: Irrigazione automatica
Post by: zoomx on May 30, 2019, 03:50 pm
Si potrebbe anche ricavare l'orario in base al giorno dell'anno di cui si conosce l'ora di alba e tramonto tramite formule.
Title: Re: Irrigazione automatica
Post by: Maurotec on May 30, 2019, 04:57 pm
Non entro nel merito perché non mi intendo di coltivazione, però a me il codice sembra sempre più confuso.

Puoi spiegare nuovamente tutte le fasi manuali, cioè come se le compissi tu manualmente.

Code: [Select]
if ((MESE=GENNAIO) || (MESE=FEBBRAIO) || (MESE=NOVEMBRE) || (MESE=DICEMBRE))

Non usare '=' perché è assegnazione e non eguaglianza '==', quindi,
Code: [Select]

if   (  (MESE==GENNAIO)
     || (MESE==FEBBRAIO)
     || (MESE==NOVEMBRE)
     || (MESE==DICEMBRE) )
{
    // eseguito solo a gennaio, febbraio, novembre e dicembre
}


PS: l'ho scritto cosi per comodità e inoltre non crea problemi al compilatore.

     
Title: Re: Irrigazione automatica
Post by: maubarzi on May 30, 2019, 05:04 pm
@Maurotec scusa ...
Quando scrivi @Maurotec mi sa che intendi me ;) almeno in quest'ultimo post...

...mi stai dicendo questa cosa perchè hai visto i post #82 e #83 ?
Si, ma soprattutto il post di claudio che inglobava alcune fasi del mio schema in un unico test riducendo il numero delle fasi.

Come hai fatto va bene, se ti trovi meglio così e fa quello che ti serve (doppio uguale a parte come spiegato dal vero @Maurotec unico e originale ;) ).
Io suggerivo di mettere tutto dentro una funzione per tenere snello il loop e spostare la complessità fuori, ma fa lo stesso, poco cambia.
L'importante è che ti capisci tu.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 30, 2019, 05:24 pm
Lo schema è questo sempre se va bene
Mi sembra che manchi un riempimento dopo l'irrigazione.




Quote
Code: [Select]
  int GENNAIO = now.month() == 1;
    int FEBBRAIO = now.month() == 2;
    int MARZO = now.month() == 3;
    int APRILE = now.month() == 4;
    ........

Con il codice precedente crei dodici variabili che valgono tutte 0 (false) e una sola 1 (true), per cui il test  successivo non può essere fatto con la variabile MESE che vale da 1 a 12, ma basta usare direttamente il valore booleano di queste variabili:
Code: [Select]
if (GENNAIO || FEBBRAIO || NOVEMBRE || DICEMBRE) ....
Ma allora senza creare tutte quelle variabili bastava anche fare:

Code: [Select]
if ((MESE >= 11) || (MESE <= 2)) ....




Quote
Code: [Select]
  uint8_t readnvram(uint8_t address);
    void readnvram(uint8_t* buf, uint8_t size, uint8_t address);
    void writenvram(uint8_t address, uint8_t data);
    void writenvram(uint8_t address, uint8_t* buf, uint8_t size);

@gpb01 Hai un link con esempi? non saprei come usare questo suggerimento
Quelle sono quattro funzioni, le prime due per leggere rispettivamente un singolo byte o n byte in un colpo solo. Le seconde due uguale ma per scriverlo. Andrebbero usate così:
Code: [Select]
mio_byte = readnvram(indirizzo);
readnvram(buffer, numero_di_byte, indirizzo_inizio);
writenvram(indirizzo, mio_byte);
writenvram(indirizzo_inizio, buffer, numero_di_byte);

dove buffer è un array di byte.




Quote
ed ecco che è arrivato il momento della domanda di @Maurotec :)
Link finale del post #43 e l'intero post #46 ;)




Quote from: maubarzi
Io suggerivo di mettere tutto dentro una funzione per tenere snello il loop e spostare la complessità fuori, ma fa lo stesso, poco cambia.
L'importante è che ti capisci tu.
Infatti, l'idea dell'elaborazione alla stati finiti stretta e della decomposizione funzionale forse "non è passata", ma poco male, comunque schematizzare in fasi va bene, servirà più avanti, l'importante adesso è arrivare a un diagramma di flusso completo e definitivo.... anche se dal punto di vista del flusso abbiamo reintrodotto il goto sotto mentite spoglie :smiley-mr-green:



A karnhack, un esempio di flowchart a fasi/stati è il seguente. Ogni fase (rettangolo blu) è un piccolissimo flow a sé stante che può essere contenuto in un case.

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310569)

Come vedi "senza colpo ferire" aggiungere funzionalità è "banale", ad esempio è previsto un timeout nel riempimento che manda nella fase allarme, da cui si esce premendo un pulsante "pstart". Inoltre ci sono i rabbocchi automatici casomai che con il trascorrere delle ore il livello scenda per qualche motivo.

Ad esempio tradotto in codice il case della concimazione si potrebbe ridurre al seguente. Nota che il case viene eseguito (o dovrebbe essere eseguito) migliaia di volte al secondo perché lo switch si trova all'interno del loop che è già un ciclo che si ripete all'infinito.

Code: [Select]
case CONCIMAZIONE:
    digitalWrite(PIN_PERISTALSI, ACCESO);
    if (trascorso(TEMPO_PERISTALSI))
    {
        digitalWrite(PIN_PERISTALSI, SPENTO);
        fase = AGITAZIONE;
    }
break;
Title: Re: Irrigazione automatica
Post by: maubarzi on May 30, 2019, 06:50 pm
beh, il goto non manca mai, se si guarda sotto il tappeto...
a volte si chiama jmp ma sempre di goto si tratta ;)
... incombe sempre  :smiley-evil:
Title: Re: Irrigazione automatica
Post by: karnhack on May 30, 2019, 07:44 pm
Mi sembra che manchi un riempimento dopo l'irrigazione.
Si è vero manca il riempimento

Inoltre ci sono i rabbocchi automatici casomai che con il trascorrere delle ore il livello scenda per qualche motivo.
No i rabocchi no altrimenti mi rimettono il cloro nell'acqua. Piuttosto aggiungo una fase per la verifica subito dopo la pausa di 24 ore
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 30, 2019, 08:10 pm
Agitare l'acqua aiuta a far evaporare il cloro... ma poi, quanto è grande questo bidone?
Title: Re: Irrigazione automatica
Post by: maubarzi on May 30, 2019, 10:55 pm
Claudio, abbiamo capito che la pausa ci va dopo ogni rabbocco e non solo al primo avvio ;)

Invece, si potrebbe memorizzare quando è stato fatto l'ultimo rabbocco e se non c'è stata irrigazione non fare ulteriori rabbocchi assumendo il bidone ancora pieno, anche se a causa di qualche perdita o all'evaporazione si è andati sotto soglia del troppo pieno.
Servirebbe, per sicurezza, un sensore di troppo vuoto per interrompere l'irrigazione e non rischiare danni alla pompa nel caso di rotture o svuotamenti imprevisti o irrigazione troppo lunga per errori nell'impostazione delle tempistiche varie.
Title: Re: Irrigazione automatica
Post by: karnhack on May 31, 2019, 10:19 am


Quelle sono quattro funzioni, le prime due per leggere rispettivamente un singolo byte o n byte in un colpo solo. Le seconde due uguale ma per scriverlo. Andrebbero usate così:
Code: [Select]
mio_byte = readnvram(indirizzo);
readnvram(buffer, numero_di_byte, indirizzo_inizio);
writenvram(indirizzo, mio_byte);
writenvram(indirizzo_inizio, buffer, numero_di_byte);

dove buffer è un array di byte.
Al momento il mio problema maggiore è scrivere sulla nvram dell'RTC. Non capisco la logica degli indirizzi 0x64, 0x10 ecc. come si ricavano? fin dove arrivano? c'è una specie di schematico per vederli? Questo è il mio maggiore problema.
Per esempio, leggo da uno sketch trovato in rete che gli indirizzi vanno da
Code: [Select]
// DS 1307 storage registers 0x08 to 0x3F
Si ma come faccio a sapere fin quando posso andare avanti?
0x08, 0x09, 0x10, 0x11, 0x12 ... fin dove posso arrivare?
0x3F, 0x4F, 0x5F, 0x6F funziona cosi oppure
0x3f, 0x3G, 0x3H, 0x3I così? come funziona sta logica?

Risolto il problema sopra esposto, io potrei registrare sulla nvram la data e l'ora del primo avvio in modo tale da creare una regola tipo: se è il primo avvio pausa 24 ore altrimenti fai altro

Stessa cosa per quanto riguarda le varie fasi, vorrei mettere a ogni fine fase una sorta di firma da salvare su nvram in questo modo ad ogni inizio fase posso fare un controllo e creare regole... se per esempio è mancata la corrente e non ha potuto irrigare, attraverso questa firma posso bypassare le regole e forzare l'irrigazione
Title: Re: Irrigazione automatica
Post by: gpb01 on May 31, 2019, 10:39 am
Per esempio, leggo da uno sketch trovato in rete che gli indirizzi vanno da
Code: [Select]
// DS 1307 storage registers 0x08 to 0x3F
Te l'ho anche scritto io nel post #66 e ti ho dato anche la mappa degli indirizzi interni del DS1307 ...
... purtroppo, occorre saper leggere i datasheet (... sono li che si trovano tutte le informazioni).   ::)

Giusto per completezza, nel caso ci fossero dubbi, il formato 0xnn indica un numero espresso in base 16 ovvero in esadecimale; invece di scrivere che vanno da 0x08 a 0x3F avrei potuto scrivere, in decimale, che vanno dall'indirizzo 8 all'indirizzo 63.

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on May 31, 2019, 12:39 pm
Giusto per completezza, nel caso ci fossero dubbi, il formato 0xnn indica un numero espresso in base 16 ovvero in esadecimale; invece di scrivere che vanno da 0x08 a 0x3F avrei potuto scrivere, in decimale, che vanno dall'indirizzo 8 all'indirizzo 63.
Ci sono riuscito grazie... non sapendo fosse esadecimale mi immaginavo una cosa tipo "battaglia navale"...
Title: Re: Irrigazione automatica
Post by: docdoc on May 31, 2019, 12:48 pm
Ma allora senza creare tutte quelle variabili bastava anche fare:
Code: [Select]
if ((MESE >= 11) && (MESE <= 2)) ....
Hm, direi che sia meglio:

Code: [Select]
if ((MESE >= 11) || (MESE <= 2)) ....
;)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on May 31, 2019, 05:11 pm
Hm, direi che sia meglio:
Code: [Select]
if ((MESE >= 11) || (MESE <= 2)) ....
Corretto grazie.


Quote from: karnhack
Ci sono riuscito grazie... non sapendo fosse esadecimale mi immaginavo una cosa tipo "battaglia navale"...
Il valore dodici lo puoi scrivere in:
decimale    12
esadecimale 0x0c
binario     0b1100

In ogni caso per la macchina sarà sempre il byte 00001100

Quote from: maubarzi
la pausa ci va dopo ogni rabbocco e non solo al primo avvio
Diciamo che dopo il primo avvio, dopo il successivo rabbocco passa comunque un giorno, salvo nei momenti di cambio irrigazione dalla mattina alla sera o viceversa, che va valutato come gestire... aspettiamo 36 ore?

Quote
per sicurezza, un sensore di troppo vuoto
Ottima osservazione e assolutamente semplice da attuare in quanto basta aggiungere la condizione alla condizione di terminazione dell'irrigazione.

Quote
a volte si chiama jmp ma sempre di goto si tratta ;)
Oh, ma io non l'ho mai demonizzato. Se viene usato per creare strutture e non spaghetti allora anche un programma assembly può essere perfettamente strutturato, anche se non nella sintassi stretta.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 01, 2019, 11:40 am
ho fatto così, ma sono sicuro che la stessa cosa si poteva fare con due righe di codice... ho aggiunto due stati interazione utente e  controllo

Code: [Select]
case INTERAZIONE_UTENTE:
        interazioneUtente();
        break;

      case CONTROLLO:
        RTC.readnvram( 0x08 | 0x0A );        // controllo se l' nvram ha i campi azzerati
        if  (  (RTC.readnvram(0x08) == 00 )  // e se lo sono
            && (RTC.readnvram(0x09) == 00 )
            && (RTC.readnvram(0x0A) == 00 ) )
            {
              RTC.writenvram(0x08, GIORNO);  // li aggiorno
              RTC.writenvram(0x09, MESE);
              RTC.writenvram(0x0A, ADESSO);
              fase = PAUSA_24H;              // e passo alla fase pausa 24 h
            } else
            {
              Serial.println("Riempio/Rabocco...");
              fase = RIEMPIMENTO_RABOCCO;    // se non lo sono passo al riempimento o rabocco
            }
            break;


Interazione utente chiede se è il primo avvio, se lo è riporta la data a 0 e passa alla fase controllo, e nella fase controllo  se trova la data a 0 lo considera un primo avvio/reset altrimenti riempie o rabocca

Code: [Select]
// INTERAZIONE UTENTE

char risposta;
const unsigned long timeout = 15000; // timeout 15 secondi


void interazioneUtente() {
unsigned long inizioTimer; //Inizio timer


   
inizioTimer = millis();

 do{   
    if(Serial.available())
       {
         risposta = Serial.read();  // domanda: primo avvio? resettare?
       
         if(risposta == 's')  // Se SI, salva dati su nvram e pausa 24h
         {
         Serial.println("Resetto data e ora su NVRAM"); // resetta nvram
         RTC.writenvram(0x08, 00);
         RTC.writenvram(0x09, 00);
         RTC.writenvram(0x0A, 00);
         RTC.readnvram(0x08 | 0x0A );
         Serial.print("Giorno: ");
         Serial.print(RTC.readnvram(0x08), DEC);
         Serial.print(' ');
         Serial.print("Mese: ");
         Serial.print(RTC.readnvram(0x09), DEC);
         Serial.print(' ');
         Serial.print("Ora: ");
         Serial.print(RTC.readnvram(0x0A), DEC);
         Serial.println();
         }
       }
  } while (((millis() - inizioTimer) < timeout)); // se timeout scade va alla fase controllo
 
Serial.println("Verifico...");
delay(3000);
fase = CONTROLLO;
}


Almeno ho capito un po di cose... per esempio che non esistono solo void loop e setup.  Poi se non ho capito male qualsiasi timeout che non sia un delay deve stare fuori il void loop... o sbaglio?
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 01, 2019, 06:46 pm
Questa istruzione mi sembra non abbia senso, equivale a leggere un byte dalla cella dieci della nvram e scartare il risultato:
Code: [Select]
RTC.readnvram( 0x08 | 0x0A );

Quote
se non ho capito male qualsiasi timeout che non sia un delay deve stare fuori il void loop... o sbaglio?
Se scrivi codice procedurale bloccante (quello che stai facendo, nonostante la struttura a fasi che permetterebbe di evitarlo) allora qualsiasi tipo di verifica dei tempi va bene dappertutto, compreso delay.
Se invece scrivi codice a stati non bloccante allora il delay non va messo da nessuna parte e va usato solo millis (o i secondi letti dall'RTC)... ma allora non vanno neppure scritti cicli while/ for ecc che blocchino l'esecuzione generale.
Per come stai impostando l'esecuzione usa pure liberamente delay e millis dove ti pare, ma sappi che non potrai controllare più di una operazione alla volta (ad esempio non potrai far lampeggiare un LED indipendente dalle fasi in corso).

Come esempio questi sono due flussi dell'interazione utente. A sinistra c'è il tuo (bloccante), a destra l'equivalente non bloccante che sfrutta il fatto che il loop è già di suo un ciclo che si ripete all'infinito:

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310845)

E dirai, che differenza c'è? Sempre al controllo available si torna.
Vero, ma a sinistra scrivi un loop esplicito (do/while) e finché non termina non si può fare altro.
A destra invece finisce il case, finisce lo switch, e si prosegue con il loop. Il loop è già un ciclo, e al prossimo giro "riparte" lo switch, "riparte" il case e si torna ovviamente all' available di prima, ma nel frattempo (uscendo dallo switch e rientrandoci) nel loop si possono fare anche altre cose, ad esempio gestire altri tre switch che controllano altri tre irrigatori in parallelo o qualsiasi altra cosa.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 02, 2019, 09:38 am
Ok, alla fine ho risolto con un while (finchè il timer non scade, se digiti S fai questo, altrimenti passa a fase).
Ci cono molti serial print perchè mi aiutano a capire tramite serial monitor se la condizione ha funzionato, ma poi rimarranno solo gli indispensabili:

Code: [Select]
// INTERAZIONE UTENTE

char risposta;
const unsigned long timeout = 10000; // timeout 10 secondi


void interazioneUtente() {
unsigned long inizioTimer; //Inizio timer
 
inizioTimer = millis();

while (((millis() - inizioTimer) < timeout))
      {
      if(Serial.available())
         {
         risposta = Serial.read();  // domanda: primo avvio? resettare?
      
         if(risposta == 's')  // Se SI, salva dati su nvram e pausa 24h
         {
         Serial.println("Resetto data e ora su NVRAM"); // resetta nvram e scrive 00
         RTC.writenvram(0x08, 00);  // nvram interazione
         RTC.writenvram(0x09, 00);
         RTC.writenvram(0x0A, 00);
        
         RTC.writenvram(0x0B, 00);  // nvram primo innaffio dopo 24 h
         RTC.writenvram(0x0C, 00);
         RTC.writenvram(0x0d, 00);
        
         Serial.print("Giorno: ");
         Serial.print(RTC.readnvram(0x08), DEC);
         Serial.print(' ');
         Serial.print("Mese: ");
         Serial.print(RTC.readnvram(0x09), DEC);
         Serial.print(' ');
         Serial.print("Ora: ");
         Serial.print(RTC.readnvram(0x0A), DEC);
         Serial.println();
         }
         }
      }
      {
         Serial.println("Controllo...");
         fase = CONTROLLO;  
      }
}
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 02, 2019, 11:43 am
Non puoi salvare la variabile a 16 bit 'adesso' in un solo byte della nvram. Servono due byte di nvram, in uno si scrivono gli 8 bit bassi e nell'altro gli 8 bit alti della variabile:

Code: [Select]
RTC.writenvram(addr, lowByte(adesso));
RTC.writenvram(addr+1, highByte(adesso));

Per rileggere il valore bisogna ricomporre i due byte in un valore a 16 bit:

Code: [Select]
adesso = RTC.readnvram(addr) | (RTC.readnvram(addr+1) << 8);


(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310913)
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 02, 2019, 11:57 am
Non puoi salvare la variabile a 16 bit 'adesso' in un solo byte della nvram
Ti riferisci allo stato RIPOSO e cioè questo?:
Code: [Select]
if  (  (RTC.readnvram(0x0B) == GIORNO )  // se il giorno nvram è uguale a giorno rtc
          && (RTC.readnvram(0x0C) == MESE )    // e se il mese nvram è uguale al mese rtc
          && (ADESSO == orario_start )  )      // e se adesso è uguale ad orario start
          {
            fase = IRRIGAZIONE;
          }
          {
            fase = RIPOSO;
          }


Non so se sto procedendo bene ma non volevo salvare ADESSO nella nvram. In pratica volevo fare:

 SE giorno nvram è uguale a GIORNO (dove nel NVRAM sta scritto il giorno futuro in cui dovrà irrigare)
 e SE mese nvram è uguale a MESE (dove nel NVRAM sta scritto il mese futuro in cui dovrà irrigare)
 e SE ADESSO è uguale ad orario_start (dove orario_start non viene preso da nvram ma dal calcolo se è inverno o estate e dunque se deve irrigare all'ora 1 o 2)

SE tutte le condizioni sopra sono SI vai a IRRIGAZIONE altrimenti RIPOSO. E va ancora aggiunta la condizione per la concimazione.... sono indeciso se cancellare tutto e ripartire da capo o no...
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 02, 2019, 12:00 pm
Mi riferisco a:
Code: [Select]
RTC.writenvram(0x0A, ADESSO);
Per il resto nella tua logica mi sto perdendo... per me una fase è uno stato in cui si rimane per un certo tempo, e la fase finisce quando avviene qualcosa (un timeout, un segnale esterno ecc). Per dire la PAUSA_24H secondo me dovrebbe essere una semplice attesa di 24 ore (fatta con millis o delay si ha un errore di due minuti).
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 02, 2019, 12:35 pm
Per il resto nella tua logica mi sto perdendo... per me una fase è uno stato in cui si rimane per un certo tempo, e la fase finisce quando avviene qualcosa (un timeout, un segnale esterno ecc). Per dire la PAUSA_24H secondo me dovrebbe essere una semplice attesa di 24 ore (fatta con millis o delay si ha un errore di due minuti).
Si perchè non conoscendo "gli attrezzi" a priori li scopro e provo quando mi servono e di conseguenza tra un operazione e l'altra ci sono differenze di logica.

Nella pausa 24 ore stavo cercando di capire come evitare il delay e sono capitato su millis. Ma avendo l'RTC è da stupidi fare come ho fatto... ora la modifico... a dire il vero trovo difficoltà a disegnarmi gli schemi logici come fai tu e sto provando a farne uno completo, se mi riesce credo che ricomincio d'accapo. Ma c'è un simbolo che distingue il while dall'if?
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 02, 2019, 06:14 pm
Ma c'è un simbolo che distingue il while dall'if?
No, si riconosce dalla freccia che torna indietro. In un while cè sempre un if implicito e un ritorno indietro.

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=310955)

E poi ricominciare da capo anche più volte non è una cattiva idea, a volte meglio rifare che cercare di adattare a tutti i costi qualcosa partito storto.

I miei miniflow sono comprensibili solo partendo dal presupposto spiegato alla fine dal post #101, e cioè che non serve nessun while perché il loop è già un ciclo, e si continua a uscire e rientrare velocemente nel case attualmente "attivo" (identificato dal valore della variabile fase).

La pausa 24 ore potrebbe semplicemente essere:

Code: [Select]
case PAUSA_24H:
    if ((millis() - tempo_inizio) >= UNGIORNO) { fase = ...prossima fase...; }
break;

Oppure scritta in modo bloccante:

Code: [Select]
case PAUSA_24H:
    delay(UNGIORNO);
    fase = ...prossima fase...;
break;

...oppure con una variabile contatore si potrebbero contare i minuti scanditi dall'RTC, arrivati a 1440 è passato un giorno... i sistemi sono tanti.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 02, 2019, 07:06 pm
Sto cercando una soluzione per gestire le pause in un unico modo e su tutte le fasi che necessitano di pausa:

Code: [Select]

  DateTime now = RTC.now();
  DateTime futuro (now + TimeSpan(0,0,0,15)); // Ritardo 15s (dd,hh,mm,ss)
  byte adesso[] = { now.hour(),now.minute(),now.second() };
  byte ritardo[] = { futuro.hour(),futuro.minute(),futuro.second() };
  byte oreFuture = futuro.hour();
  byte minutiFuturi = futuro.minute();
  byte secondiFuturi = futuro.second();

  if/while (adesso == adesso[oreFuture,minutiFuturi,secondiFuturi]) //regola per le pause
        {
   
        }


In questo modo tramite il TimeSpan(0,0,0,0)) dovrei riuscire ad impostare le pause e quindi

TimeSpan(0,0,0,15)) : Pausa 15 sec  (per interazione utente)
TimeSpan(0,24,0,0)) : Pausa 24h      (per decantazione acqua)
TimeSpan(40,0,0,0)) : Pausa 40gg    (tra una concimazione e l'altra)

Sempre che accetti valori oltre al mese...
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 02, 2019, 07:23 pm
Code: [Select]
 // calcolo di un tempo di arrivo (non conosco DateTime non so se si puo` fare)
  DateTime now = RTC.now();
  DateTime arrivo (now + TimeSpan(0,0,0,15)); // Ritardo 15s (dd,hh,mm,ss)

Code: [Select]
 // tempo attuale
  DateTime now = RTC.now();

Code: [Select]
 // se ore minuti e secondi coincidono
  if ( (now.hour() == arrivo.hour())
       && (now.minute() == arrivo.minute())
       && (now.second() == arrivo.second()) ) { ..... }

Ma per tempi di pochi secondi alcuni minuti userei senz'altro millis...
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 02, 2019, 09:39 pm
Per oggi mi arrendo, sembravo vicino alla fine ed ora mi accorgo che non parte più il riempimento... mi tocca ricontrollare tutto. Pensavo fosse un contatto del pin ma se lo leggo  restituisce 0 e 1, quindi non so proprio perchè non parte. Le fasi le attraversa tutte fino a CONTROLLO... controllo lo esegue fino alla fine e mi dice che sta passando alla fase RIEMPIMENTO_RABOCCO ma in pratica non ci passa... :smiley-small:
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 03, 2019, 03:44 am
Con questa struttura switch per gestire la macchina a stati (o a fasi) c'è l'inconveniente che alle volte vogliamo
eseguire del codice solo all'ingresso dello stato (fase).

Ad esempio qui,
Code: [Select]

case RIPOSO:
      Serial.println("Fase: RIPOSO");

Fintanto che rimane in questa fase stamperà nel serial monitor la stringa: Fase: RIPOSO.

Avevo accennato in precedenza di questo inconveniente e come aggirarlo, forse ora è il caso di provvedere.

Il codice seguente non è arduinesco ma codice che gira sul PC, tuttavia lo considero valido a patto di sostituire tutti
i printf con serial.println().

Al posto della funzione loop() c'è un while(endloop)

Code: [Select]

#include <stdio.h>
#include <stdint.h>

// fasi della fsm (Finite State Machine)
#define RIEMPIMENTO_RABOCCO 1   // verifica se il bidone è pieno
                               // o vuoto, se è pieno passa alla fase
                                // successiva, se è vuoto lo riempie e poi passa oltre
#define INTERAZIONE_UTENTE 0

// crea delle comode macro autodocumntanti per gestire la fsm
#define FSM_UPDATE() (oldFase = fase)
#define FSM_ON_SWITCH() (oldFase != fase)

// definisce il tipo fsm_t a partire da tipo base uint8_t (il valore è riservato 254)
typedef uint8_t fsm_t;

// inizializza fase e oldFase a valori differenti
fsm_t fase = INTERAZIONE_UTENTE;
fsm_t oldFase = 255;

fsm_t endloop = 1;      // termina il while endloop == 0

uint8_t counter = 0;    // semplice contatore

int main()
{
    while (endloop) {
        switch (fase) {
        case INTERAZIONE_UTENTE:
            if (counter<255)  {
                counter++;
            }
            // questa printf viene eseguita una sola volta all'ingresso di questo stato
            if (FSM_ON_SWITCH()) {
                printf("INTERAZIONE_UTENTE\t");
                FSM_UPDATE();   // importante aggiorna la fsm
            }
            if (counter == 255) {
                printf("counter = %u\n", counter);
                counter = 0;
                fase = RIEMPIMENTO_RABOCCO;
            }
            break;

        case RIEMPIMENTO_RABOCCO:
            if (counter<255)  {
                counter++;
            }
            if (FSM_ON_SWITCH()) {
                printf("RIEMPIMENTO_RABOCCO\t");
                FSM_UPDATE();
            }
            // dimostra che RIEMPIMENTO_RABOCCO viene stampato una sola volta
            // infatti counter arriva a 255
            if (counter == 255) {
                printf("counter = %u\n", counter);
                endloop = 0; // esce da while restituendo il controllo al sistema operativo
            }
            break;

        } // end switch
    } // end while

    return 0;
}



I nomi usati per variabile e macro sono i primi che mi sono venuti in mente e pertanto se possono trovare altri
più calzanti (autodocumentanti).

Il codice stampa la seguente:

INTERAZIONE_UTENTE counter = 255
RIEMPIMENTO_RABOCCO counter = 255


Il fatto che counter sia uguale a 255 conferma il comportamento desiderato.

Il trucco sta nelle due variabili di stato fase e oldFase e a come li usiamo.

PS: questo espediente può essere impiegato anche per stampare su un display una maschera dati.
PS1: c'è anche un esempio di impiego di typedef,  

Altra cosa riguardo allo switch di stato (fase) prematuro. Prendo un pezzo del codice per esempio,

Code: [Select]

     case CONTROLLO:
        Serial.println("Fase: CONTROLLO");
        // controllo se l' nvram ha i campi azzerati
        adessoNVRAM = RTC.readnvram(0x0A) | ( RTC.readnvram(0x0A+1) << 8);
       
        if  (  (RTC.readnvram(0x08) == 00 )  // e se lo sono
            && (RTC.readnvram(0x09) == 00 )
            && (adessoNVRAM == 0000 ) )
            {
              RTC.writenvram(0x08, GIORNO);  // li aggiorno
              RTC.writenvram(0x09, MESE);
              RTC.writenvram(0x0A, lowByte(ADESSO));
              RTC.writenvram(0x0A + 1, highByte(ADESSO));
              Serial.println("Passo alla fase: PAUSA 24H");
              fase = PAUSA_24H;              // e passo alla fase pausa 24 h
              // ok se al posto dell'else ci fosse stato altro codice che qui hai deciso di non eseguire,
              // già qui puoi inserire un altro break
              // break;
            }
            else
            {
              Serial.println("Passo alla fase: RIEMPIMENTO / RABOCCO");
              fase = RIEMPIMENTO_RABOCCO; // se non lo sono passo al riempimento o rabocco
            }
            break;


Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 12:02 pm
Code: [Select]

#include <stdio.h>
#include <stdint.h>

// fasi della fsm (Finite State Machine)
#define RIEMPIMENTO_RABOCCO 1   // verifica se il bidone è pieno
                               // o vuoto, se è pieno passa alla fase
                                // successiva, se è vuoto lo riempie e poi passa oltre
#define INTERAZIONE_UTENTE 0

// crea delle comode macro autodocumntanti per gestire la fsm
#define FSM_UPDATE() (oldFase = fase)
#define FSM_ON_SWITCH() (oldFase != fase)

// definisce il tipo fsm_t a partire da tipo base uint8_t (il valore è riservato 254)
typedef uint8_t fsm_t;

// inizializza fase e oldFase a valori differenti
fsm_t fase = INTERAZIONE_UTENTE;
fsm_t oldFase = 255;

fsm_t endloop = 1;      // termina il while endloop == 0

uint8_t counter = 0;    // semplice contatore

int main()
{
    while (endloop) {
        switch (fase) {
        case INTERAZIONE_UTENTE:
            if (counter<255)  {
                counter++;
            }
            // questa printf viene eseguita una sola volta all'ingresso di questo stato
            if (FSM_ON_SWITCH()) {
                printf("INTERAZIONE_UTENTE\t");
                FSM_UPDATE();   // importante aggiorna la fsm
            }
            if (counter == 255) {
                printf("counter = %u\n", counter);
                counter = 0;
                fase = RIEMPIMENTO_RABOCCO;
            }
            break;

        case RIEMPIMENTO_RABOCCO:
            if (counter<255)  {
                counter++;
            }
            if (FSM_ON_SWITCH()) {
                printf("RIEMPIMENTO_RABOCCO\t");
                FSM_UPDATE();
            }
            // dimostra che RIEMPIMENTO_RABOCCO viene stampato una sola volta
            // infatti counter arriva a 255
            if (counter == 255) {
                printf("counter = %u\n", counter);
                endloop = 0; // esce da while restituendo il controllo al sistema operativo
            }
            break;

        } // end switch
    } // end while

    return 0;
}

Sto provando a capirci qualcosa ma ricevo degli errori su questa linea:
Code: [Select]
Serial.println("counter = %u\n", counter);
l'errore è:
Code: [Select]

conversion of argument 1 would be ill-formed:
candidate: size_t Print::println(long unsigned int, int) <near match>
     size_t println(unsigned long, int = DEC);


Non capisco se l'errore c'è a prescindere da come sto provando ad utilizzare il codice. Poi altra cosa che non capisco è il fatto che sia int main() cosa vuol dire? che sto dichiarando una variabile e quindi va inserito nel loop o fuori? Troppa carne sul fuoco comincio a non capirci nulla...  :(
Title: Re: Irrigazione automatica
Post by: Standardoil on Jun 03, 2019, 12:09 pm
Per lo OP
Ma le tue specifiche di funzionamento sono le stesse del primo post?
Scusa ma non mi metto a leggere 8 pagine di discussione
Ci sono state modifiche nella logica di funzionamento originale?
Title: Re: Irrigazione automatica
Post by: gpb01 on Jun 03, 2019, 12:13 pm
Sto provando a capirci qualcosa ma ricevo degli errori su questa linea:
Code: [Select]
Serial.println("counter = %u\n", counter);
... ma dove hai letto che la classe Serial ed i metodi print e prinln supportano la formattazione della sprinf() ? ? ? :o

Se vuoi usare quella sintassi, devi crearti una variabile d'appoggio di tipo char array e riempirla con la sprintf() e DOPO stamparla con la Serial.prinln().

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 12:24 pm
... ma dove hai letto che la classe Serial ed i metodi print e prinln supportano la formattazione della sprinf() ? ? ? :o

Se vuoi usare quella sintassi, devi crearti una variabile d'appoggio di tipo char array e riempirla con la sprintf() e DOPO stamparla con la Serial.prinln().

Guglielmo
Allora a parte il primo case INTERAZIONE_UTENTE non è che abbia tanto l'esigenza di scrivere sul seriale... lo stavo usando solo come spia per capire se si passava alla fase successiva o no e quindi ho fatto così:
Code: [Select]
case IRRIGAZIONE:
      Serial.println("Irrigazione:");
        // istruzioni c
        break;


Ma ripeto era  solo per capire se aveva cambiato stato o no... l'ho fatto per tutte le fasi ma ieri sera si è bloccato, non riesce più a passare alla fase RIEMPIMENTO_RABOCCO, che tra l'altro è stata la prima che ho scritto e la prima a funzionare...
Dopo il blocco ho postato  #110 ed allegato il codice e @Maurotec ma ha gentilmente risposto consigliandomi delle soluzioni... non vorrei però ficcarmi in una via senza uscita visto che ho una comprensione molto limitata in questo campo.
Il mio problema attuale è che non passa alla fase RIEMPIMENTO_RABOCCO, il perchè non ci passa non lo so.
Title: Re: Irrigazione automatica
Post by: Standardoil on Jun 03, 2019, 12:33 pm
Sì,  ma le prescrizioni?
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 12:36 pm
Sì,  ma le prescrizioni?
Cioè? cosa sono le prescrizioni?  :o
Title: Re: Irrigazione automatica
Post by: Standardoil on Jun 03, 2019, 12:37 pm
Cosa vuoi ottenne
Ben dettagliato
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 03, 2019, 01:47 pm
Quote
Dopo il blocco ho postato  #110 ed allegato il codice e @Maurotec ma ha gentilmente risposto consigliandomi delle soluzioni... non vorrei però ficcarmi in una via senza uscita visto che ho una comprensione molto limitata in questo campo.
Malinteso ci fù, non era mia intenzione fornire una soluzione al problema specifico.
Inoltre ci sono parti di codice che non riesco proprio a seguire.

Il mio intento era quello di mostrare quello che Claudio e gli altri ti hanno descritto in riferimento al while, così da aggiungere un esempio e qualche freccia in più al tuo arco.  ;)

Per testare il codice non avevo arduino e lo fatto con il PC, ora mi rendo conto che non basta dire di sostituire printf con serial.print.  :)

Qui di seguito la versione arduinesca, non testata. Posto solo la funzione loop(), (la setup la aggiungi tu) che sostituisce int main () ecc.

Code: [Select]

void loop() {
    while (endloop) {
        switch (fase) {
        case INTERAZIONE_UTENTE:
            if (counter<255)  {
                counter++;
            }
            // questa printf viene eseguita una sola volta all'ingresso di questo stato
            if (FSM_ON_SWITCH()) {
                serial.print("INTERAZIONE_UTENTE\t");
                FSM_UPDATE();   // importante aggiorna la fsm
            }
            if (counter == 255) {
                //printf("counter = %u\n", counter);
                serial.print("counter = ");
                serial.println(counter);
                counter = 0;
                fase = RIEMPIMENTO_RABOCCO;
            }
            break;

        case RIEMPIMENTO_RABOCCO:
            if (counter<255)  {
                counter++;
            }
            if (FSM_ON_SWITCH()) {
                serial.print("RIEMPIMENTO_RABOCCO\t");
                FSM_UPDATE();
            }
            // dimostra che RIEMPIMENTO_RABOCCO viene stampato una sola volta
            // infatti counter arriva a 255
            if (counter == 255) {
                //printf("counter = %u\n", counter);
                serial.print("counter = ");
                serial.println(counter);
                endloop = 0; // esce da while restituendo il controllo al sistema operativo
            }
            break;

        } // end switch
    } // end while
    serial.println("Fine programma.\n");
    while(1); // la funzione loop non termina mai
}


\t tabulazione
\n nuova linea

Nel post precedente ho preso la seguente riga come esempio di codice che si vuole eseguire una sola volta all'ingresso
dello stato.

Code: [Select]

case RIPOSO:
      Serial.println("Fase: RIPOSO");


PS: Il mio intervento non è specifico ma genericamente non legato alla anomalia che riscontri.

Ciao.
 
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 02:58 pm
Cosa vuoi ottenne
Ben dettagliato
Spero cosi si capisca

Code: [Select]

switch (fase)
 {

   case INTERAZIONE_UTENTE:
   Viene chiesto se è il primo avvio o se si vuole resettare.
   Se è il primo avvio/reset viene scritto 0 sulla nvram1 e passa
   alla fase CONTROLLO. Se non è il primo avvio e il timeout scade
   passa alla fase CONTROLLO
   break;

   case CONTROLLO:
   Controlla se nvram1 è 0, se lo è prende la data attuale la scrive
   su nvram1 e passa a PAUSA_24H. Mentre se sulla nvram1
   c'è una data (non è 0) passa a RIEMPIMENTO_RABOCCO
   break;

   case PAUSA_24H:
Stabilisce se è estate o inverno ed in base alla stagione restituisce due tipi di orario di irrigazione.
   Imposta una pausa di 24ore e scrive su nvram2 la prossima
   data di prima irrigazione. Poi passa a fase RIPOSO;
   break;

   case RIEMPIMENTO_RABOCCO:
   Si occupa del riempimento della tanica dunque lascia l'elettrovalvola aperta
   finchè il sensore del troppopieno è aperto. Poi passa alla fase RIPOSO
   break;

   case RIPOSO:
   Attende l'orario nvram2 d' irrigazione per la prima irrigazione  (manca ancora la di concimazione ogni 40 gg)
   break;

   case CONCIMAZIONE:
   Avvia pompa peristaltica per prelevare il concime e mette in moto l' agitatore
   break;

   case IRRIGAZIONE:
   Avvia la pompa per xx secondi
   break;



Riallego il file dove ho fatto altre modifiche da stamattina.
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 03, 2019, 03:56 pm
Code: [Select]

if  (  (RTC.readnvram(0x0C) == GIORNO )  // se il giorno nvram2 è uguale a giorno rtc
          && (RTC.readnvram(0x0D) == MESE )    // e se il mese nvram2 è uguale al mese rtc
          && (adessoNVRAM2== ADESSO )  )      // e se adesso nvram2 è uguale ad adesso rtc
          {
            fase = IRRIGAZIONE;
          }
          {
            fase = RIPOSO;
          }
        delay(1000);

Manca l'else
Code: [Select]

if  (  (RTC.readnvram(0x0C) == GIORNO )  // se il giorno nvram2 è uguale a giorno rtc
          && (RTC.readnvram(0x0D) == MESE )    // e se il mese nvram2 è uguale al mese rtc
          && (adessoNVRAM2== ADESSO )  )      // e se adesso nvram2 è uguale ad adesso rtc
          {
            fase = IRRIGAZIONE;
          } else  {
            fase = RIPOSO;
          }
        delay(1000);


Quanto rompe sto delay, se non ci fosse basterebbe
Code: [Select]
if  (  (RTC.readnvram(0x0C) == GIORNO )  // se il giorno nvram2 è uguale a giorno rtc
          && (RTC.readnvram(0x0D) == MESE )    // e se il mese nvram2 è uguale al mese rtc
          && (adessoNVRAM2== ADESSO )  )      // e se adesso nvram2 è uguale ad adesso rtc
{
    fase = IRRIGAZIONE;
    break;
}

fase = RIPOSO;
break;


Ciao.




Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 04:00 pm
Code: [Select]


Quanto rompe sto delay, se non ci fosse basterebbe
[code]if  (  (RTC.readnvram(0x0C) == GIORNO )  // se il giorno nvram2 è uguale a giorno rtc
          && (RTC.readnvram(0x0D) == MESE )    // e se il mese nvram2 è uguale al mese rtc
          && (adessoNVRAM2== ADESSO )  )      // e se adesso nvram2 è uguale ad adesso rtc
{
    fase = IRRIGAZIONE;
    break;
}

fase = RIPOSO;
break;

[/code]
L'avevo già tolto, ho ricaricato il file subito dopo  :D
Sto provando a togliere tutto l'inutile
Title: Re: Irrigazione automatica
Post by: Federico66 on Jun 03, 2019, 04:34 pm
[OT]

Scusate l'intromissione OT, ma trovo questo thread (letto per curiosità) un ottimo esempio su come dovrebbe essere strutturata una richiesta d'aiuto da parte di chi è alle prime armi, ma non solo, di come dovrebbe partecipare alla discussione: essere presente (il più delle volte spariscono), non avere fretta di risolvere, quindi studiare, cercare di capire e testare le soluzioni proposte, essere propositivi.
Dall'altra parte, complimenti a tutti i partecipanti, in pochi forum, si nota una tale pazienza ed una chiara volontà all'insegnamento (perchè di questo si tratta).

Questo thread, inoltre, ha il pregio di essere un vero tutorial (almeno la prima parte) per chi volesse affrontare seriamente un qualunque progetto con Arduino (ma non solo) ed inoltre, leggendolo si ricavano informazioni di base utilissime a chi è agli inizi.
Grazie anche da parte mia, non mi interezza l'irrigazione, ma continuerò a seguirlo :)

Federico
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 03, 2019, 05:20 pm
A modo mio ho sistemato un poco di cose per migliorare la leggibilità, ma molto c'è ancora da fare.
Sarebbe comodo spostare le macro (#define ecc) in un file ino separato, come pure le funzioni utente.

Allego IRRORino-0.2.1-mtec.

Modifiche
macro:
   GEN, FEB ecc
Funzioni:
   isWinter( uint8_t mese )

PS: Prima di allegare usa CTRL-T per formattare il codice.

Ciao.
Title: Re: Irrigazione automatica
Post by: Standardoil on Jun 03, 2019, 05:45 pm
Per federico 66
concordo con te sulle prime pagine, ma poi questa discussione si è allargata troppo, an chi in considerazione dell'esperienza dello OP
Adesso siamo a mettere le define in file separati, secondo me troppo
Se dopo oltre otto pagine il cavallo è ancora azzoppato è  ora di abbatterlo e crearne uno nuovo, sano robusto e giovane
Io propongo (restando su cose facili, solo array no strutture ) un array di 12 elementi con le ore di start
Il numero del mese è direttamente l'indice  dello array
Avvio con Un if su rtc
Un secondo array coi tempi di erogazione, stop con un banale delay pilotato dallo array
Al termine si apre elettrovalvola while not  sensore (sempre pensare easy)
Banalmente un delay per far scattare l'ora ed evitare la ripetizione
In tutto questo manca il fertilizzante
Ora, delle due l'una
O è fertilizzato l'intero bidone, oppure la sola prima irrigazione del mese
Caso 1
All'apertura della valvola di carico si avvia la pompa peristaltica, che scarica nel 'tubo' di carico, la miscelazione è garantita dal moto turbolento dell'acqua  nel tubo
Caso 2
Uguale, ma nel tubo di scarico durante l'erogazione
Ci vuole meno a scriverlo che a dirlo...
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 06:32 pm
Sarebbe comodo spostare le macro (#define ecc) in un file ino separato, come pure le funzioni utente.
Guarda stavo giusto indagando su questo, anche perchè il fatto di non lavorare a settori separati mi incasina e a volte vado su è giù nel codice senza un motivo.  In pratica stavo guardando com'è fatto il fw della stampante 3d e stavo cercando di replicarlo per provare a suddividere il codice... ovvero un file IRROrino.ino

Code: [Select]
#include "IRRORino.h"

void setup() {
 
}

void loop() {
 
}


poi un file IRROrino.h che è l'elenco dei file, e include le librerie arduino.h e pins.arduino.h e gli altri file

Code: [Select]
#include "Arduino.h"
#include "pins_arduino.h"

/**
 * Include file
 */
#include "src/1.h"


Poi in pratica nel file 1.h dovrebbero andarci... non ho capito bene, a parte il richiamo a
Code: [Select]
#include "../IRRORino.h"

Infine c'è il file 1.cpp che per quello che ho capito è l'eseguibile dove va scritto il codice
Code: [Select]
#include "../IRRORino.h"

#include <Wire.h>
#include <RTClib.h>

#include "1.h"

// qui va il codice


Era una prova così tanto per provare, non l'avrei neanche scritta sul forum ma visto che l'hai nominata...  :D
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 03, 2019, 07:33 pm
Caso 1
All'apertura della valvola di carico si avvia la pompa peristaltica, che scarica nel 'tubo' di carico, la miscelazione è garantita dal moto turbolento dell'acqua  nel tubo
Il Caso 1 è l'ideale

Ci vuole meno a scriverlo che a dirlo...
Ci vuole meno a farselo da soli che a farlo capire... ed anche questo lo so in quanto essere bipede abitante abitante di questo pianeta.  :)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 03, 2019, 07:58 pm
Il Caso 1 è l'ideale
Non so mica... se l'acqua deve poi decantare per 24 ore... con il fertilizzante dentro?



Quote from: Standardoil
Se dopo oltre otto pagine il cavallo è ancora azzoppato è  ora di abbatterlo e crearne uno nuovo, sano robusto e giovane
Io per ulteriori consigli attendo di vedere che piega prende "il flusso"...



Quote from: Maurotec
Fintanto che rimane in questa fase stamperà nel serial monitor la stringa: Fase: RIPOSO. Avevo accennato in precedenza di questo inconveniente e come aggirarlo, forse ora è il caso di provvedere.
Allora si può rendere ancora più semplice e comodo:
Code: [Select]
byte     fase = PRIMAFASE;  // fase iniziale
byte     old_fase = ~fase;
bool     first_pass;  // vera un ciclo quando una fase diventa attiva
uint32_t inizio_fase; // tempo di inizio fase
uint32_t trascorso;   // secondi trascorsi da attivazione fase

Code: [Select]
first_pass = false;
if (fase != old_fase) { first_pass = true;  inizio_fase = millis(); }
old_fase = fase;
trascorso = (millis() - inizio_fase) / 1000;

switch (fase)
{
    case PRIMAFASE:
        if (first_pass) { ..operaz. eseguite una sola volta... }
        if (trascorso >= 10) { ..operaz. eseguite dopo 10 sec.. }
        ...operaz.eseguite sempre...
    break;
}
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 03, 2019, 08:39 pm
Quote
Allora si può rendere ancora più semplice e comodo:
Si ho capito cosa intendi, non è che si può, si deve. :)

Vediamo come @karnhack digerisce quanto fin qui esposto.

Inoltre ci sarebbe da nascondere i dettagli dentro le funzioni,anziché scrivere if interminabili (e poco comprensibili), anche quello che hai postato tu, andrebbe implementato nascondendo la complessità dentro le funzioni. Tuttavia io non devo irrigare nulla e stiamo procedendo passo passo, fornendo tanti spunti che poi karnhack è libero di implementare, ma gli dobbiamo dare tempo.

Ciao.


Title: Re: Irrigazione automatica
Post by: karnhack on Jun 04, 2019, 11:07 am
Non so mica... se l'acqua deve poi decantare per 24 ore... con il fertilizzante dentro?
Hai ragione non ci avevo pensato, la concimazione va fatta subito prima dell'innaffiatura.

Vediamo come @karnhack digerisce quanto fin qui esposto.
Io sto cercando di capire il materiale che mi avete fornito, però se devo dire la verità sto procedendo alla cieca nel senso che non ho capito perche il flusso si blocca... se riuscissi a capire questo, probabilmente sarei più avvantaggiato nel capire gli altri suggerimenti, sempre che centrino col problema. Anche perchè se  elimino tutti i Serial.println il flusso non funziona lo stesso
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 04, 2019, 05:02 pm
Pare che ne sono uscito!   :smiley-mr-green:
Ho riscritto quasi tutto d'accapo...

Le fasi concimazione ed irrigazione per ora le ho fatte alla meno peggio, mi sarebbe utile capire se il cavallo è ancora zoppo o se ci sono speranze di guarigione. Grazie ancora per la disponibilità
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 04, 2019, 05:34 pm
Prima di continuare... lo sai che 0x0A+1 equivale a 0x0B ?
Mi pare che stai usando la stessa cella undici per due scopi contemporaneamente.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 04, 2019, 06:11 pm
Prima di continuare... lo sai che 0x0A+1 equivale a 0x0B ?
Mi pare che stai usando la stessa cella undici per due scopi contemporaneamente.
Ok grazie, inoltre ci sono altri errori ho messo alcune cose fuori dal loop e andavano dentro...

Ora sembra che vada, ogni stato assegna una data futura nella nvram,  e lo stato RIPOSO non fa altro che aspettare quella data che trova scritta sulla nvram.  Dopo aver irrigato scrive su nvram la prossima data di irrigazione, dopo aver concimato uguale su due settori a parte. Così il problema dovrebbe esserci solo se manca la corrente durante la fase di irrigazione, in ogni altro caso dovrebbe rimanere li memorizzata.

Copiando dal monitor seriale si vede il primo caso dove c'è il reset:

Code: [Select]

18:20:06.066 -> Fase: INTERAZIONE UTENTE
18:20:06.100 -> Se è il Primo Avvio o vuoi Resettare premi [s] e attendi...
18:20:16.024 -> Resetto data e ora su NVRAM
18:20:16.058 -> Fase: CONTROLLO
18:20:16.058 -> Fase: PAUSA 24H
18:20:16.094 -> Fase: RIEMPIMENTO / RABOCCO
18:20:21.333 -> Fase: RIPOSO
18:20:21.333 -> Prossima irrigazione GG/MM:  5/6 Alle ore: 1050


L'altro caso se non si fa niente (per esempio se arduino si riavvia per mancanza di corrente):

Code: [Select]
18:21:20.090 -> Fase: INTERAZIONE UTENTE
18:21:20.124 -> Se è il Primo Avvio o vuoi Resettare premi [s] e attendi...
18:21:30.104 -> Fase: CONTROLLO
18:21:30.142 -> Fase: RIEMPIMENTO / RABOCCO
18:21:32.930 -> Fase: RIPOSO
18:21:32.930 -> Prossima irrigazione GG/MM:  5/6 Alle ore: 1050


Sempre che poi vada oltre...

Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 04, 2019, 09:50 pm
Facciamo un po' di ordine nel primo case...
Dov'è andato perso il serial available? :smiley-lol:
E che succede se premi la S maiuscola?  :smiley-slim:

Code: [Select]
case INTERAZIONE_UTENTE:
    if (first_pass) {
        Serial.println("Fase: INTERAZIONE UTENTE ");
        Serial.println("Se è il Primo Avvio o vuoi Resettare premi [s] e attendi...");
    }

    if (trascorso >= 10) {  // evento: timeout 10 secondi
        fase = CONTROLLO;
    }
    else if (Serial.available()  &&  (tolower(Serial.read()) == 's')) {  // evento: ricevuto 's'
        Serial.println("Resetto data e ora su NVRAM");
        for (byte i=0x08;  i <= 0x0D;  i++) { RTC.writenvram(i, 0); }
        fase = CONTROLLO;
    }
break;
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 05, 2019, 12:54 am
Facciamo un po' di ordine nel primo case...
Dov'è andato perso il serial available? :smiley-lol:
Me lo sono giocato alla prima e poi il copia e incolla ha fatto il resto  :smiley-roll:

E che succede se premi la S maiuscola?  :smiley-slim:
Nel frattempo ho fatto una prova  "a stati finiti" ed ho creato nuove schede e diviso le fasi per file... spero non aver fatto un casino, mi pare funzioni e comunque non è mia intenzione rubare più tempo del dovuto e nel caso si continua come prima... in pratica ho fatto cosi:

Code: [Select]

switch (fase) {
   
    case INTERAZIONE_UTENTE:
    faseInterazioneUtente();
    break;

    case CONTROLLO:
    faseControllo();
    break;

    case PAUSA_24H:
    fasePausa24h();
    break;

    case RIEMPIMENTO_RABOCCO:
    faseRiempimentoRabocco();
    break;

    case RIPOSO:
    faseRiposo();
    break;

    case CONCIMAZIONE:
    faseConcimazione();
    break;

    case IRRIGAZIONE:
    faseIrrigazione();
    break;


e poi per esempio il primo stato... :

Code: [Select]

void faseInterazioneUtente() {
 
if (first_pass) {
      if (Serial.available()) {
      Serial.println( "Fase: INTERAZIONE UTENTE " );
      Serial.println( "Se è il Primo Avvio o vuoi Resettare premi [s] e attendi..." );
      }
    }
    // se trascorrono 10 secondi va alla fase CONTROLLO
    if (trascorso >= 10) {  // evento: timeout 10 secondi
       fase = CONTROLLO;
       }
    // se non trascorrono 10 secondi e si digita S scrive 0 sulla nvram e va alla fase CONTROLLO
    else if (Serial.available()  &&  (tolower(Serial.read()) == 's' || 'S' )) {  // evento: ricevuto 's'
       Serial.println("Resetto data e ora su NVRAM");
       for (byte i=0x08;  i <= 0x0D;  i++) { RTC.writenvram(i, 0); }
       fase = CONTROLLO;
       }
       
}  // fine void faseInterazioneUtente
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 05, 2019, 10:02 am
Facciamo un po' di ordine nel primo case...

Code: [Select]
case INTERAZIONE_UTENTE:
        for (byte i=0x08;  i <= 0x0D;  i++) { RTC.writenvram(i, 0); }

Quello che non è capito bene è... hai dichiarato che il byte i è 0x08 fino a 0x0D, però lo hai fatto all'interno del case INTERAZIONE_UTENTE. Ora se io volessi utilizzare questa lettura anche in un altro case posso scrivere per esempio questo?

Code: [Select]
if  (  (RTC.readnvram(i) == 0 ) { xxxx } oppure devo dichiarare di nuovo che il byte i è 0x08 fino a 0x0D tipo così?

Code: [Select]
for (byte i=0x08;  i <= 0x0D;  i++) { RTC.readnvram(i); }
Title: Re: Irrigazione automatica
Post by: maubarzi on Jun 05, 2019, 10:44 am
Occhio ad usare queste memorie come RAM.
Se non sei a corto di SRAM, usale solo per appoggiarci valori che devono resistere a riavvii o interruzioni impreviste, quindi le letture sarebbero da fare solo nel setup per ripartire da dove si era arrivati prima dell'interruzione.
Per il funzionamento normale, vista la premessa qui sopra, ti consiglerei di usare variabili normali.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 05, 2019, 11:35 am
Occhio ad usare queste memorie come RAM.
Se non sei a corto di SRAM, usale solo per appoggiarci valori che devono resistere a riavvii o interruzioni impreviste, quindi le letture sarebbero da fare solo nel setup per ripartire da dove si era arrivati prima dell'interruzione.
Per il funzionamento normale, vista la premessa qui sopra, ti consiglerei di usare variabili normali.
Io, salvo correggere gli errori, lo lascerei così e magari rimanderei l'ottimizzazione ad un secondo passaggio. Anche perchè per ora mi interessa raggiungere lo scopo di avere l'innaffiatoio, poi siccome sono interessato ad approfondire il c++ posso usare questo progetto per sperimentare cose nuove, ma in aggiornamenti successivi... anche perchè ho bisogno di staccare. Dunque mi concentrerei ad avere una prima versione accettabile e funzionante

Ora stavo cominciando a guardare sul web su come gestire uno stepper tramite gli easydriver visto che me li ritrovo da vecchi progetti e stacco stepper da ogni stampante che trovo in giro.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 05, 2019, 04:18 pm
Dov'è andato perso il serial available? :smiley-lol:
In pratica se l'aggiungo non parte più nulla, li avevo corretti tutti cosi

Code: [Select]

if (first_pass) {
   if (Serial.available()) {
   Serial.println("Fase: CONTROLLO");
   }
}
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 05, 2019, 06:31 pm
In pratica se l'aggiungo non parte più nulla, li avevo corretti tutti cosi
Code: [Select]

if (first_pass) {
   if (Serial.available()) {
   Serial.println("Fase: CONTROLLO");
   }
}

Con gli ultimi post hai accatastato tanti di quegli errori di semantica (a cosa servono e cosa fanno le istruzioni) che secondo me non è più possibile "correggere" nulla se non cominciando a studiare per bene le basi del C.

Bisogna fare molti passi indietro perché di nuovo mi sembrano tentativi alla cieca "pur di concludere qualcosa".

Per quale motivo (a me incomprensibile se si sa a cosa serve Serial.available) hai messo la Serial.available in tutti i case? :o  :o  :o La riga già completa e corretta te l'ho scritta io nel post #134, e l'hai anche copiata modificandola in modo errato nel post #135 (infatti come l'hai modificata riconosce valido qualsiasi carattere.... errore di semantica, la riga non fa quello che pensi faccia... hai copiato 'tolower' senza andare a vedere cosa fa?).

Quote
posso scrivere per esempio questo?
Code: [Select]

if  (  (RTC.readnvram(i) == 0 ) { xxxx }

Certo, è una riga perfettamente valida e funzionante... però...

Quote
oppure devo dichiarare di nuovo che il byte i è 0x08 fino a 0x0D tipo così?
...e ci risiamo con la semantica, il che mi fa pensare che tu non abbia in realtà capito cosa fa la riga e cosa sia 'i', e neppure che 0x08 è la stessa cosa di scrivere 8, e che 0x0D è la stessa cosa di scrivere 13 (metà post #99).

Non "devi" dichiarare nulla, devi scrivere quello che ti serve. Cosa ti serve? Leggere una cella, allora la variabile 'i' è l'indirizzo della cella. Devi leggere un gruppo di celle? Allora 'i' deve essere di volta in volta l'indirizzo che ti interessa. Farlo con un ciclo for? Si, se ti serve farlo con un ciclo for, no se non ti serve. Cosa ti serve? (A margine, sai come funziona un ciclo for?)

Dal codice post #138:
Code: [Select]
/************************PAUSA_24H*****************************/
/* Il questa fase si passa solo se CONTROLLO ha letto 0 su nvram.
Di conseguenza l'unico scopo di PAUSA_24H è quello di calcolare
24h e scriverle sulla nvram.
Successivamente passa alla fase RIEMPIMENTO_RABOCCO           */

Visto che le fasi sono normalmente quegli stati in cui si permane per un certo tempo fino al verificarsi di qualche condizione, allora da una fase chiamata PAUSA_24H mi aspetterei che "l'unico scopo di PAUSA_24H" sia la permanenza nella fase per 24 ore, invece la descrizione dice tutta un'altra cosa.... dice che calcola... ma non c'è nessun calcolo.... c'è solo la scrittura nella NVRAM... Capisci che è impossibile seguire la logica di qualcosa se anche nomi e descrizioni non c'entrano con quello che fa il codice?

Avanti, variabili con lo stesso nome dichiarate in più punti (ADESSO, MESE, GIORNO ecc). L'unico motivo per cui non si è ancora verificato il disastro è che tutto il codice è contenuto nel loop, ma appena dividi in funzioni non funziona più un tubo. Le variabili hanno delle regole di visibilità (punti del codice in cui sono visibili e modificabili) che vanno conosciute, altrimenti come prima c'è un errore di semantica (si pensa che debba succedere qualcosa ma succede qualcos'altro). In particolare la prima dichiarazione esterna all'inizio del programma crea delle variabili globali, mentre quella all'interno del loop crea delle variabili locali (diverse da quelle globali anche se il nome è lo stesso), quindi le dichiarazioni vanno fatte in base a quello che ti serve. Servono delle variabili globali che mantengono il valore tra un'esecuzione e l'altra della funzione loop? Oppure bastano delle locali che vengono ricreate nuove ad ogni esecuzione della loop?.

Code: [Select]
{
    fase = PAUSA_24H;  // passo alla fase PAUSA_24H
}
else
{
    fase = RIEMPIMENTO_RABOCCO;  //  e passo alla fase RIEMPIMENTO_RABOCCO
}

Anche qui i commenti sono errati.... c'è una differenza abissale tra dire 'e' o dire 'altrimenti'. Come si fa "da fuori" a capire se quello giusto è il codice o il commento e da questo a cercare di intuire cosa volevi realmente dire/fare?  >:(


Quote
Vi prego dunque di aiutarmi a capire cosa non capisco
Quote
Se voi non mi mollate io non mollo! Siete avvisati!
Quote
ho bisogno di staccare. Dunque mi concentrerei ad avere una prima versione accettabile e funzionante
Che famo?  :smiley-fat: :smiley-roll-sweat:

I suggerimenti di Standardoil del pomodoro proprio no?  :smiley-slim:
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 05, 2019, 09:48 pm
Però ragazzi, ristabiliamo l'equilibrio degli intenti perchè altrimenti non va bene... io sto chiedendo aiuto ma ho una soglia oltre la quale non vado... la soglia della chiarezza.
Io non sono arrivato qui  facendo finta di sapere, di conoscere il c++, e facendo finta qualsiasi altra cosa che alludesse al fatto  che io ne sapessi qualcosa... sono arrivato qui dichiarando la mia ignoranza in materia (post #1).
Ora ho capito che siamo a 10  pagine ecc. e che magari questo thread sta andando fuori standard... però non venite a rinfacciarmi cose che non ho mai detto. Non capisco la semantica? dimmi: leggiti questo "link" e poi parliamo... Non capisco il loop? dimmi: leggiti questo "link" e poi parliamo... io ci sto perchè come ho detto, ho intenzione di dedicare del tempo a questa cosa e c'è l'interesse. Però se mi viene fatto un "rimprovero" di non sapere o capire delle cose, è fuori di ogni logica... o quanto meno è off-topic, relativamente al mio primo post.
Per quanto riguarda la frase "ho bisogno di staccare. Dunque mi concentrerei ad avere una prima versione accettabile e funzionante" ovviamente una frase presa a se non vale nulla, quello che volevo dire è che sapendo che ancora mi devo smazzare il motore stepper (fase concimazione) e sapendo che è ancora lunga, mi accontenterei  anche di avere un codice non perfetto a livello di logica ma quantomeno funzionante.

Detto questo ribadisco il fatto che vi sono grato per il tempo fin ora dedicatomi. Anche se voi non lo vedete io vedo già grandi risultati che mi stanno incoraggiando a continuare. Sto cercando un libro di testo valido per approfondire la cosa... più di questo non saprei cosa fare. Ciao
Title: Re: Irrigazione automatica
Post by: gpb01 on Jun 05, 2019, 09:54 pm
... Non capisco la semantica? dimmi: leggiti questo "link" e poi parliamo... Non capisco il loop? dimmi: leggiti questo "link" e poi parliamo... io ci sto perchè come ho intenzione di dedicare del tempo a questa cosa
Bene, allora ti do io le indicazioni ... puoi cominciare con studiare QUESTO (http://cabestano.altervista.org/alterpages/files/TizianaMarsella-ProgrammareArduino.pdf) proseguire con QUESTO (https://drive.google.com/file/d/0B2OYiD2XGofOVkpodUFNaFNweWM/view) e acquistare qualche buon libro (es. QUESTO (http://www.amazon.it/Arduino-essenziale-linguaggio-librerie-elettronica/dp/8865374837)) ... vedrai che, alla fine dello studio, tutto ti sarà molto più chiaro :)

Guglielmo
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 06, 2019, 02:45 am
Quote
Per quanto riguarda la frase "ho bisogno di staccare. Dunque mi concentrerei ad avere una prima versione accettabile e funzionante" ovviamente una frase presa a se non vale nulla, quello che volevo dire è che sapendo che ancora mi devo smazzare il motore stepper (fase concimazione) e sapendo che è ancora lunga, mi accontenterei  anche di avere un codice non perfetto a livello di logica ma quantomeno funzionante.
Che hai fretta mi pare di averlo già detto (aspe che controllo, si l'avevo detto #27) ;)

A proposito rileggilo quel post, circa le convenzioni.

Certamente se il codice fosse corretto nella logica si comporterà come logica vuole, tuttavia quando chiedi aiuto, chi ti risponde non ha il tuo stesso hardware a disposizione per cui non può verificare che la logica funziona. In mancanza di ciò ci si basa sul codice, io ad esempio non ho L'ide nè board sotto mano, e mi devo "sbattere" un po di più.

Quindi supponiamo che il programma lavora come ti aspetti, ma io come faccio a consigliarti se l'unico riferimento per me è il codice. Se è scritto male io capisco male e su queste basi io (e gli altri) interveniamo o meno. Come dire diversamente, per consigliare bene devo capire bene, altrimenti se non capisco, se mi perdo non posto nulla. 

Comunque evitiamo di fare polemica e andiamo dritti al sodo.
Libri in italiano su arduino (o C/C++) che possa consigliarti oltre a quelli suggeriti da gpb01 al momento non ne ho.

Per il codice postato al momento devo convenire con quello che dice Claudio. Inoltre mi pare di averlo scritto, prima che quando aumentano il numero di variabili seguire la logica è compito impegnativo e ci si perde facilmente, il linguaggio offre strumenti che aiutano ma non posso introdurli in questo momento e sai bene il perché.

Circa le variabili globali e quelle locali
Le variabili globali sono dichiarate nel corpo principale del programma al di fuori da qualunque funzione.
Le variabili locali sono dichiarate dentro le funzioni, in verità si dichiarano dentro la porzione di codice delimitata da { e }, che nei libri in inglese viene detto essere un blocco di codice.

Un blocco di codice {} può esistere sia collegato,
Code: [Select]

if (1) {
    // blocco di codice collegato alla if
}


che isolato,

Code: [Select]

if (1) {
    // blocco di codice collegato alla if
    {
         // blocco di codice isolato
    }

}


Si dice che i blocchi di codice sono innestati perché uno contiene l'altro e così via.

Vita di una variabile

Le variabili locali hanno vita breve, perché sono create in memoria quando all'interno del blocco di codice
si trova la dichiarazione e vengono distrutte poco prima di '}'.

Le variabili globali hanno vita eterna.

Ambito di visibilità
Una variabile globale è visibile ovunque e quindi ha ambito globale. Una variabile
locale ha ambito locale ed è visibile solo all'interno del blocco di codice.

Due variabili con lo stesso nome, una globale e l'altra locale, quest'ultima nasconde la variabile globale.

Code: [Select]

int x = 0;

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

    int x = 12;  // x è locale nasconde x globale
    serial.println(x);  // stampa 12

}

void loop() {
    serial.println(x);  // stampa 0

}



Ecco perché non si danno nomi brevi alle variabili globali. Mentre x, y, z li uso dentro le funzioni o dentro a blocchi di codice.

Ciao.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 06, 2019, 06:41 am
Come dire diversamente, per consigliare bene devo capire bene, altrimenti se non capisco, se mi perdo non posto nulla.
Direi che questo sintetizza in modo perfetto. Il mio post ovviamente non era un attacco, ma una richiesta di maggiore chiarezza (che deve esserci in entrambi i sensi) evidenziando diversi aspetti a cui prestare attenzione, perché la volontà di sperimentare si vede che c'è. E quando chiedo ad esempio "sai come funziona il ciclo for"... NON è da leggere come: "non sai ancora cosa fa il for?", ma è una richiesta di informazioni (feedback) in senso letterale, perché non so di cosa posso o non posso parlare.
Title: Re: Irrigazione automatica
Post by: maubarzi on Jun 06, 2019, 09:18 am
Non capisco la semantica?
Nessuno lo ha affermato, è solo stato detto che nel software ci sono problemi di semantica.
Se si dichiara che una funzione fa una cosa e poi questa funzione non la fa, si è inserito un problema di semantica.
Questo non significa che chi lo ha scritto non capisce la semantica.
Quando si programma il cervello spesso si divide in due, quello che progetta e quello che realizza.
Quello che progetta porta a scrive gli appunti di quello che intende fare, quello che realizza porta a scrive quello che al momento serve.
Capita spesso che le due cose non coincidano perchè si sono cambiati i piani in corsa.
Credo capiti a tutti.
Il trucco è riallineare subito il tutto per rimettere ordine.
Se questo non accade, si crea confusione a chi legge il codice e anche a noi stessi a distanza di tempo, dopo che abbiamo dimenticato i ragionamenti fatti.
Ti confesso che a causa di questo "disordine", è da un po' che non intervengo, perchè mi sono un po' perso e faccio fatica a riprendere il filo.

Per quanto riguarda la frase "ho bisogno di staccare. Dunque mi concentrerei ad avere una prima versione accettabile e funzionante" ovviamente una frase presa a se non vale nulla, quello che volevo dire è che sapendo che ancora mi devo smazzare il motore stepper (fase concimazione) e sapendo che è ancora lunga, mi accontenterei  anche di avere un codice non perfetto a livello di logica ma quantomeno funzionante.
Su questo dissento totalmente.
Se il software è funzionante la logica è corretta, se la logica non è corretta il software non può essere funzionante. Questo per definizione!
Il software può essere più o meno ottimizzato e ordinato/disordinato ma la logica deve quadrare.
Puoi fare 20 giri per testare una singola variabile, ma alla fine il test per quanto contorto deve essere giusto per funzionare. Se funziona la logica è corretta anche se il test risulta contorto, ridondante e disordinato.

Quindi, più il codice è tenuto ordinato e più riceverai aiuto, più è disordinato e incoerente e più potenziali aiutanti perderai perchè non riusciranno più a seguire il filo logico.

Poi, sta a te prendere in mano il timone del progetto (come quando mi hai risposto che preferivi fare diversamente da quanto ti avevo appena consigliato, questo è legittimo e hai fatto bene a dirlo) e decidere la via, però diventerà sempre più difficile farlo se non si fa un po' di ordine e non si sistema la logica di base.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 06, 2019, 10:44 am
Ragazzi ognuno di voi ha  evidenziato delle cose giustissime e che io stesso vedo...  è proprio li che mi perdo cioè nel capire cosa va nel loop, nel setup e fuori dai due, di conseguenza ha ragione Maurotec a sottolinearmi la differenza tra le variabili globali e locali, la vita e l'ambito di visibilità. Infatti guardando come ho spostato le cose da uno sketch all'altro è evidente che non ho capito quello, o quantomeno mi è sempre più evidente. Questo è il motivo per cui ho esordito dicendo "aiutatemi a capire cosa non capisco", e certo non pretendo mi dobbiate spiegare le cose una ad una come ha fatto ora Maurotec.
Maubarzi riguardo alla citazione "mi accontenterei  anche di avere un codice non perfetto a livello di logica ma quantomeno funzionante" mi riferivo al fatto che mi stavi mettendo in guardia nell'utilizzare la NVRAM e che potevo limitarla solo alle situazioni in cui serve... di conseguenza intendevo dire che anche se stavo usando la nvram in maniera poco sana mi sarei comunque accontentato di questo sistema, fino a quando le competenze acquisite non mi avrebbero permesso di usare altre vie.
Detto questo, non sono un giovincello ho 42 anni, mi conosco bene e conosco anche la mia perseveranza.  Questo progetto lo voglio finire e sto andando a leggermi i libri che mi avete consigliato... per ora vi ringrazio ed eviterò di farvi perdere altro tempo finché non mi sarò chiarito alcuni concetti...
Title: Re: Irrigazione automatica
Post by: maubarzi on Jun 06, 2019, 12:31 pm
Quando ho scritto:
...come quando mi hai risposto che preferivi fare diversamente da quanto ti avevo appena consigliato, questo è legittimo e hai fatto bene a dirlo...
Alludevo proprio a questo:

Maubarzi riguardo alla citazione "mi accontenterei  anche di avere un codice non perfetto a livello di logica ma quantomeno funzionante" mi riferivo al fatto che mi stavi mettendo in guardia nell'utilizzare la NVRAM e che potevo limitarla solo alle situazioni in cui serve...
Hai preso una decisione legittima che non è sbagliata o illogica, quindi ripeto che "hai fatto bene a dirlo" e a concentrarti sul resto che per te è più importante.

Gli ultimi post, mi pare, siano tutti nell'ottica riassunta dalla frase: aiutaci ad aiutarti ;)
tutto qui.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 07, 2019, 10:04 am
Per quale motivo (a me incomprensibile se si sa a cosa serve Serial.available) hai messo la Serial.available in tutti i case? :o  :o  :o La riga già completa e corretta te l'ho scritta io nel post #134, e l'hai anche copiata modificandola in modo errato nel post #135 (infatti come l'hai modificata riconosce valido qualsiasi carattere...
Ieri rileggendo il post mi sono accorto dove non ci siamo capiti... il motivo per cui avevo messo  la Serial.available in tutti i case è che avevo interpretato male il tuo post precedente.

Dov'è andato perso il serial available? :smiley-lol:
Non mi ero accorto che il codice che avevi incorporato era il tuo, pensavo fosse il mio e che mi stavi chiedendo perchè l'avevo tolto... e l'ho messo a tutti...

Ovviamente alla base di tutti gli equivoci c'è il fatto che non immaginavo neanche lontanamente che esistessero variabili di tipo globale e locale e che quindi ci sono livelli di visibilità o globali, o del loop, o del ciclo  :o ... capito questo mi si è aperto un mondo e ora capisco anche perchè non ci capivamo...

Sto rivendendo un po tutto, anche le fasi e a breve vi aggiorno. Però ho una domanda da fare... tenetevi... una variabile può essere locale e visibile solo al case? cioè posso fare una cosa del genere? gli esempi che ho lo fanno ma all'interno di una funzione e volevo sapere se i case lavora allo stesso modo.

Code: [Select]

case PAUSA_24H:

int pippo;
   
   ( ...ciclo calcolo pippo...)

break;

{


Title: Re: Irrigazione automatica
Post by: gpb01 on Jun 07, 2019, 10:16 am
... Però ho una domanda da fare... tenetevi... una variabile può essere locale e visibile solo al case? cioè posso fare una cosa del genere? ...
No, non così ... devi creare un raggruppamento con le parentesi graffe. Guarda l'esempio qui sotto e capirai ...

Code: [Select]
void setup() {
  uint8_t indice;

  switch (indice) {
   case 1: {
      uint8_t variabile;
      variabile = 1;
      break;
   }
   case 2:
      variabile = 2;
      break;
   default:
     
      break;
  }

}

void loop() {


}

... se provi a compilare vedrai che ti darà errore nel "case 2:" perché "variabile", nel caso qui sopra, è visibile SOLO nel "case 1:".

Se invece togli le graffe del "case 1:" allora non ti darà errore e la variabile sarà visibile in tutto lo "switch" (ma non al di fuori).

Guglielmo
Title: Re: Irrigazione automatica
Post by: maubarzi on Jun 07, 2019, 10:26 am
si
una variabile definita in un blocco di codice è locale in quel blocco di codice.
sullo switch case però c'è una complicazione che non ho ancora compreso al 100% perchè ignorante sono.
non puoi inizializzare la variabile durante la definizione perchè si incappa in un problema che se ho capito bene dipende dal fatto che l'inizializzazione non viene fatta se non si entra nel relativo case.

Cioè, puoi definire come hai fatto:
Code: [Select]
case PAUSA_24H:
  int pippo;
---

ma non
Code: [Select]
case PAUSA_24H:
  int pippo = 0;
  ...


Una variabile definita così ha visibilità fino alla fine dello switch.
Quindi puoi scrivere:

Code: [Select]
switch (i) {
  case 0:
    int j;
    j = 0;
    break;
  case 1:
    j = 1;
    break;
  default:
    j = 10;
    break;
}

se vuoi limitare la visibilità al singolo case devi creare un blocco con le graffe, cioè:
Code: [Select]

  switch (i) {
    case 0:
      {
        int j = 1; // Creando il blocco con le graffe non c'è più il problema dell'inizializzazione.
        j = 0;
      }
      break;
    case 1:
      j = 1; // Questo, ora va in errore perchè j non è più accessibile da qui.
      break;
    default:
      j = 10; // Questo, ora va in errore perchè j non è più accessibile da qui.
      break;
  }
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 07, 2019, 01:17 pm
Ho stravolto quasi tutto... innanzitutto, e spero di non aver sbagliato, ho diviso i settori in files.h per pulire un po la visuale e fare un po d'ordine. Poi il file.h lo richiamo con #include e sembra non dia errori, anzi arduino segnala anche gli errori di compilazione in questi file dunque non dovrebbero esserci problemi.
Quindi ora nella cartella / si trovano solo il filePrincipale.ino e  filePrincipale.h che sarebbe una sorta di libreria che include gli altri settori. Poi in una sottocartella ho suddiviso pin, variabili globali, funzioni variabili globali, costanti e setup. Nello sketch principale rimane solo lo switch case. Scusate ma ho dovuto farlo perchè altrimenti mi perdevo.

Altra modifica ho eliminato le fasi inutili e la nvram viene usata solo per memorizzare la data di concimazione ogni 40gg... ora rimangono solo

INTERAZIONE_UTENTE:
Primo avvio (I fase). Viene chiesto di resettare, se risposta Si imposta ePausa come true e scrive 0 su nvram ma solo per la concimazione!. Trascorsi 10 sec imposta ePausa come false. In ogni caso si passa alla fase RIEMPIMENTO_RABOCCO.

RIEMPIMENTO_RABOCCO:
Se valvola aperta apri elettrovalvola altrimenti chiudila e passa a RIPOSO

RIPOSO: Qui forse ci sono errori  ma da qui ora partono tutti gli "switch" con dei confronti tra data giorno, mese e scrittura su nvram (concimazione). Sono tre IF uno dovrebbe ritardare di 24 ore, l'altro irrigare, e l'altro concimare. Nella fase riposo ho provato a fare una variabile locale visibile solo dal case stesso e che si occupa di ricavare giorno e mese attuali + 24 ore

CONCIMAZIONE:
Avvia peristalsi e agitamento, riaggiorna l'nvram con giorno, mese attuale + 40gg. e passa a irrigazione. DA COMPLETARE

IRRIGAZIONE:
se è trascorso meno di durataIrrigazione pompa irrigazione accesa altrimenti spegni e passa a RIEMPIMENTO_RABOCCO
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 07, 2019, 08:13 pm
Non mi ero accorto che il codice che avevi incorporato era il tuo, pensavo fosse il mio e che mi stavi chiedendo perchè l'avevo tolto... e l'ho messo a tutti...
Il problema è esattamente questo, non avresti dovuto metterlo neppure se ti dicevo di farlo.

Avresti dovuto chiederti: a cosa serve Serial.available (https://www.arduino.cc/reference/en/language/functions/communication/serial/available/)?  Dal reference: "Returns The number of bytes available to read." Ah, serve per sapere se e quanti byte sono arrivati sulla seriale. Ok, e a cosa mi serve questa informazione in tutti i case che non siano il primo di interazione? Risposta: ma assolutamente a niente. Anzi... se metto la condizione 'available' anche negli altri case... allora se non arrivano caratteri sulla seriale la condizione sarà sempre falsa, e oh, ma allora non mi esegue più il codice dei case... sta a vedere che mi hanno detto bischerate.

E purtroppo questo tipo di "piccoli errori" lo hai riportato ancora in più punti nel codice nuovo, in primis il mio codice del post #134, che credevi fosse il tuo nonostante contenga la funzione 'tolower' che non hai scritto tu:
Code: [Select]
else if (Serial.available()  &&  (tolower(Serial.read()) == 's')) {  // evento: ricevuto 's'
Questa riga andava compresa prima di essere usata... invece l'hai modificata in modo errato (come ho detto nel post #140), non hai risposto alla domanda su 'tolower' (che era un invito a capire cosa fa, da cui si sarebbe capito l'errore e che la modifica era inutile perché la riga è già fatta apposta per accettare solo la 's' maiuscola e minuscola), e hai copiato la riga compreso l'errore anche nel codice nuovo (nonostante nel post #148 tu mi abbia anche quotato la frase in cui dicevo che era sbagliata).

Ora, non vorrei sembrare un inquisitore, ma è solo che il "metodo" mi sembra un po' "confusionario", se non si presta attenzione alle "piccole cose segnalate" non funzionerà mai niente. Se uno dice "quella riga è sbagliata" non la si copia tale e quale anche nel codice nuovo, ma prima di andare avanti ci si chiede davvero? Perché? Dove? Come?...altrimenti la passione si smorza...

Mi sembra che anche le righe seguenti non sono state comprese, infatti messe dove sono state messe (in un file incluso) non servono a niente:
Code: [Select]
// operazione eseguite una sola volta, dopo 10 sec, o sempre
first_pass = false;
if (fase != old_fase) { first_pass = true;  inizio_fase = millis(); }
old_fase = fase;
trascorso = (millis() - inizio_fase) / 1000;

Queste righe sono fondamentali per l'aggiornamento ad ogni ciclo di loop delle variabili dello switch. Altrimenti 'first_pass' rimane sempre vera, e 'trascorso'... non trascorre mai... Andavano lasciate come da esempio post #128, cioè appena prima dello switch che controllano. Il commento poteva essere ad esempio: //aggiornamento ad ogni ciclo di programma delle variabili ausiliarie 'first_pass' e 'trascorso' per funzionamento della macchina a stati realizzata con switch. La variabile 'first_pass' diventa vera per un solo ciclo ad ogni cambio di fase, questo permette di eseguire una sola volta delle operazioni in un case quando quella fase diventa attiva. La variabile 'trascorso' si azzera ad ogni cambio di fase e contiene i secondi trascorsi da quando una fase diventa attiva.

Altra cosa, in almeno un paio di case vedo un errore di logica che li fa terminare immediatamente lasciando i relé sempre accesi... ad esempio in irrigazione il cambio della fase è al di fuori di ogni condizione, quindi avviene già al primo passaggio. È solo una svista?
Code: [Select]
case IRRIGAZIONE:
  if (first_pass) {
    Serial.println("Fase: IRRIGAZIONE");
  }
  
  if (trascorso <= durataIrrigazione) {
    digitalWrite(pinPompa, ACCESO);
  }
  else
  {
    digitalWrite(pinPompa, SPENTO);
  }
fase = RIEMPIMENTO_RABOCCO;  
break;

Il codice corretto sarebbe questo:
Code: [Select]
case IRRIGAZIONE:
  if (first_pass) {
    Serial.println("Fase: IRRIGAZIONE");
    digitalWrite(pinPompa, ACCESO);
  }
  
  if (trascorso >= durataIrrigazione) {  // evento: timeout
    digitalWrite(pinPompa, SPENTO);
    fase = RIEMPIMENTO_RABOCCO;  
  }
break;
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 10:30 am
Il problema è esattamente questo, non avresti dovuto metterlo neppure se ti dicevo di farlo.
Avresti dovuto chiederti: a cosa serve Serial.available (https://www.arduino.cc/reference/en/language/functions/communication/serial/available/)?  Dal reference: "Returns The number of bytes available to read."
Errore mio di pressapochismo e me ne scuso, altra cosa da imparare è guardare ogni virgola.

E purtroppo questo tipo di "piccoli errori" lo hai riportato ancora in più punti nel codice nuovo, in primis il mio codice del post #134, che credevi fosse il tuo nonostante contenga la funzione 'tolower' che non hai scritto tu:
Code: [Select]
else if (Serial.available()  &&  (tolower(Serial.read()) == 's')) {  // evento: ricevuto 's'
Questa riga andava compresa prima di essere usata... invece l'hai modificata in modo errato (come ho detto nel post #140), non hai risposto alla domanda su 'tolower' (era un invito a capire cosa fa da cui si sarebbe capito l'errore e che la modifica era inutile), e hai copiato la riga compreso l'errore anche nel codice nuovo (nonostante nel post #148 tu mi abbia anche quotato la frase in cui dicevo che era sbagliata).
Vebbé però non è proprio così dai, pensavo che era il mio perché lo spazio nel post che include il code di default si apre di una certa grandezza e non si vedeva l'aggiunta... poi ho dato per scontato che il codice era corretto ed alla tua domanda (è se uno scrive S anzichè s? ho risposto inserendo nel codice la  S
Code: [Select]
else if (Serial.available()  &&  (tolower(Serial.read()) == 's' || 'S'))

Ora, non vorrei sembrare un inquisitore, ma è solo che il "metodo" mi sembra un po' "confusionario", se non si presta attenzione alle "piccole cose segnalate" non funzionerà mai niente. Se uno dice "quella riga è sbagliata" non la si copia tale e quale anche nel codice nuovo, ma prima di andare avanti ci si chiede perché? Dove? Come? Davvero?...altrimenti la passione si smorza...
Si però le persone non sono digitali. Mica esiste solo 0 e 1, hai "capito" o hai "non capito", esiste pure "credo di aver capito", poi fai una prova e scopri che non hai capito... l'ignoranza il più delle volte non è non sapere ma è pensare di sapere e so bene che è una cosa sgradevole agli occhi degli altri.

Mi sembra che anche le righe seguenti non sono state comprese, infatti messe dove sono state messe (in un file incluso) non servono a niente:
Code: [Select]
// operazione eseguite una sola volta, dopo 10 sec, o sempre
first_pass = false;
if (fase != old_fase) { first_pass = true;  inizio_fase = millis(); }
old_fase = fase;
trascorso = (millis() - inizio_fase) / 1000;

Ed anche qui non sapevo che la separazione in file portasse ad un diverso comportamento. Per il resto è nello stesso ed identico posto di dove lo hai messo cioè prima dello switch, solo che si trova in un file a parte.

Altra cosa, in almeno un paio di case vedo un errore di logica che li fa terminare immediatamente lasciando i relé sempre accesi... ad esempio in irrigazione il cambio della fase è al di fuori di ogni condizione, quindi avviene già al primo passaggio. E anche qui noi non sappiamo se è solo una svista, o se c'è una logica non compresa da chiarire:
Code: [Select]
case IRRIGAZIONE:
  if (first_pass) {
    Serial.println("Fase: IRRIGAZIONE");
  }
 
  if (trascorso <= durataIrrigazione) {
    digitalWrite(pinPompa, ACCESO);
  }
  else
  {
    digitalWrite(pinPompa, SPENTO);
  }
fase = RIEMPIMENTO_RABOCCO; 
break;

Il codice corretto sarebbe questo:
Code: [Select]
case IRRIGAZIONE:
  if (first_pass) {
    Serial.println("Fase: IRRIGAZIONE");
    digitalWrite(pinPompa, ACCESO);
  }
 
  if (trascorso >= durataIrrigazione) {  // evento: timeout
    digitalWrite(pinPompa, SPENTO);
    fase = RIEMPIMENTO_RABOCCO; 
  }
break;


Ora che mi fai vedere l'errore lo capisco. In effetti il funzionamento del loop, di ciò che si muove e ciò che sta fermo è una cosa che sto cercando di inquadrare e non mi è chiarissima. Poi altra cosa, è che faccio la prova sull'arduino e se vedo che funziona penso che funziona ma magari funziona nonostante l'errore. Che ti devo dire, ci riprovo tenendo conto di tutto ciò che mi hai fatto notare, per ora ti ringrazio e spero che non perdi la passione  :smiley-sweat:
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 08, 2019, 10:40 am
altra cosa da imparare è guardare ogni virgola.
Purtroppo stiamo parlando di una scienza esatta :D

Quote
Ed anche qui non sapevo che la separazione in file portasse ad un diverso comportamento. Per il resto è nello stesso ed identico posto di dove lo hai messo cioè prima dello switch, solo che si trova in un file a parte.
Ni, lo è fisicamente, ma non lo è nell'ordine di esecuzione, perché non si trova dentro il loop assieme allo switch. Mmmm, no, qui ho un dubbio sull'include messo all'interno di una struttura... forse va bene:
Code: [Select]
void loop() {
  
  // data e ora rtc, due diversi orari per stagione
  #include "src/Funzioni_Variabili_Globali.h"

  switch (fase) {



Quote
In effetti il funzionamento del loop, di ciò che si muove e ciò che sta fermo è una cosa che sto cercando di inquadrare e non mi è chiarissima.
Perfetto, l'ordine in cui avvengono le cose è fondamentale.

Quote
Poi altra cosa, è che faccio la prova sull'arduino e se vedo che funziona penso che funziona ma magari funziona nonostante l'errore.
È possibile, è un funzionamento corretto in alcune condizoni (magari quelle di test), ma con una bomba pronta ad esplodere nel momento peggiore.... si può dire bomba in un forum vero? :smiley-mr-green:
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 10:44 am
Ni, lo è fisicamente, ma non lo è nell'ordine di esecuzione, perché non si trova dentro il loop assieme allo switch.
Si invece, si trova alla fine del file Funzioni_Variabili_Globali.h che è nel loop:

Code: [Select]

void loop() {
 
  #include "src/Funzioni_Variabili_Globali.h"

  switch (fase) {
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 11:37 am
Quindi ricapitolando... per ora ho lasciato le istruzioni nel file #include "src/Funzioni_Variabili_Globali.h" pare che funzioni, ma comunque ci sono sempre a spostarlo.


Ho tolto dal loop (src/Funzioni_Variabili_Globali.h) la richiesta che interroga l'RTC chiedendogli se è attivo e mi accorgo ora che era anche sbagliata perché chiedeva se NON era attivo...  :

Code: [Select]

// if (! RTC.isrunning()) { // ELIMINATO
    DateTime now = RTC.now();
    DateTime futuro40gg (now + TimeSpan(40,0,0,0)); // aggiunge 40gg al settore giorni (gg, hh, mm, ss)
    DateTime futuro24h (now + TimeSpan(0,24,0,0));  // aggiunge 24 al settore ore (gg, hh, mm, ss)
    adessoOra = now.hour() * 60 + now.minute();     // tempi da 0 a 1439 minuti
    adessoMese = now.month();
    adessoGiorno = now.day();
    giornoFuturo40gg = futuro40gg.day();        // ricavo la variabile
    meseFuturo40gg = futuro40gg.month();        // ricavo la variabile
    giornoFuturo24h = futuro24h.day();            // ricavo la variabile
    meseFuturo24h = futuro24h.month();            // ricavo la variabile
    giornoNVRAM = RTC.readnvram(0x08);        // ricava il giorno da nvram
    meseNVRAM = RTC.readnvram(0x09);          // ricava il mese da nvram


Ed ora funziona e scrive correttamente la data, e spero pure che funzioni il bool ePausa che a breve controllerò. Quindi la modifica che ho fatto al primo case è:

Code: [Select]

case INTERAZIONE_UTENTE:
   
      if (first_pass) {
        Serial.println("Fase: INTERAZIONE UTENTE ");                                         // stampo la fase su seriale
        Serial.println("Se è il Primo Avvio o vuoi Resettare premi [s] e attendi..."); // stampo la domanda su seriale
      }
     
      if (trascorso >= 10) {                                          // evento: timeout 10 secondi
        ePausa = false;                                                 // ePausa false (l'unico modo per mettere ePausa in true è premere S)
        fase = RIEMPIMENTO_RABOCCO;                      // vai a fase RIEMPIMENTO_RABOCCO
      }
      else if (tolower(Serial.read()) == 's') {                  // evento: ricevuto 's';
        ePausa = true;                                                  // imposta la pausa come true
        RTC.writenvram(0x08, giornoFuturo40gg);      // scrivo il giorno della prima concimazione su nvram
        RTC.writenvram(0x09, meseFuturo40gg);                   // scrivo il mese della prossima irrigazione su nvram
        fase = RIEMPIMENTO_RABOCCO;                               // vai a fase RIEMPIMENTO_RABOCCO
      }
    break;


Dove tolower si occupa di rendere lowercase ogni carattere incluso... pare che questo prima case funzioni salvo altre tirate di orecchie... :) passo avanti...
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 08, 2019, 11:54 am
1) È di nuovo sparito Serial.available, qui sembra andare tutto bene solo perché i blocchi dell'esecuzione dovuti al timeout della Serial.read non danno (in questo caso specifico) alcun sintomo visibile...

2) Nel codice precedente azzeravi la nvram, qui ci scrivi dei valori, io non so quale delle due versioni è corretta, i commenti non mi aiutano, perché in base ad essi stai salvando il giorno della prima concimazione, e il mese della prossima irrigazione. Ma comunque viste la variabili 40 giorni si deduce che si sta salvando il momento della concimazione desiderato, esattamente 40 giorni nel futuro a partire dal momento del reset/primo avvio confermato con 's'.

3) I commenti sulla variabile 'ePausa' non mi aiutano, perché vedo anch'io che viene messa a true o false, quello che non so è se true significa 'pausa 24 ore abilitata'... questo sarebbe un commento utile. E naturalmente da qualche altra parte ci dovrà poi essere una corrispondente disabilitazione per evitare che questa pausa venga successivamente ripetuta (visto che da quanto ho capito è da fare una sola volta).

E robettine minori, tipo meglio usare solo caratteri ASCII e non altri come le vocali accentate. E qualche commento ridondante come: "passo a fase x" e "stampo richiesta" che sono già cose autoevidenti:

Code: [Select]
case INTERAZIONE_UTENTE:
    if (first_pass) {
        Serial.println("Fase: INTERAZIONE UTENTE ");
        Serial.println("Se e` il Primo Avvio o vuoi Resettare premi [s] e attendi...");
    }

    if (trascorso >= 10) {                     // evento: timeout 10 secondi
        ePausa = false;                        // nessuna pausa 24 ore
        fase = RIEMPIMENTO_RABBOCCO;
    }
    else if (Serial.available() && (tolower(Serial.read()) == 's')) {  // evento: ricevuto 's'
        ePausa = true;                         // pausa 24 ore abilitata
        RTC.writenvram(8, giornoFuturo40gg);   // concimazione prevista
        RTC.writenvram(9, meseFuturo40gg);     // a 40 giorni da adesso
        fase = RIEMPIMENTO_RABBOCCO;
    }
break;
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 08, 2019, 11:58 am
Ma dentro lo sketch si possono usare le funzioni inline, uno cosa tipo,
Code: [Select]

#define ATTR_ALWAYS_INLINE           __attribute__ ((always_inline))
void inline fsmUpdate() ATTR_ALWAYS_INLINE;
void inline fsmUpdate() {
    first_pass = false;
    if (fase != old_fase) {
        first_pass = true;
        inizio_fase = millis();
    }
    old_fase = fase;
    trascorso = (millis() - inizio_fase) / 1000;
}


@karnhack
Certo è un modo originale di includere pezzi di codice, questa è la prima volta che vedo una suddivisione
di questo tipo. Io avevo pensato di inserire in un file le funzioni che lavorano sull'rtc, in un altro quelle che stampano, e così via. Comunque se tu ti ci ritrovi e funziona per adesso lo lasci così, tanto mentre studi, imparerai tante cose nuove che ti faranno cambiare idea mille volte.

Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 12:27 pm
Ok, e a cosa mi serve questa informazione in tutti i case che non siano il primo di interazione? Risposta: ma assolutamente a niente.
Ok me lo avevi detto che serve solo alla prima interazione...

2) Nel codice precedente azzeravi la nvram, qui ci scrivi dei valori, io non so quale delle due versioni è corretta, i commenti non mi aiutano, perché in base ad essi stai salvando il giorno della prima concimazione, e il mese della prossima irrigazione. Ma comunque viste la variabili 40 giorni si deduce che si sta salvando il momento della concimazione desiderato, esattamente 40 giorni nel futuro a partire dal momento del reset/primo avvio confermato con 's'.
Avevo comunicato i cambiamenti nel post #151. Dovendo rivedere tutto d'accapo ho preso in considerazione il consiglio di @maubarzi di andarci piano con l'NVRAM quindi ho pensato ad un altro modo e cioè nella fase interazione si da il valore alla bool ePausa (è pausa?).
Dunque se nella fase interazione scadono i 10 sec ePausa è falsa, diventa vera solo se si clicca S.

In questo modo quando si passa al CASE riposo, sarà quest'ultimo a dare le istruzioni quindi:


Aggiornamento: la scrittura dell'nvram può anche essere spostata nel case RIPOSO... se la condizione èPAUSA è vera (pausa è abilitato) aspetta 24h e quando parte l'irrigazione scrive la data su nvram. Per quanto riguarda la fase riposo la sto riscrivendo.

3) I commenti sulla variabile 'ePausa' non mi aiutano, perché vedo anch'io che viene messa a true o false, quello che non so è se true significa 'pausa 24 ore abilitata'... questo sarebbe un commento utile. E naturalmente da qualche altra parte ci dovrà poi essere una corrispondente disabilitazione per evitare che questa pausa venga successivamente ripetuta (visto che da quanto ho capito è da fare una sola volta).

E robettine minori, tipo meglio usare solo caratteri ASCII e non altri come le vocali accentate. Qualche commento ridondante come "passo a fase", "stampo richiesta" che sono già cose autoevidenti:
La disabilitazione di ePausa avviene ad ogni riavvio che vede il timeout di 10 secondi scadere. Per quanto riguarda i commenti provo a migliorarli, per i caratteri ASCII provvedo. Grazie ancora

Ma dentro lo sketch si possono usare le funzioni inline, uno cosa tipo,

@karnhack
Certo è un modo originale di includere pezzi di codice, questa è la prima volta che vedo una suddivisione
di questo tipo. Io avevo pensato di inserire in un file le funzioni che lavorano sull'rtc, in un altro quelle che stampano, e così via. Comunque se tu ti ci ritrovi e funziona per adesso lo lasci così, tanto mentre studi, imparerai tante cose nuove che ti faranno cambiare idea mille volte.

Ciao.
Ed infatti l'esempio da cui ho preso spunto (un fw per stampanti 3D) utilizza le classi inline e per ogni file.h dove sembra si definisce la classe, c'è un file dallo stesso nome file.cpp nel quale ci stanno le funzioni... però non volevo mettere troppa carne sul fuoco, ho testato con un unico file.h e funzionava...
Sto seguendo la via più ardua dello switch case proprio perchè voglio usare questo progetto come base di partenza per poi allenarmi ad inserire funzioni nuove e migliorarlo e sono d'accordo che imparando cambierò idee mille volte.  :smiley-mr-green:
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 08, 2019, 02:33 pm
Se è vero pausa 24h e IRRIGAZIONE (e scrittura nvram).
Dopo di che se non disabiliti 'ePausa' la troverai ancora true al rientro nello stato RIPOSO, e quindi si farà un'altra bella pausa...

A me continua a sembrare che la pausa debba essere un case a sé stante:
Code: [Select]
case PAUSA_24H:
    if (trascorso >= 86400) {  // evento: trascorso un giorno (86400 ±120 sec)
        fase = .....;
    }
break;


Quote
Sto seguendo la via più ardua dello switch case
:smiley-zipper:
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 03:00 pm
Dopo di che se non disabiliti 'ePausa' la troverai ancora true al rientro nello stato RIPOSO, e quindi si farà un'altra bella pausa...

A me continua a sembrare che la pausa debba essere un case a sé stante:
Code: [Select]
case PAUSA_24H:
    if (trascorso >= 86400) {  // evento: trascorso un giorno (86400 ±120 sec)
        fase = .....;
    }
break;

 :smiley-zipper:
Hai ragione sul fatto di disabilitare ePausa ed anche sul fatto di rimetterla su un case a parte. Tieni conto però che RIEMPIMENTO deve avvenire prima di PAUSA 24h, quindi dovrei mettere una condizione al case RIEMPIMENTO che se ePausa è ATTIVA il case successivo sarà PAUSA_24H mentre se ePausa è NONATTIVO il case successivo sarà RIPOSO. Nel case PAUSA_24H  imposto il timer e prima di passare alla fase IRRIGAZIONE rimetto ePause in false.

:smiley-zipper:
8)

In pratica così:

Code: [Select]

case PAUSA_24H:

if (trascorso >= 86400) {    // evento: trascorso un giorno (86400 sec)
    ePausa = NONATTIVO;    // imposto ePausa come falso
    fase = RIPOSO;              // fase riposo
    }
break;


Trascorso un giorno ho due vie, vai a fase RIPOSO oppure IRRIGA... certo che se trascorse le 24 ore salta di un minuto l'ora di start, la prossima irrigazione sarà il giorno dopo...
Mi sa che per la PAUSA conviene mettere un pausa fino a mezzanotte, dopodiché va in fase RIPOSO e se la vede lui...
Code: [Select]

if  (adessoOra == 1439) {    // quando l'ora attuale arriva alle 23:59
    ePausa = NONATTIVO;     // metti ePausa come non attivo false
    fase = RIPOSO;                 // passa a fase riposo
        }


Invece per quanto riguarda il RIEMPIMENTO prima della PAUSA ho fatto così

Code: [Select]

case RIEMPIMENTO_RABOCCO:
    
      if (first_pass) {
        Serial.println("Fase: RIEMPIMENTO / RABOCCO");
        }
        
        while (digitalRead(pinTroppopieno) == APERTO)   // finchè contatto aperto
        {
         digitalWrite(pinElettrovalvola, ACCESO);       // valvola aperta
        }
        {
         digitalWrite(pinElettrovalvola, SPENTO);       // poi chiudila
        }

      if (ePausa == ATTIVO)                             // Se ePausa è true, è attiva
        {
         fase = PAUSA_24H;                              // vai al case PAUSA_24
        }
        else
        {
         fase = RIPOSO;                                   // altrimenti vai al case RIPOSO    
        }
      
    break;
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 08, 2019, 04:13 pm
Non vedo errori ne di logica, ne di funzionamento.

Magari commenti inutili come:
Code: [Select]
fase = RIPOSO;              // fase riposoI commenti devono spiegare cosa si sta facendo nel caso in cui non sia chiaro, non descrivere l'istruzione C o ripetere il già ovvio :)

Nel riempimento toglierei il while bloccante lasciando ciclare il loop, la logica si semplifica in un semplice "quando il bidone è pieno faccio...":

Code: [Select]
case RIEMPIMENTO_RABBOCCO:
    if (first_pass) {
        Serial.println("Fase: RIEMPIMENTO / RABBOCCO");
        digitalWrite(pinElettrovalvola, ACCESO);   // valvola aperta
    }

    if (digitalRead(pinTroppopieno) == CHIUSO) {   // se bidone pieno
        digitalWrite(pinElettrovalvola, SPENTO);   // chiudi valvola
        if (ePausa) { fase = PAUSA_24H; }
        else        { fase = RIPOSO;    }
    }
break;

Code: [Select]
case PAUSA_24H:
    if (trascorso >= 86400) {    // se trascorso un giorno (86400 sec)
        ePausa = false;          // disabilito prossime pause
        fase = RIPOSO;
    }
break;

A me verrebbe comunque da aggiungere una sicurezza nel rabbocco:
Code: [Select]
else if (trascorso >= TEMPO_RIEMPIMENTO) {     // se timeout riempimento
    digitalWrite(pinElettrovalvola, SPENTO);
    fase = ALLARME;                            // contatto guasto o manca acqua
}
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 08, 2019, 04:46 pm
Ho fatto così

Code: [Select]

case RIEMPIMENTO_RABOCCO:
    
      if (first_pass) {
        Serial.println("Fase: RIEMPIMENTO / RABOCCO");
        digitalWrite(pinElettrovalvola, ACCESO);              // valvola aperta
        }

      if (digitalRead(pinTroppopieno) == CHIUSO) {       // se bidone pieno
          digitalWrite(pinElettrovalvola, SPENTO);            // chiudi valvola  
          if (ePausa == ATTIVO) { fase = PAUSA_24H; } // Se ePausa è true vai a PAUSA_24
          else                  { fase = RIPOSO;    }              // altrimenti vai a RIPOSO
          }
      else if (trascorso >= 180) {                                 // altrimenti se timeout supera i 3 minuti
          digitalWrite(pinElettrovalvola, SPENTO);           // chiudi valvola
          fase = ALLARME;                                            // vai ad allarme per guasto o manca acqua
          }
    
    break;


Però per quanto riguarda il guasto non saprei che fare oltre ad introdurre un beep o lcd, per ora ho considerato solo la mancanza d'acqua e prova a riempire ogni ora

Code: [Select]

case ALLARME:

      if (trascorso >= 3600) {                          // dopo un ora
        fase = RIEMPIMENTO_RABOCCO;                     // riprova a riempire andando alla fase RIEMPIMENTO_RABOCCO
      }
      
    break;


 Aggiornamento: Sembra funzionare tutto manca solo la gestione del motore in concimazione! :smiley-mr-green:  allego il file.
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 09, 2019, 09:45 am
Mi sembra che la retta via sia stata imboccata 8)

Solo un appunto sulle variabili bool come 'ePausa'.

Sono nate per chiarezza per non stare li a fare test come if(a == 1) (qualche compilatore probabilmente le tratta come singoli bit, ma su Arduino occupano comunque un intero byte), e sempre per  chiarezza hanno aggiunto true e false come alias di 1 e 0.

Se alle variabili bool si danno nomi domanda (a cui rispondere solo si/no), il confronto con true/false è del tutto ridondante, in effetti la 'ePausa' potrebbe forse essere chiamata in modo più autodescrittivo 'pausa_abilitata', e nei test sarebbe sufficiente scrivere if(pausa_abilitata) (senza bisogno di alcun confronto esplicito con 1/0 true/false, e senza necessità di commenti per spiegare cosa fa quella variabile).

Ma comunque sono finezze, come i nomi descrittivi al posto dei numeri. Il codice mi sembra già molto più chiaro di quello scritto da persone che programmano da anni ma non applicano questi accorgimenti.
Title: Re: Irrigazione automatica
Post by: Maurotec on Jun 10, 2019, 01:10 am
Code: [Select]

case RIPOSO:
...

else if ((adessoOra == orarioStart) // se l'ora attuale è uguale a orarioStart
      && (adessoGiorno = giornoNVRAM)     // se il giono nvram è uguale a quello attuale
      && (adessoMese = meseNVRAM))        // se il mese nvram è uguale a quello attuale
      {
        fase = CONCIMAZIONE;              // concimazione
      }


Le ultime due condizioni vengono valutate vera, in quanto si tratta di una assegnazione '=', mentre vogliamo verificare l'eguaglianza '=='.

ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 11, 2019, 03:45 am
Ho trovato l'RTC con la data sbagliata, pensavo di aver omesso qualcosa nel codice ma probabilmente ha la batteria scarica dal magazzino... guardando meglio l'ho vista leggermente gonfia ed scoperto che il TinyRTC fa passare una piccola carica di corrente nella batteria per ricaricarla, ma le batterie consigliate sono le CR2032 (e su altri manuali leggo CR1225) che non sono affatto ricaricabili! Le ricaricabili sono le LIR2032 che però hanno un voltaggio leggermente superiore di 3.6v anziché i 3v della CR2032...  :o
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Jun 11, 2019, 05:50 am
guardando meglio l'ho vista leggermente gonfia ed scoperto che il TinyRTC fa passare una piccola carica di corrente nella batteria per ricaricarla
Vero, qui sul forum abbiamo già a avuto scoppi di pile su RTC alimentati a 5V. Basta asportare il diodo D1.
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 14, 2019, 10:03 am
Vero, qui sul forum abbiamo già a avuto scoppi di pile su RTC alimentati a 5V. Basta asportare il diodo D1.
Scusate i ritardi nelle risposte ma a quanto pare è iniziato un periodo di sbattimento... Per il momento vorrei provare ad usare le LIR2032 prima di dissaldare il diodo, anche perché le ho viste utilizzare anche in altri progetti (http://www.brescianet.com/appunti/Elettronica/Arduino/corso/Esempio_RTC.htm).
 
Nel frattempo ho ordinato un po di componentistica come la valvola meccanica, una basetta millefori, un interruttorino di finecorsa e sto dando un occhiata per prendere un elettrovalvola decente.
Per quanto riguarda la movimentazione della pompa peristaltica, avendo già gli easydriver da vecchi progettinho visto che non è un operazione difficile visto che basta indicare solo la direzione di rotazione, la velocità di rotazione ed il numero di giri. Quindi non mi resta che disegnarmi la pompa peristaltica e poi fare delle prove per capire le quantità di liquido che si muove per ogni rotazione... non voglio perdermi in calcoli inutili anche perchè non userò tubi per peristaltica (che costano un occhio) ma un semplice tubo morbido in silicone che oltre a non essere preciso al centesimo di mm, non essendo fatto per questo scopo, credo soffrirà anche di "ernie" (ne so qualcosa visto che ho fatto per molti anni la manutenzione di alcuni plotter) per cui credo mi convenga procedere empiricamente provando e misurando.
In ogni caso l'irrigatore è già funzionante perchè la fase CONCIMAZIONE al momento scrive solo la  data di concimazione su nvram e poi salta subito all'irrigazione
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 28, 2019, 08:02 pm
C'è qualche motivo per cui questo progetto non funziona su arduino nano? Lo sto provando sul nano ma non funziona correttamente e in fase di riempimento va dritto, il relè si accende per un attimo e passa alla fase successiva. Mi stavo chiedendo se fosse una questione di pin (ho scelto pin digitali 2, 3 e 4)
Title: Re: Irrigazione automatica
Post by: gpb01 on Jun 28, 2019, 08:17 pm
La Nano è esattamente come la UNO (monta lo stesso ATmega328P), cambiano solo le dimensioni, poi ...
... come sempre, ci sono le Nano ufficiali da 16€ e le Nano cinesi da 1.2€ ... ::)

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on Jun 28, 2019, 08:53 pm
In effetti sto usando un clone ma l'originale è in arrivo... spesso uso i cloni per testare ma poi il progetto finale lo faccio andare con l'originale
Title: Re: Irrigazione automatica
Post by: gpb01 on Jun 28, 2019, 09:09 pm
In effetti sto usando un clone ma l'originale è in arrivo...
... comunque controlla bene tutti i collegamenti perché, salvo casi di prodotti veramente "di scarto" (... e ce ne sono tanti), i cloni vanno bene tanto quanto un originale quindi ... fatti tutte le verifiche ;)

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 24, 2019, 01:06 pm
Come al mio solito, ho fritto tutto mandando in corto un pin Arduino e l'rtc... fortunatamente era un clone :)
Nel frattempo mi è arrivato l'arduino nano originale ed inoltre ho preso un RTC DS3231 al posto del 1307.

Ovviamente ho dei problemi con la nuova configurazione... Ho eliminato la libreria RTC di Adafruit ed ho installato al suo posto la libreria RTClib by NeiroN. Ho fatto questo cambio di libreria per non riconfigurare tutto, perché da esempi visti in rete mi è sembrato di capire che questa libreria usa gli stessi comandi della 1307 (now.hour, now.month ecc.) altrimenti avrei dovuto cambiare tutti i riferimenti.

Ora gli unici due errori che ho nella compilazione riguardano l'NVRAM e la funzione TimeSpan con cui ottenevo le date future per irrigazione e concimazione.

Code: [Select]
DateTime futuro40gg (now + TimeSpan(40,0,0,0)); // aggiunge 40gg al settore giorni (gg, hh, mm, ss)

La scelta di prendere  il DS3231 è motivata dal fatto che oltre ad essere più preciso, può utilizzare la libreria TimeAlarms.h ed in questo modo volevo eliminare sia la scrittura NVRAM che il calcolo della data tramite TimesSpan

Ora però non riesco a capire come utilizzare la libreria TimeAlarms.h...
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 24, 2019, 01:31 pm
Forse ho trovato come calcolare gli allarmi direttamente dalla libreria RTClib by Neiron che riporta questo esempio   che però non è commentato e non ci capisco molto...

Code: [Select]
void setup () {
    Serial.begin(57600);
   
    DateTime dt0 (0, 1, 1, 0, 0, 0);
    showDate("dt0", dt0);

    DateTime dt1 (1, 1, 1, 0, 0, 0);
    showDate("dt1", dt1);

    DateTime dt2 (2009, 1, 1, 0, 0, 0);
    showDate("dt2", dt2);

    DateTime dt3 (2009, 1, 2, 0, 0, 0);
    showDate("dt3", dt3);

    DateTime dt4 (2009, 1, 27, 0, 0, 0);
    showDate("dt4", dt4);

    DateTime dt5 (2009, 2, 27, 0, 0, 0);
    showDate("dt5", dt5);

    DateTime dt6 (2009, 12, 27, 0, 0, 0);
    showDate("dt6", dt6);

    DateTime dt7 (dt6.unixtime() + 3600); // one hour later
    showDate("dt7", dt7);

    DateTime dt8 (dt6.unixtime() + 86400L); // one day later
    showDate("dt8", dt8);

    DateTime dt9 (dt6.unixtime() + 7 * 86400L); // one week later
    showDate("dt9", dt9);
}

void loop () {
}
Title: Re: Irrigazione automatica
Post by: Silente on Jul 24, 2019, 02:50 pm
Visto che stai usando un RTC, tramite il quale conosci data e ora puoi anche trasformare tali informazioni in un unico numero ("unixtime") e usarle tipo millis() per crearti tu i timer, senza usare codici che non capisci (e che non capisco nemmeno io)
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 24, 2019, 03:37 pm
Forse ho trovato come calcolare gli allarmi direttamente dalla libreria RTClib by Neiron che riporta questo esempio   che però non è commentato e non ci capisco molto...
Con il DS3231 è possibile avere un allarme ad un determinato orario (credo vada aggiunta anche la data) oppure è possibile avere un allarme quando l'ora, i minuti e i secondi diventano una certa cifra.

Ad esempio puoi impostare l'allarme quando i minuti sono a zero, scatterà ogni ora.
Le possibilità sono descritte nel datasheet nella tabella
Table 2. Alarm Mask Bits

In genere però la libreria RTClib e derivate non gestiscono tutte le possibilità oppure non gestiscono alcun allarme.
Se non ricordo male lo fanno queste
https://github.com/JChristensen/DS3232RTC (https://github.com/JChristensen/DS3232RTC)
https://github.com/FabioCuomo/FabioCuomo-DS3231/ (https://github.com/FabioCuomo/FabioCuomo-DS3231/)
ma ce ne saranno sicuramente altre.
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 24, 2019, 04:59 pm
In pratica ho tre allarmi da impostare e cioè:
- Quello estivo quotidiano, tutti i giorni alla stessa ora.
- Quello invernale per esempio Lunedì e Giovedì o addirittura un solo giorno a settimana (funzione nuova che devo inserire perché non avevo pensato al fatto che d'inverno l'annaffiatura quotidiana non serve)
- Quello ogni 40gg per la concimazione

Esiste già una variabile che irriga di mattina o di sera in base alla stagione invernale-estiva. Altra variabile che dovrò inserire è per la concimazione che non va fatta d'inverno.

Se non ricordo male lo fanno queste
https://github.com/JChristensen/DS3232RTC (https://github.com/JChristensen/DS3232RTC)
https://github.com/FabioCuomo/FabioCuomo-DS3231/ (https://github.com/FabioCuomo/FabioCuomo-DS3231/)
ma ce ne saranno sicuramente altre.
La libreria di JChristensen sembra fare al caso mio:
Code: [Select]
ALM1_EVERY_SECOND -- causes an alarm once per second.
ALM1_MATCH_SECONDS -- causes an alarm when the seconds match (i.e. once per minute).
ALM1_MATCH_MINUTES -- causes an alarm when the minutes and seconds match.
ALM1_MATCH_HOURS -- causes an alarm when the hours and minutes and seconds match.
ALM1_MATCH_DATE -- causes an alarm when the date of the month and hours and minutes and seconds match.
ALM1_MATCH_DAY -- causes an alarm when the day of the week and hours and minutes and seconds match.


Quello che non mi è chiaro : se prendo giorno e mese dall'RTC, per esempio 31-12 e aggiungo tramite variabile 1 giorno ed 1 mese... come faccio a far si che la data sia 1-1 e non 32-13? (non so se mi sono spiegato). Dovrebbe essere una funzione interna alla libreria altrimenti mi conviene ricavare tutto da me senza l'ausilio di altro
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 24, 2019, 05:23 pm
La libreria di JChristensen sembra fare al caso mio:
Attenzione: quella libreria, che trovo comodissima, gestisce solo due allarmi (quelli del RTC, ALM1 al secondo, ALM2 al minuto), questo significa che ne puoi avere solo due attivi contemporaneamente.
Significa che quando scatta l'allarme, lo devi reimpostare per il successivo.
Nel tuo caso, potresti usare ALM1 per l'irrigazione, che quindi va reimpostato in funzione della stagione ogni volta che scatta, e ALM2 per la concimazione, che quindi va reimpostato "tra 40 gg" ogni volta che scatta.

Detto questo, però, visto che siamo già a 180 post, probabilmente il tuo codice è già funzionante o comunque a buon punto, quindi verifica bene se è il caso di ricominciare daccapo con altra logica per gli allarmi!!!
Non ho letto tutto il thread, ma sicuramente dovresti fare molte modifiche.


Federico

Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 10:13 am
Ho riutilizzato la libreria RTClib di adafruit, il problema era solo legato alla sigla rtc scritta in minuscolo, sostituita quella si è risolto tutto e la benedetta funzione TimeSpan ora funziona  :)
Ho però dovuto utilizzare la libreria RTC_DS3231 al posto di RTC_DS1307 ed ora l'unico problema che rimane è quello del comando readnvram che non riconosce... e poi dovrei capire quali sono i settori scrivibili dell'NVRAM del DS3231

Code: [Select]
error: 'class RTC_DS3231' has no member named 'readnvram'

AGGIORNAMENTO: A quanto pare il DS3231 non ha NVRAM disponibile per l'utente quindi come potrei fare?
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 25, 2019, 10:29 am
Il DS3231 non mi pare abbia dei registri utilizzabili per memorizzare dati ma di solito nelle board è presente una memoria flash I2C 24c32 che invece può essere utilizzata e che non perde i dati neanche se rimuovi la batteria.
In rete ci dovrebbero essere librerie che ne fanno uso tipo questa
https://github.com/cyberp/AT24Cx (https://github.com/cyberp/AT24Cx)
ma ce ne sono diverse.

Edit: nn articolo di Alfieri di alcuni giorni fa sulla 24C02, il modello più piccolo
http://www.mauroalfieri.it/elettronica/i2c-eeprom-at24c02.html (http://www.mauroalfieri.it/elettronica/i2c-eeprom-at24c02.html)
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 25, 2019, 10:43 am
Il DS3231 non mi pare abbia dei registri utilizzabili per memorizzare dati ...
Confermo, quel modulo non spazio utilizzabile dall'utente.


Federico
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 10:56 am
Il DS3231 non mi pare abbia dei registri utilizzabili per memorizzare dati ma di solito nelle board è presente una memoria flash I2C 24c32 che invece può essere utilizzata e che non perde i dati neanche se rimuovi la batteria.
In rete ci dovrebbero essere librerie che ne fanno uso tipo questa
https://github.com/cyberp/AT24Cx (https://github.com/cyberp/AT24Cx)
ma ce ne sono diverse.
Grazie zoomx, ho risolto
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 11:42 am
Uff in realtà non ho risolto, scusatemi. Il problema è che non ci capisco nulla coi datasheet...
Sul chip c'è scritto:

ATHYC532
24C32N
SU27 D

Ho inserito la libreria AT24CX.h poi come da esempi la richiamo con mem:
Code: [Select]
AT24CX mem;

e la scrivo

Code: [Select]

mem.write(0x0C, giornoFuturo40gg);         // Primo avvio o reset, scrivo il giorno della prima concimazione su nvram
mem.write(0x0D, meseFuturo40gg);          // scrivo il mese della prossima irrigazione su nvram


mi è parso di capire che i settori scrivibile partono dal 12 è quindi in esadecimale ho scritto su 0x0C e 0x0D (ho difficolta a capire tra guide inglesi e tedesche aggiunte alla mia ignoranza  :smiley-roll-blue: )

poi vado a leggerla con
Code: [Select]

giornoNVRAM = mem.read(0x0C);        // ricava il giorno da nvram
meseNVRAM = mem.read(0x0D);          // ricava il mese da nvram


Il problema però è che legge 0 su tutti e due i campi. Forse sbaglio settore di scrittura?
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 25, 2019, 11:58 am
Potrebbe essere un problema di indirizzo I2C, usa l'esempio AT24CX_search_IC.ino oppure uno scanner di indirizzi I2C.

Mi sa che tra le librerie esistenti te ne ho indicata una non semplicissima e mi pare anche spiegata male.
Questo tipo di memorie hanno 8 indirizzi I2C disponibili per cui se si usa il primo basta l'istruzione
AT24C32();
altrimenti ci vuole
AT24C32(byte index);

Ora da quello che leggo il modulo dovrebbe avere la memoria all'indirizzo 0x56 che, nella tabella della pagina in tedesco, sarebbe il settimo per cui immagino che vada usata l'istruzione
AT24C32(6);  //ricordiamoci che si parte da zero!
Da mettere nel setup.

Il bello è che nell'esempio il tizio questa istruzione non la mette.

Edit: altrove ho letto che l'indirizzo potrebbe essere 0x57 per cui è meglio far girare uno scanner.
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 03:19 pm
Code: [Select]
12:28:17.971 -> Search at [50]: not found
12:28:17.971 -> Search at [51]: not found
12:28:17.971 -> Search at [52]: not found
12:28:17.971 -> Search at [53]: not found
12:28:17.971 -> Search at [54]: not found
12:28:17.971 -> Search at [55]: not found
12:28:17.971 -> Search at [56]: not found
12:28:17.971 -> Search at [57]: FOUND!


Non ho capito bene perché va nel setup... in pratica è come se gli stessi dicendo che la zona di scrittura parte dal 57? Quindi nel setup dovrei inserire

AT24C32(57);

Ed avendo 8 indirizzi disponibili posso andare a scrivere i dati in 57 e 58?
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 25, 2019, 03:40 pm
No
AT24C32(7);
ha l'indirizzo 0x57 che nella tabella sarebbe l'ottavo ma che siccome l'indice parte da zero diventa 7
il tizio parla di indici partendo da zero che è il default.
Questo perché potresti avere 8 differenti memorie AT24C32 contemporaneamente.


Certo che è un po' ufficio complicazione affari semplici. Se dentro ci mettevi l'indirizzo faceva prima, invece no.
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 04:03 pm
Chi ci capisce e bravo...

Scrivo giorno e mese sui settori 7 ed 8
Code: [Select]

mem.write(7, giornoFuturo40gg);   // Primo avvio o reset, scrivo il giorno della prima concimazione su nvram
mem.write(8, meseFuturo40gg);    // scrivo il mese della prossima irrigazione su nvram


Poi li vado a leggere

Code: [Select]

giornoNVRAM = mem.read(7);        // ricava il giorno da nvram
meseNVRAM = mem.read(8);          // ricava il mese da nvram


Ma ottengo sempre 0
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 25, 2019, 04:29 pm
Prova questo
Code: [Select]
#include <AT24CX.h>

AT24CX mem;


void setup() {
  Serial.begin(115200);
  Serial.println("AT24CX");
  AT24C32(7);
  mem.write(0x0C, 21);
  mem.write(0x0D, 8);
  Serial.println(mem.read(0x0C));
  Serial.println(mem.read(0x0D));

}

void loop() {

}


Dovrebbe stampare 21 e 8.
Non ho l'hardware sottomano.
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 25, 2019, 05:31 pm
Prova questo
Code: [Select]
#include <AT24CX.h>

AT24CX mem;


void setup() {
  Serial.begin(115200);
  Serial.println("AT24CX");
  AT24C32(7);
  mem.write(0x0C, 21);
  mem.write(0x0D, 8);
  Serial.println(mem.read(0x0C));
  Serial.println(mem.read(0x0D));

}

void loop() {

}


Dovrebbe stampare 21 e 8.
Non ho l'hardware sottomano.
Non va, ho provato a modificare gli hex da 0x00 fino a 0x8F e scrive sempre 0
Title: Re: Irrigazione automatica
Post by: gpb01 on Jul 25, 2019, 05:48 pm
Certo che è un po' ufficio complicazione affari semplici. Se dentro ci mettevi l'indirizzo faceva prima, invece no.
In realtà è più semplice di quello che sembri ...
... di base, in AT24CX.h, c'è una riga che dichiara:

Code: [Select]
#define AT24CX_ID B1010000
... ovvero, definisce un indirizzo di base 0x50.

A questo punto, nel modulo AT24CX.cpp c'è una semplice riga che somma a tale valore il valore che si passa:

Code: [Select]
_id = AT24CX_ID | (index & 0x7);
... dove _id è l'indirizzo I2C che viene usato, quindi ... è giusto passare da 0 a 7 a seconda di come sono impostati i tre pin A0, A1 ed A2 sulla breakout board.

Guglielmo

P.S.: ... non ho seguito tutto il thread ... c'è un motivo particolare perché scrivete nelle celle 0x0C e 0x0D e non nelle prime due celle 0x00 e 0x01 ?
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 25, 2019, 06:29 pm
Incuriosito e avendo sotto mano un DS3231, ho fatto un test e confermo che non funzia, o meglio funziona solo con i char!

Codice di test (AT24CX_demo):
Code: [Select]

#include <Wire.h>
#include <AT24CX.h>

// EEPROM object
AT24CX mem;

// setup
void setup() {
  // serial init
  Serial.begin(115200);
  Serial.println("AT24CX read/write demo");
  Serial.println("----------------------");

  AT24C32(7); //0x57

  Serial.println("Write 42 to address 12");
  mem.write(12, 42);
  Serial.println("Read byte from address 12 ...");
  byte b = mem.read(12);
  Serial.print("... read: ");
  Serial.println(b, DEC);
  Serial.println();

  // read and write integer
  Serial.println("Write 65000 to address 15");
  mem.writeInt(15, 65000);
  Serial.println("Read integer from address 15 ...");
  unsigned int i = mem.readInt(15);
  Serial.print("... read: ");
  Serial.println(i, DEC);
  Serial.println();

  // read and write long
  Serial.println("Write 3293732729 to address 20");
  mem.writeLong(20, 3293732729UL);
  Serial.println("Read long from address 20 ...");
  unsigned long l = mem.readLong(20);
  Serial.print("... read: ");
  Serial.println(l, DEC);
  Serial.println();

  // read and write long
  Serial.println("Write 1111111111 to address 31");
  mem.writeLong(31, 1111111111);
  Serial.println("Read long from address 31 ...");
  unsigned long l2 = mem.readLong(31);
  Serial.print("... read: ");
  Serial.println(l2, DEC);
  Serial.println();

  // read and write float
  Serial.println("Write 3.14 to address 40");
  mem.writeFloat(40, 3.14);
  Serial.println("Read float from address 40 ...");
  float f = mem.readFloat(40);
  Serial.print("... read: ");
  Serial.println(f, DEC);
  Serial.println();

  // read and write double
  Serial.println("Write 3.14159265359 to address 50");
  mem.writeDouble(50, 3.14159265359);
  Serial.println("Read double from address 50 ...");
  double d = mem.readDouble(50);
  Serial.print("... read: ");
  Serial.println(d, DEC);
  Serial.println();

  // read and write char
  Serial.print("Write chars: '");
  char msg[] = "This is a message";
  Serial.print(msg);
  Serial.println("' to address 200");
  mem.writeChars(200, msg, sizeof(msg));
  Serial.println("Read chars from address 200 ...");
  char msg2[30];
  mem.readChars(200, msg2, sizeof(msg2));
  Serial.print("... read: '");
  Serial.print(msg2);
  Serial.println("'");
  Serial.println();

}


Output:
Code: [Select]

AT24CX read/write demo
----------------------
Write 42 to address 12
Read byte from address 12 ...
... read: 0

Write 65000 to address 15
Read integer from address 15 ...
... read: 0

Write 3293732729 to address 20
Read long from address 20 ...
... read: 0

Write 1111111111 to address 31
Read long from address 31 ...
... read: 0

Write 3.14 to address 40
Read float from address 40 ...
... read: 0.0000000000

Write 3.14159265359 to address 50
Read double from address 50 ...
... read: 0.0000000000

Write chars: 'This is a message' to address 200
Read chars from address 200 ...
... read: '=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZThis is a message'



Adesso non ho tempo di indagare, ma è curioso  ::)  ::)


Federico


PS
Non ho voglia di leggere tutto il thread, ma perchè non usi la eeprom di arduino, quanta roba devi scriverci?
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 06:48 pm
In realtà  Non funziona nemmeno coi char
Però  dal tipo di malfunzionamento ho avuto idea
Appena a casa, non dal furbofono, ne scrivo
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 07:03 pm
all'ora, per federico: tu in pratica hai usato uno degli esempi della libreria (anzi, l'unico esempio)
non va, nemmeno per i char
tu hai scritto (o tentato di scrivere, adesso vediamo) all'indirizzo 200 una stringa lunga 17 (array di char lungo 18, col terminatore automatico)
ok, poi hai tentato di leggerla in un array di char lungo 30, che si sarebbe dovuto popolare fino a 18 terminatore compreso (sì, in realtà si sarebbe popolato tutto, ma in stampa alla posizione 18 il terminatore avrebbe fermato la stampa)
NON è stato così, la posizione 0 dell'array NON contiene l'inizio della stringa, e via così....
io faccio ipotesi che la lettura NON sia andata a buon fine, e l'array di caratteri NON è stato popolato
essendo una variabile locale è "nata sporca", e quindi in stampa qualcosa esce, e siccome per caso non c'era terminatore la stampa è andata avanti molto oltre il carattere 30 (fine dello array, che in 'C' non c'è controllo di non sbordare) e per caso li era registrato il primo dei due array
quindi la lettura NON è mai andata a buon fine
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 25, 2019, 07:05 pm
Non è che la flash va a pagine e che ci vuole un comando per scrivere la pagina?

Suggerisco di cambiare libreria.
https://github.com/jlesech/Eeprom24C32_64 (https://github.com/jlesech/Eeprom24C32_64)
Questa gestisce sia il DS3231 che la memoria
https://github.com/sleemanj/DS3231_Simple (https://github.com/sleemanj/DS3231_Simple)

https://github.com/wSmithyeah/AT24C32 (https://github.com/wSmithyeah/AT24C32)
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 07:14 pm
puo' essere
comunque, visto che l'esempio va (altrimenti chissa' quanti ne avrebbero scritto su github) è la nostra implementazione che non va
l'unica vera differenza tra la versione che usiamo
(giusta regola non devo appropriarmi dei vostri meriti, usate voi, io sono appena arrivato)
e la versione dell'esempio è nell'indirizzo io ipotizzo un errore nell'inizializzazione dell'indirizzo

propongo di provare
Code: [Select]

#include <Wire.h>
#include <AT24CX.h>

// EEPROM object
AT24CX mem(7,32);

// setup
void setup() {
  // serial init
  Serial.begin(115200);
  Serial.println("AT24CX read/write demo");
  Serial.println("----------------------");


  Serial.println("Write 42 to address 12");
  mem.write(12, 42);
  Serial.println("Read byte from address 12 ...");
  byte b = mem.read(12);
  Serial.print("... read: ");
  Serial.println(b, DEC);
  Serial.println();

  // read and write integer
  Serial.println("Write 65000 to address 15");
  mem.writeInt(15, 65000);
  Serial.println("Read integer from address 15 ...");
  unsigned int i = mem.readInt(15);
  Serial.print("... read: ");
  Serial.println(i, DEC);
  Serial.println();

  // read and write long
  Serial.println("Write 3293732729 to address 20");
  mem.writeLong(20, 3293732729UL);
  Serial.println("Read long from address 20 ...");
  unsigned long l = mem.readLong(20);
  Serial.print("... read: ");
  Serial.println(l, DEC);
  Serial.println();

  // read and write long
  Serial.println("Write 1111111111 to address 31");
  mem.writeLong(31, 1111111111);
  Serial.println("Read long from address 31 ...");
  unsigned long l2 = mem.readLong(31);
  Serial.print("... read: ");
  Serial.println(l2, DEC);
  Serial.println();

  // read and write float
  Serial.println("Write 3.14 to address 40");
  mem.writeFloat(40, 3.14);
  Serial.println("Read float from address 40 ...");
  float f = mem.readFloat(40);
  Serial.print("... read: ");
  Serial.println(f, DEC);
  Serial.println();

  // read and write double
  Serial.println("Write 3.14159265359 to address 50");
  mem.writeDouble(50, 3.14159265359);
  Serial.println("Read double from address 50 ...");
  double d = mem.readDouble(50);
  Serial.print("... read: ");
  Serial.println(d, DEC);
  Serial.println();

  // read and write char
  Serial.print("Write chars: '");
  char msg[] = "This is a message";
  Serial.print(msg);
  Serial.println("' to address 200");
  mem.writeChars(200, msg, sizeof(msg));
  Serial.println("Read chars from address 200 ...");
  char msg2[30];
  mem.readChars(200, msg2, sizeof(msg2));
  Serial.print("... read: '");
  Serial.print(msg2);
  Serial.println("'");
  Serial.println();

}


io non ho l'hardware, quindi non so se va
ma guardando la libreria sembra che se l'operazione NON va a buon fine ritorna comunque senza segnalazione d'errore
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 25, 2019, 07:33 pm
propongo di provare
...e un bravo a @Standardoil :)

mea culpa, effettivamente, nella fretta ho fatto girare l'esempio senza leggere il reference :(

Confermo che iniziandola correttamente, funziona
Code: [Select]

 AT24CX mem(7, 32);
 oppure
 AT24C32 mem(7);


Code: [Select]

AT24CX read/write demo
----------------------
Write 42 to address 12
Read byte from address 12 ...
... read: 42

Write 65000 to address 15
Read integer from address 15 ...
... read: 65000

Write 3293732729 to address 20
Read long from address 20 ...
... read: 3293732729

Write 1111111111 to address 31
Read long from address 31 ...
... read: 1111111111

Write 3.14 to address 40
Read float from address 40 ...
... read: 3.1400001049

Write 3.14159265359 to address 50
Read double from address 50 ...
... read: 3.1415927410

Write chars: 'This is a message' to address 200
Read chars from address 200 ...
... read: 'This is a message'



Federico
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 07:54 pm
Ok,vedo anche un karma aggiunto, grazie
ma, permttetemi di dirlo in una lingua neolatina a caso:
pero ahora vamos acabar com essa sujeira
ovvero, quagliamo qualcosa, 13 pagine sono troppe da seguire
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 25, 2019, 08:00 pm
Ok,vedo anche un karma aggiunto, grazie
è il mio, perchè mi hai bacchettato con classe :)

per il resto, non so che dire, mi sono intromesso perchè mi incuriosiva il fatto di poter utilizzare AT24C32 sul DS3231, non che mi serva, ma come si dice, impara l'arte e mettila da parte :)

Federico
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 08:28 pm
anch'io mi sono intromesso stessa ragione
mi dispiace che tu ti sia sentito bacchettato, non volevo, non ra mia intenzione e comunque non lo meritavi
cosa te lo ha fatto credere?
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 25, 2019, 08:57 pm
cosa te lo ha fatto credere?
... ma no, era più una battuta... in ogni caso avresti potuto urlarmi che è meglio leggere il reference prima di usare una libreria :)

e pensare che proprio stamattina ho detto la stessa cosa ad un tizio per lo stesso motivo :)


Federico
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 25, 2019, 09:29 pm
vorrei spiegarmi
nemmeno io non ho letto il reference
ho ipotizzato che non andasse perchè "non mi è piaciuta" l'inizializzazione
dato che ipotizzavo onn andasse
ho pensato per quale ragione poteva "sembrare" che andasse solo per i char,
da li ho ipotizzato cosa (non) scriveva la libreria,
ho quindi "confermato" che non andava
e "ipotizzato" una diversa maniera per inizilizzare
il tutto lo ho fatto "in diretta" scrivendolo mentre lo pensavo
non era un "pistolotto" ma una considerazione, un libero pensiero.....
fortuna che non ti sei offeso....
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 26, 2019, 08:59 am
Diavolo, hai ragione eccome
Code: [Select]
uses the device with index 0 and given page size. You can select a device with given index between 0 and 8 with constructor
AT24CX(byte index, byte pageSize);


Io invece mi ero fatto distrarre dall'ultima parte

Code: [Select]
Alternative you can use the individual classes with predefined page sizes:
AT24C32();
AT24C64();
AT24C128();
AT24C256();
AT24C512();
or with different index than 0:
AT24C32(byte index);
AT24C64(byte index);
AT24C128(byte index);
AT24C256(byte index);
AT24C512(byte index);


Per cui si poteva scrivere
AT24C32(7) mem;
se non ho capito male.
Title: Re: Irrigazione automatica
Post by: gpb01 on Jul 26, 2019, 09:12 am
... difatti c'è qualche cosa che NON mi quadra ... nel tuo post #188 leggo chiaramente "AT24C32(7);" che è corretto, difatti, dal .cpp della libreria si ha:

Code: [Select]
/**
 * Constructor with AT24Cx EEPROM at given index
 */
AT24C32::AT24C32(byte index) {
init(index, 32);
}

... ed, a seguire ...

Code: [Select]
/**
 * Init
 */
void AT24CX::init(byte index, byte pageSize) {
_id = AT24CX_ID | (index & 0x7);
_pageSize = pageSize;
Wire.begin();
}

... ovvero fa esattamente la stessa cosa per cui ... perché non dovrebbe funzionare ? ? ?

Guglielmo

EDIT: ... ok, capito, lo avevi messo come riga a se stante invece che come costruttore ;)
Title: Re: Irrigazione automatica
Post by: zoomx on Jul 26, 2019, 09:26 am
Infatti, dalla documentazione mi era sembrato che andava messo nel setup, invece andava nel costruttore.
Ma io non sono un programmatore di firmware per Airbus A350 !!!!
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 26, 2019, 09:35 am
Infatti, dalla documentazione mi era sembrato che andava messo nel setup, invece andava nel costruttore.
Ma io non sono un programmatore di firmware per Airbus A350 !!!!
Tranquillo,la documentazione è scritta veramente male, e l'esempio altrettanto! :)


Federico
Title: Re: Irrigazione automatica
Post by: gpb01 on Jul 26, 2019, 09:38 am
Ma io non sono un programmatore di firmware per Airbus A350 !!!!
(http://www.nikonland.eu/forum/public/style_emoticons/default/post-42-1201873916.gif)

Guglielmo

P.S.: ... per chi non l'avesse capita ... QUESTO (https://www.theregister.co.uk/2019/07/25/a350_power_cycle_software_bug_149_hours/) articolo chiarisce ... :D
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 26, 2019, 09:46 am
fortuna che non ti sei offeso....
tranquillo, il giorno che mi offenderò, lo capirai ... e non ti darò un karma ;)

frequento per imparare, e la tua veloce deduzione del problema guardando il risultato mi ha colpito,
avevo notato qualcosa di strano, ma non riuscivo a capire, probabilmente avrei impiegato ore...

Federico

PS
ora basta, questa discussione sta diventando melensa :)



Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 26, 2019, 10:05 am
(http://www.nikonland.eu/forum/public/style_emoticons/default/post-42-1201873916.gif)

Guglielmo

P.S.: ... per chi non l'avesse capita ... QUESTO (https://www.theregister.co.uk/2019/07/25/a350_power_cycle_software_bug_149_hours/) articolo chiarisce ... :D
io invece avevo capito che si riferiva ai miei ingannieri...
Oggia' airbus la abbiamo persa....
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 26, 2019, 10:18 am
E aggiungo
Oddiobbono c'è una prescrizione di aeronavigabilitá ... Spegnere e riaccendere...
Micro$oft docet

Sembra proprio una caxella dei miei ingannieri...
Title: Re: Irrigazione automatica
Post by: gpb01 on Jul 26, 2019, 10:26 am
... Micro$oft docet
... lo dico sempre che Micro$oft con il suo CTRL-ALT-DEL ha rovinato intere generazioni :D :D :D

Guglielmo
Title: Re: Irrigazione automatica
Post by: Federico66 on Jul 26, 2019, 10:45 am


(https://img.buzzfeed.com/buzzfeed-static/static/2017-08/14/18/campaign_images/buzzfeed-prod-fastlane-03/37-times-the-it-crowd-characters-were-the-most-ic-2-25004-1502748398-2_dblbig.jpg)


PS
Per chi non sapesse, "The IT Crowd" è una sitcom inglese nella quale ""Ha provato a spegnerlo e riaccenderlo?", è la soluzione ad ogni problema informatico :)

@Guglielmo, naturalmente puoi ripulire :)


Title: Re: Irrigazione automatica
Post by: karnhack on Jul 26, 2019, 12:31 pm
Grazie ragazzi, con l'esempio di Standardoil ho risolto. Vedervi discutere mi incoraggia, perché un novello come me è portato a pensare che il problema è solo suo che non capisce, invece dai vostri discorsi si evince che anche un professionista ha bisogno di tempo e ragionamenti per capire il funzionamento.
Title: Re: Irrigazione automatica
Post by: Standardoil on Jul 26, 2019, 01:34 pm
Sì, ma tu rispondi a federico66, che ti ha fatto una domanda che 'sento anche mia':
Perché non usi la eeprom interna?
Title: Re: Irrigazione automatica
Post by: karnhack on Jul 26, 2019, 02:08 pm
Non avevo visto la domanda di Federico, cmq preferisco preservare Arduino piuttosto che  l'rtc che con due soldi lo ricompro. Visto che con questo progetto sto imparando sto facendo anche parecchie cazzate soprattutto all'inizio, per esempio mettendo la scrittura nvram nel loop,  bruciando due schede (Arduino clone + TinyRTC). Per finire in bellezza ieri mi è caduto il vino sul raspberry... una frana!
Sono più portato per la meccanica che per l'elettronica e la programmazione, sto cercando di imparare senza troppe pretese per fare qualche piccola automazione e giocare un po.
Title: Re: Irrigazione automatica
Post by: gpb01 on Jul 26, 2019, 02:37 pm
... per esempio mettendo la scrittura nvram nel loop,  bruciato due schede (Arduino clone + TinyRTC). Per finire in bellezza ieri mi è caduto il vino sul raspberry... una frana!
Tranquillo, abbiamo tutti cominciato facendo ... danni inenarrabili :D :D :D :D :D

Guglielmo
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 02, 2019, 01:55 pm
Qualcosa non va con la funzione del troppopieno...  in pratica funziona al contrario cioè quando l'interruttore del troppopieno è CHIUSO l'elettrovalvola si apre e viceversa. Ovviamente la prima cosa che ho fatto è stata quella di invertire le costanti APERTO a 1 e CHIUSO a 0 ma in questo modo non funziona proprio.
Sarà che nel codice non c'è una condizione che gli dice espressamente cosa deve fare quando è APERTO?

Code: [Select]

const byte ACCESO = LOW;
const byte SPENTO = HIGH;
const byte APERTO = 0;
const byte CHIUSO = 1;

....

if (first_pass) {
    Serial.println("Fase: RIEMPIMENTO / RABOCCO");
    digitalWrite(pinElettrovalvola, ACCESO);             // valvola aperta
}

if (digitalRead(pinTroppopieno) == CHIUSO) {        // se bidone pieno
    digitalWrite(pinElettrovalvola, SPENTO);        // chiudi valvola
    if (ePausa == ATTIVO) { fase = PAUSA_24H; }     // Se ePausa e true vai a PAUSA 24
    else                  { fase = RIPOSO;    }     // altrimenti vai a RIPOSO
}
else if (trascorso >= 180) {                        // e se timeout riempimento supera i 3 minuti
    digitalWrite(pinElettrovalvola, SPENTO);        // chiudi valvola
    fase = ALLARME;                                 // vai ad allarme contatto guasto o manca acqua
}


Title: Re: Irrigazione automatica
Post by: Maurotec on Aug 03, 2019, 04:39 am
Allora inverti questi,
Code: [Select]

const byte ACCESO = LOW;
const byte SPENTO = HIGH;

Cioè,
Code: [Select]

const byte ACCESO = HIGH;
const byte SPENTO = LOW;


Oppure,

Code: [Select]

void switchEV0( const bool tf ) {
     digitalWrite( pinElettrovalvola, tf );   
}


o se preferisci le macro,

Code: [Select]

#define SET_EV0_ON() (digitalWrite( pinElettrovalvola, HIGH ))
#define SET_EV0_OFF() (digitalWrite( pinElettrovalvola, LOW ))


Per richiamare una macro ti basta,
Code: [Select]

SET_EV0_ON(); // per accenderla
SET_EV0_OFF(); // per spegnerla


Ciao.
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 03, 2019, 12:37 pm
Maurotec forse non mi sono spiegato bene e ti chiedo scusa. In ogni caso ho fatto le prove che mi hai suggerito ma succede il finimondo, si accende tutto pompa ed elettrovalvola ed ignora completamente l'interruttore del troppopieno.
Il problema secondo me è sull'interruttore che funziona solo se è chiuso... quindi se è chiuso aspetta che si apre e questo funziona:
Code: [Select]

if (first_pass) {
    Serial.println("Fase: RIEMPIMENTO / RABOCCO");
    digitalWrite(pinElettrovalvola, ACCESO);        // valvola aperta
}

if (digitalRead(pinTroppopieno) == CHIUSO) {        // se bidone pieno
    digitalWrite(pinElettrovalvola, SPENTO);        // chiudi valvola
    if (ePausa == ATTIVO) { fase = PAUSA_24H; }     // Se ePausa e true vai a PAUSA 24
    else                  { fase = RIPOSO;    }     // altrimenti vai a RIPOSO
}
else if (trascorso >= 180) {                        // e se timeout riempimento supera i 3 minuti
    digitalWrite(pinElettrovalvola, SPENTO);        // chiudi valvola
    fase = ALLARME;                                 // vai ad allarme contatto guasto o manca acqua
}


Però se lo trova aperto non ha nessuna informazione su come deve comportarsi ed esegue direttamente lo switch passando alla fase successiva:

Code: [Select]

if (digitalRead(pinTroppopieno) == CHIUSO) {        // se bidone pieno
    digitalWrite(pinElettrovalvola, SPENTO);        // chiudi valvola
    if (ePausa == ATTIVO) { fase = PAUSA_24H; }     // Se ePausa e true vai a PAUSA 24
    else                  { fase = RIPOSO;    }     // altrimenti vai a RIPOSO
}



Sto facendo delle prove che non funzionano però sto vedendo che le costanti dichiarate dell'interruttore sono corrette, il problema è altrove.
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 03, 2019, 01:13 pm
Fermi tutti, ho risolto!
Ho cambiato interruttore  e saldato il contatto su NC... anziché su NO...
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Aug 03, 2019, 01:31 pm
Che poi, essendo un finecorsa, dal punto di vista della sicurezza era anche meglio lasciarlo su NC, così un'interruzione accidentale del collegamento veniva vista come livello raggiunto. Se metti il contatto NO e il cavetto si interrompe, la condizione di livello raggiunto non diventa mai vera  ;) (avevo anche suggerito un timeout sul riempimento proprio per evitare un rabbocco che non si arresta mai)
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 03, 2019, 01:51 pm
Che poi, essendo un finecorsa, dal punto di vista della sicurezza era anche meglio lasciarlo su NC, così un'interruzione accidentale del collegamento veniva vista come livello raggiunto. Se metti il contatto NO e il cavetto si interrompe, la condizione di livello raggiunto non diventa mai vera  ;) (avevo anche suggerito un timeout sul riempimento proprio per evitare un rabbocco che non si arresta mai)
Ciao Claudio, pensavo mi avessi abbandonato! :D

Riguardo al finecorsa hai ragione ma non riesco a risolvere altrimenti e con sto caldo la via di minor resistenza ha la precedenza... poi si rischierebbe di arrivare a 300 risposte su questo thread anche se per me non è un problema...
Cmq non mi preoccupo più di tanto perché ho inserito una valvola di sicurezza meccanica che chiude la mandata in caso di malfunzionamento... inoltre se ricordi ho inserito uno stato di allarme alla quale collegherò un "cicalino"  o come si chiama lui...
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 06, 2019, 09:25 am
Ragazzi vi ringrazio per tutto l'aiuto, finalmente comincio a vedere la fine.
Ora sono ad un bivio e cioè scegliere il tipo di alimentazione e stavo pensando a due vie e cioè :
- usare un alimentatore da 5v per alimentare arduino, relé ed rtc e alimentare la pompa peristaltica ed il motorino a parte con un alimentatore da 12v
- Alimentare tutto col 12V visto che ho letto che arduino se alimentato da usb "taglia" automaticamente la corrente portandola a 5v

Non capendo di elettronica però non so se sia "salutare" sparare i 12v sull' arduino e non vorrei si riscaldasse troppo e che nel tempo si danneggi. Volendo potrei anche mettere uno stepdown visto che ne ho uno e far fare questo lavoro a lui. Cosa mi consigliate? Grazie mille

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=319387)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Aug 06, 2019, 06:14 pm
Puoi alimentare tutto a 12 MA NON appoggiandoti al regolatore interno 5V di Arduino, serve obbligatoriamente uno step-down (per quei relé occorrono come minimo 300mA in totale).

Se lo step-down è lineare e non switching, allora dovrai dissipare più di 2W, il che vorrebbe dire un'aletta formato bancomat.


PS: bello il supporto stampato 3D 8)
Title: Re: Irrigazione automatica
Post by: karnhack on Aug 06, 2019, 06:44 pm
Come alimentatore ho un 12v 2A recuperato da qualche parte, mentre lo step down è un MP1584EN che ha queste caratteristiche... credo di riuscire ad alimentare tutto anche se non so bene che motore usare per la pompa peristaltica, forse un nema visto che ne ho già uno anche se mi sembra un po sprecato:

Mini regolatore di alimentazione step-down MP1584EN ad elevata efficienza energetica con tensione regolabile da 0.8V a 20V e corrente massima di 3A. Il peso di soli 3gr lo rende ideale in tutte le applicazioni di mobilità, comunicazione e miniaturizzazione, è perfetto per essere utilizzato in modellismo, aeromodelli e droni.

TENSIONE DI INGRESSO 4.5V - 28V
TENSIONE IN USCITA 0.8V - 20V
CORRENTE 3A
RIPPLE <30mV
FREQUENZA DI SWITCHING 1MHz
EFFICIENZA 96%
DIMENSIONI 22x17x4mm

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=319458)

(https://forum.arduino.cc/index.php?action=dlattach;topic=617496.0;attach=319460)
Title: Re: Irrigazione automatica
Post by: Claudio_FF on Aug 06, 2019, 07:01 pm
Mi pare che vada tutto bene.