Impianto d'Irrigazione Interrato gestito da Arduino

Salve, mi scuso se il titolo non spiega proprio bene quello che vorrei fare ma non basterebbe lo spazio disponibile per farlo.


Obiettivo:

Creare una Centralina d'Irrigazione con Arduino.
Ho già acquistato diversi componenti tra cui uno mi deve ancora arrivare nel frattempo sto cercando di occuparmi del lato programmazione.

Componenti:

  • Arduino UNO R3;
  • RTC DS3231 I2C (Componente che mi dovrà ancora arrivare e se vogliamo il più importante dell'intero progetto);
  • LCD 1602 I2C;
  • Relay Board 8Ch
  • 4 Pulsanti Normalmente Aperti
  • 5 Resistenze qualsiasi
  • Cavetterie Varie
  • BreadBoard per la fase di test che poi trasformerò tutto in un PCB

Informazioni:

Ho scelto di utilizzare l'LCD e l'RTC connettendoli entrambi al modulo I2C per risparmiare quanti più pin digitali possibili e farli utilizzare dal Modulo Relay a 8 canali da connetterli a delle elettrovalvole che interromperanno il flusso dell'acqua tramite una Bassa Tensione (24V) dato che Acqua e Corrente sono altamente pericolosi se messi vicini... ma sono consapevole di quello che faccio e che utilizzare la corrente è altamente pericoloso per me e per chiunque. Tornando al discorso ho scelto di utilizzare 5 pulsanti collegati tutti a un solo pin analogico che tramite resistenze, 5V+ e GND dell'Arduino posso utilizzarli per creare i soliti 4 pulsanti: Sopra, Sotto, Invio e Indietro.

Diciamo che mi sento già a buon punto però ora arriva la parte cruciale (o almeno per me)... il lato programmazione.

Domanda:

Dovrei creare un menù, nel quale muovermi sull'LCD tramite i pulsanti, così come ho creato uno schema logico tramite notepad++.

Una volta creato il menù dovrò:
Inserire la possibilità di impostare data e ora attuale;
Settare 4 timer diversi per ogni Relay che utilizzerà l'RTC in modo che se dovessi interrompere l'alimentazione ad Arduino verrà tutto salvato grazie la batteria a bottone presente su di esso;
E questo è tutto... per l'accensione manuale per fortuna riesco a fare da solo il problema è la programmazione automatica giornaliera.

Mi sono informato prima di scrivervi qui e ho visto che ci sono delle librerie per la creazione dei menù ma non ho dimestichezza... ci ho provato ma non riesco proprio ad utilizzarla (troppo complicata per il mio livello di programmazione sennò non starei qui a chiedervi aiuti ed esempi).

Se per voi è un problema aiutarmi interamente, mi basterebbero anche degli esempi di sketch:

Esempio per la creazione di menù, submenù a 5 livelli/piani magari con dei commenti che mi fanno capire come modificarli o sistemarli per il mio scopo;

Esempio per far funzionare il modulo RTC DS3231 I2C che mi permettono di Settare la Data Attuale, Settare l'Ora Attuale, Visualizzare Ora e data su due righe diverse ma nella stessa schermata;

Esempio di come, se premo il pulsante Invio una volta giunto al "submenù" di 5° Livello, mi faccia impostare l'Ora di Attivazione relativa a un pin dal quale sarà attivato un relay (non chiedo l'esempio per lo spegnimento in quanto sarà il contrario e credo di potercela fare da solo una volta capito il funzionamento dell'attivazione)

Esempio di come salvare i timer inseriti in modo che non vengano dimenticati in caso di mancata alimentazione elettrica (Se non erro qui si tratterà di eeprom e sò bene che questa mi darà dei problemi, non ci ho mai capito niente dalle varie discussioni lette sui forum dove se ne parla di come salvare date e orari... per cui se riusciste a commentare qualche stringa anche qui mi aiutereste davvero tanto.

E in teoria dovrebbe essere tutto se non dimentico qualcosa.

Per favore, non rimandatemi a forum dove discutono di come funzionano gli elementi ecc. perchè come ci sapete andare voi ci sò andare anche io e se vi scrivo è perchè non mi sono di aiuto per cui confido in soli vostri commenti ed esempi che mi aiutino a realizzare questo progetto che una volta finito renderò pubblico per chiunque ne abbia bisogno (anche perchè tra progetti italiani e stranieri relativo alle centraline d'irrigazioni nessuno è tanto preciso quanto questo che vorrei realizzare io).

Mi scuso per le eventuali ripetizioni o il mio stile di scrivere periodi lunghi e interminabili... sono settimane che cerco di documentarmi, ormai mi si è fuso il cervello ahah.

Ora lascio la parola a voi e spero che mi diate gli input necessari per il mio output :grinning:

Se volete vi rilascerò anche lo schema che ho realizzato con Fritzing di come ho messo in comunicazione tutti gli elementi.

Menù.h (13.8 KB)

Ciao

comincia intanto a settare RTC ed Visualizzarlo sul display.

Se NON PREMI il pulsante vedi solo la data, se PREMI il pulsante vedi per 10 secondi ORA e DATA.....ed i secondi devono scorrere , non bloccarsi.

Poi posta lo schetc se hai problemi :wink: :wink: :wink:

>Ryan0497: Nonostante tu sia iscritto da molto tempo, NON trovo il tuo post di presentazione :confused: , per cui ... nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie.

Guglielmo

gpb01:
>Ryan0497: Nonostante tu sia iscritto da molto tempo, NON trovo il tuo post di presentazione :confused: , per cui ... nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie.

Guglielmo

Sembra strano... chiedo scusa e interverrò il prima possibile non me ne vogliate ma a quest'ora non riuscirei a farlo.

Puso:
Ciao

comincia intanto a settare RTC ed Visualizzarlo sul display.

Se NON PREMI il pulsante vedi solo la data, se PREMI il pulsante vedi per 10 secondi ORA e DATA.....ed i secondi devono scorrere , non bloccarsi.

Poi posta lo schetc se hai problemi :wink: :wink: :wink:

Allora dovrò aspettare che mi arrivi l'RTC e vedrò cosa riuscirò a fare... intanto sto vedendo anche di utilizzare Blynk per Android che sembrerebbe essere ottimo al caso mio e forse più completo del mio stesso progetto.

Comunque vi terrò aggiornati non appena mi arriva il modulo. Grazie Mille e Mi scuso ancora per la mia mancata presentazione in questo forum... di solito la prima cosa che faccio nei forum è leggermi il regolamento e presentarmi. Comunque rimedierò il prima possibile.

La prima cosa da fare mi sembra sia quella di leggere correttamente i pulsanti, altrimenti poi i problemi da affrontare insieme sono più di uno :wink:

Leggere i pulsanti e farsi stampare via monitor seriale gli eventi rilevati, pressione1, pressione2, rilascio.

Claudio_FF:
La prima cosa da fare mi sembra sia quella di leggere correttamente i pulsanti, altrimenti poi i problemi da affrontare insieme sono più di uno :wink:

Leggere i pulsanti e farsi stampare via monitor seriale gli eventi rilevati, pressione1, pressione2, rilascio.

Allora io ho creato questo sketch ma funziona in parte. Non riesco a far scrivere sul monitor seriale il tasto che sto premendo al posto di farmi visualizzare solo i valori del pulsante premuto e che fanno parte degli insiemi creati a inizio sketch più o meno.

/*
  Titolo:      Tastiera Menù
  Autore:      Ryan0497
  Data:        03/05/2018
  Obiettivo:   Leggere Tutti Valori dal PIN A0 alla pressione dei pulsanti per creare tastiera menù.
*/

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

void loop() {
  
  //Dichiarazione Variabili
  int TASTIERA = analogRead(A0);  //Chiamo i valori letti dal PIN A0 "TASTIERA"
  int INVIO[]     =  {0, 20};     //Chiamo i valori inclusi nell'insieme x,y INVIO
  int SINISTRA[]  =  {929, 931};  //Chiamo i valori inclusi nell'insieme x,y SINISTRA
  int DESTRA[]    =  {936, 939};  //Chiamo i valori inclusi nell'insieme x,y DESTRA
  int SOPRA[]     =  {943, 945};  //Chiamo i valori inclusi nell'insieme x,y SOPRA
  int SOTTO[]     =  {946, 947};  //Chiamo i valori inclusi nell'insieme x,y SOTTO
  
  //Svolgimento
  Serial.println(TASTIERA); //Stampa i Valori letti alla pressione dei pulsanti per creare gli insiemi delle VARIABILI create sopra
  delay(250); //Tempo di aggiornamento prima di ristampare il valore letto
  
  //Alla pressione scrivi "IL PULSANTE PREMUTO"
  //Se TASTIERA è un numero compreso tra uno delle 5 variabili create, allora stampa il nome della variabile creata
  if (TASTIERA == INVIO) {
    Serial.println("INVIO");
  }

  if (TASTIERA == SINISTRA) {
    Serial.println("SINISTRA");
  }

  if (TASTIERA == DESTRA) {
    Serial.println("DESTRA");
  }

  if (TASTIERA == SOPRA) {
    Serial.println("SOPRA");
  }

  if (TASTIERA == SOTTO) {
    Serial.println("SOTTO");
  }
}

Ok, ho risolto il mio problema semplificandomi un po' la vita in questo modo:

/*
  Titolo:      Tastiera Menù
  Autore:      Ryan0497
  Data:        03/05/2018
  Obiettivo:   Leggere Tutti Valori dal PIN A0 alla pressione dei pulsanti per creare tastiera menù.
*/

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

void loop() {

  //Dichiarazione Variabile per Tastiera
  int TASTIERA = analogRead(A0);  //Chiamo i valori letti dal PIN A0 "TASTIERA"

  //Lettura Valori per settare la tastiera
  //Serial.println(TASTIERA); //Stampa i Valori letti alla pressione dei pulsanti per creare gli insiemi delle VARIABILI create sopra

  /******************************************************************************/
  /***********************************TASTIERA***********************************/
  /******************************************************************************/
  //INVIO
  if (TASTIERA >= 0 && TASTIERA <= 100) {
    Serial.println("INVIO");
  } else {}

  //SINISTRA
  if (TASTIERA >= 928 && TASTIERA <= 931) {
    Serial.println("SINISTRA");
  } else {}

  //DESTRA
  if (TASTIERA >= 935 && TASTIERA <= 939) {
    Serial.println("DESTRA");
  } else {}

  //SOPRA
  if (TASTIERA >= 942 && TASTIERA <= 945) {
    Serial.println("SOPRA");
  } else {}

  //SOTTO
  if (TASTIERA >= 946 && TASTIERA <= 950) {
    Serial.println("SOTTO");
  } else {}
  /******************************************************************************/
  /******************************************************************************/
  /******************************************************************************/


  delay(50); //Tempo di aggiornamento prima di ristampare il valore letto
}

Lascio in Allegato il monitor seriale.

Ora cosa mi consigliate di fare per proseguire il progetto?
Metto in comunicazione l'LCD 1602A I2C con Arduino UNO R3?

C'è qualcosa che non va nei valori di accettazione, idealmente con cinque pulsanti che generano valori equamente spaziati nel range 0..1023 dovrebbero esserci finestre di accettazione larghe circa 200 punti, non 3..4. Ritengo che il partitore di tensione usato sia un po' "strano".

In questo ad esempio i pulsanti dovrebbero generare questi valori (salvo tolleranze delle resistenze):

+5V---[R2k2]---+-------+-------+-------+-------+--->in
               |       |       |       |       |
             [R8k2]  [R3k3]  [R1k5]  [R560]    |
               |       |       |       |       |
                /       /       /       /       /
               |       |       |       |       |
              Gnd     Gnd     Gnd     Gnd     Gnd

   nessuno   sotto   sopra   destra  sinist. invio
    1023      806     614     414     208      0

Quindi in pratica il tasto si prenderà per buono per valori minori di 104, altrimenti il tasto si prenderà per buono per valori minori di 311 e così via. Poi leggendo i valori reali restituiti dal proprio partitore si aggiustano le finestre in modo da centrarle sui valori reali.

Seconda cosa, non è così semplice, con il tuo codice è vero che individui il tasto premuto, ma non rilevi il momento della pressione, cioè il click, che è il vero comando che poi dovrà comandare il menu. In pratica se tieni premuto il monitor seriale continua a stampare a raffica.

Il click avviene quando da si passa ad una delle altre possibilità (e il valore rimane stabile per almeno 50ms), il rilascio quando si torna a , e solo a quel punto potrà esserci un altro click.

Scusa, perche' non usare una rete simmetrica per il divisore ? ... una cosa tipo questa ...

con quei valori, il consumo totale della rete sarebbe di circa 300uA, e le tensioni dovrebbero essere abbastanza stabili (meno un minimo causato dalla resistenza da 220K di pulldown, che pero' influisce poco in proporzione)

Claudio_FF:
C'è qualcosa che non va nei valori di accettazione, idealmente con cinque pulsanti che generano valori equamente spaziati nel range 0..1023 dovrebbero esserci finestre di accettazione larghe circa 200 punti, non 3..4. Ritengo che il partitore di tensione usato sia un po' "strano".

In questo ad esempio i pulsanti dovrebbero generare questi valori (salvo tolleranze delle resistenze):

+5V---[R2k2]---+-------+-------+-------+-------+--->in

|       |       |       |       |
            [R8k2]  [R3k3]  [R1k5]  [R560]    |
              |       |       |       |       |
               /       /       /       /       /
              |       |       |       |       |
             Gnd     Gnd     Gnd     Gnd     Gnd

nessuno   sotto   sopra   destra  sinist. invio
   1023      806     614     414     208      0



Quindi in pratica il tasto <invio> si prenderà per buono per valori minori di 104, altrimenti il tasto <sinistra> si prenderà per buono per valori minori di 311 e così via. Poi leggendo i valori reali restituiti dal proprio partitore si aggiustano le finestre in modo da centrarle sui valori reali.

Hai perfettamente ragione, devo andare a comprare delle resistenze diverse e cambiarle con quelle attuali perchè quando ho realizzato il circuito per fare una prova, non avendo 5 resistenze diverse, decisi di utilizzarne 5 uguali che avevo da un kit comprato.

Seconda cosa, non è così semplice, con il tuo codice è vero che individui il tasto premuto, ma non rilevi il momento della pressione, cioè il click, che è il vero comando che poi dovrà comandare il menu. In pratica se tieni premuto il monitor seriale continua a stampare a raffica.

Il click avviene quando da si passa ad una delle altre possibilità (e il valore rimane stabile per almeno 50ms), il rilascio quando si torna a , e solo a quel punto potrà esserci un altro click.

Allora correggimi se erro, il codice va cacciato fuori loop() e si toglie la funzione delay(50) o non basta?
Sennò pensavo di cambiare lo stato dei pin analogici in digitale e collegare solo 4 pulsanti ai 4 pin (uno per pin) e definirli con un nome che li identificasse del tipo

int SOPRA A0;
int INDIETRO A1;
int INVIO A2;
int SOTTO A3;

Così alla pressione di uno dei tasti riesco a far leggere se il pulsante è premuto oppure no. Ovviamente quello di sopra è un esempio, non so nemmeno se è la corretta dicitura per fare tutto questo (andrò a vedere sul dizionario del linguaggio in C :smiley:

Etemenanki:
Scusa, perche' non usare una rete simmetrica per il divisore ? ... una cosa tipo questa ...

con quei valori, il consumo totale della rete sarebbe di circa 300uA, e le tensioni dovrebbero essere abbastanza stabili (meno un minimo causato dalla resistenza da 220K di pulldown, che pero' influisce poco in proporzione)

ma in questo modo se non ho capito male mi ritroverò di nuovo allo stato di prima che seppur riesco a far vedere 5 pulsanti collegati tutti allo stesso pin, durante la creazione del menù avrò problemi nel richiamarli alla loro pressione

Problema che hai comunque, con entrambi i sistemi (il mio di diverso ha solo che hai una divisione piu lineare dei valori e meno casini per calcolarti i partitori) ... per il problema che dici tu, serve che gestisci la cosa in modo diverso ... un modo, ad esempio, potrebbe essere quello di inserire nella parte che controlla il valore letto dall'ingresso analogico, come primo controllo, un'if che attiva una flag (o quello che preferisci) se il valore letto e' maggiore di un minimo ... dato che nessun pulsante = 0V, se fai il mapping con 1023, il minimo valore con 1V sarebbe intorno ai 204, per cui se metti un'if (valore letto > 50 oppure 100) flag=1 else flag=0, o qualcosa di simile, avrai la flag che va ad 1 ogni volta che premi un qualsiasi pulsante e torna a 0 quando nulla e' premuto, da poter usare nello sketch per "sentire" quando li premi ...

Mh... non capisco tanto bene come dovrei creare uno sketch che faccia quello che mi hai appena detto. Mica mi puoi mandare un mini-sketch che mi mostri come può funzionare già solo con un pulsante? Non so proprio cosa cominciare a scrivere ::slight_smile:

In che senso scusa ?

Se usi un solo pin per leggere piu di un pulsante, dovrai per forza avere nel loop almeno una sezione che ti fa la lettura dell'ingresso analogico a cui i pulsanti sono connessi, per sapere quale e' stato premuto ... potrebbe essere una cosa tipo (pseudocodice, da completare con le tue variabili)

void loop()
   {
   ...
   tuo codice
   ...
   int valoreletto=digitalRead(pin_analogico_che_usi);
   valore=map(valoreletto, 0, 1023, 0, 5); //questo da un valore proporzionale al pulsante premuto
   ...
   ...eccetera

solo come esempio, ci sono altri modi ... ma se usi una cosa simile, valoreletto sara' zero o comunque un valore pprossimo a zero senza alcun pulsante premuto, e superiore a zero (almeno 200 per 5 pulsanti) quando un qualsiasi pulsante e' premuto ... per cui, se sempre come esempio, prima della conversione fatta con la map, ci metti una cosa del genere

   if(valoreletto >= 50)
   {
      miaflag=1;
   }
   else
   {
      miaflag=0;
   }

avrai una flag (miaflag in questo caso, ma puoi dargli il nome che vuoi, e' una semplice variabile byte) che ogni volta che premi un pulsante passera' da 0 ad 1, tornando a 0 quando lo rilasci ... che quindi potrai usare in qualche altra parte dello sketch per "dire" al micro che un pulsante e' stato premuto, nel caso servisse ...

Oppure potresti usare uno switch case per valori da 0 a 5, con 0 non e' stato premuto alcun pulsante, con gli altri valori automaticamente sai che un pulsante e' stato premuto ed anche quale (l'if viene buono se non usi la switch, oppure se lo stato dei pulsanti serve anche saperlo in qualche altro punto dello sketch) ...

O magari a qualche programmatore viene in mente un sistema anche migliore, a me, non essendo un programmatore, sono venuti in mente al volo solo questi ...

un mini-sketch che mi mostri come può funzionare già solo con un pulsante?

Il riconoscimento di una variazione passa sempre per l'uso di una variabile che rappresenta lo stato precedente, da confrontare con la situazione aggiornata attuale, se c'è differenza allora è avvenuta una variazione (poi si aggiorna la variabile di stato alla situazione attuale, in modo da poter sentire variazioni successive). Il sistema più semplice per un pulsante digitale credo sia questo (si assume un collegamento hardware con resistenza di pull-up, quindi pulsante chiuso = lettura LOW):

//-----------------------------------------------
#define PULS  3
#define PULS_PRESS_LEVEL  LOW  //configuraz.pull-up
//-----------------------------------------------
byte precedente = !PULS_PRESS_LEVEL; //non premuto
//-----------------------------------------------
void setup()
{
    pinMode(PULS, INPUT);
}
//-----------------------------------------------
void loop()
{
    byte attuale = digitalRead(PULS);
    if(attuale != precedente)
    {
        precedente = attuale;
        if(attuale == PULS_PRESS_LEVEL)
        {
            //...rilevato istante di pressione...
        }
        else
        {
            //...rilevato istante di rilascio...
        }
    }
    delay(50);
}
//-----------------------------------------------

NOTA: i nomi di comodo PULS e PULS_PRESS_LEVEL sono "etichette" da usare nel resto del programma per non scrivere ogni volta il numeri dei pin o i livelli HIGH/LOW. Qui è poco importante, ma in programmi più grossi aiuta a non fare confusione.

Il delay(50) dipende. In questo caso specifico non fa male, rallenta l'esecuzione della funzione loop a circa 20 cicli al secondo e serve quindi da tempo di debounce per i pulsanti (se non hanno un debounce hardware esterno), ma potrebbe diventare un intralcio se il programma più avanti richiedesse altre temporizzazioni o una velocità maggiore della loop.

Cosa fare nelle righe ...rilevato istante di...? Quello che serve, si possono chiamare delle funzioni (che verranno eseguite una volta solo in quel momento), oppure si possono impostare delle variabili flag da leggere in un altro punto del programma:

//-----------------------------------------------
void loop()
{
    boolean onUp = false;
    boolean onDn = false;
    byte attuale = digitalRead(PULS);
    if(attuale != precedente)
    {
        precedente = attuale;
        if(attuale == PULS_PRESS_LEVEL) onDn = true;
        else                            onUp = true;
    }

    if(onDn) 
    {
        //...rilevato istante di pressione...
    }

    if(onUp)
    {
        //...rilevato istante di rilascio...
    }

    delay(50);
}
//-----------------------------------------------

NOTA: le variabili onUp e onDn diventano true per un solo ciclo di loop, cioè sono "impulsi" che avvengono solo nel momento in cui si riconosce una pressione o un rilascio, quindi continuando a tenere il pulsante premuto non ci saranno ulteriori riconoscimenti della pressione.

Per i pulsanti collegati a pin analogico alla fine va applicata la stessa idea, ma in più c'è la fase iniziale di lettura e decisione in base ai valori letti.

Innanzitutto vi ringrazio davvero tanto per le vostre spiegazioni ed esempi che mi stanno aprendo un nuovo mondo nella programmazione (i flag non li ho mai usati e questa è la prima volta che ne apprendo il significato/uso).

Purtroppo trovo complicato capire come funzionano... guardando un po' lo sketch di @Etemenanki, tutti quei numeri tra le parentesi cosa sono e cosa fanno?! Non rispondetemi per il momento perché mi rendo conto che vi faccio perdere troppo tempo.

Guardando lo sketch di Claudio_FF mi sembra più o meno più semplice e forse più funzionale per il caso mio... mi sono permesso un po' di cambiare i nomi delle variabili per studiarmelo un po' ed ecco cosa ne è uscito:

//-----------------------------------------------
#define INVIO  0
#define INVIO_PREMUTO  LOW  //configuraz.pull-up
//-----------------------------------------------
byte precedente = !INVIO_PREMUTO; //non premuto
//-----------------------------------------------
void setup()
{
    pinMode(INVIO, INPUT);
}
//-----------------------------------------------
void loop()
{
    boolean onUp = false;
    boolean onDn = false;
    byte attuale = digitalRead(INVIO);
    if(attuale != precedente)
    {
        precedente = attuale;
        if(attuale == INVIO_PREMUTO) onDn = true;
        else                         onUp = true;
    }

    if(onDn) 
    {
        //...rilevato istante di pressione...
    }

    if(onUp)
    {
        //...rilevato istante di rilascio...
    }

    delay(50);
}
//-----------------------------------------------

In questo sketch però non capisco come faccio a far capire ad Arduino che i 5 pulsanti differenti, se sono collegati tutti al pin analogico 0 con diverso valore, devono svolgere una funzione diversa.

Ho visto girando su alcuni forum inglesi in questi giorni, che utilizzano un pin analogico per ogni pulsante, dichiarando che sono pin input e che normalmente non sono premuti. Purtroppo non riesco più a trovarlo quel forum nemmeno più cercando nella cronologia. ricordo che per esempio riuscivano a far accendere un led alla pressione di un pulsante collegato all'A0.

Ora parlando con voi, mi è venuto in mente di utilizzare quel tipo di funzionamento che sembrerebbe essere ottimo per poi richiamarlo nella digitazione del menù. Il problema è che seppur dovesse essere uno sketch davvero semplice non riesco più a trovarlo... qualche idea? In pratica 4 pin analogici verranno trasformati in digitali; serve qualche libreria specifica?

Ryan0497:
mi sono permesso un po' di cambiare i nomi delle variabili per studiarmelo un po'

#define INVIO  0

I pin 0 e 1 non vanno usati, sono riservati alla seriale USB, mente A4 e A5 sono riservati per il bus i2c, e il 13 ha un LED verso massa di cui tenere conto. In pratica ne restano totalmente puliti 15.

utilizzano un pin analogico per ogni pulsante, dichiarando che sono pin input e che normalmente non sono premuti.

Infatti si usano esattamente come i digitali, solo che li chiami A0, A1 ecc e non 2, 3 ecc.

Lavorando con pulsanti singoli lo sketch sopra può essere esteso per 5 pulsanti, ciascuno dovrà avere la sua variabile stato precedente personale (esempio 'precedenteInvio', 'precedenteSinistra' ecc) e potrà generare indipendentemente dagli altri gli eventi up e dn (per cui ci saranno 10 possibili eventi, o 5 se non interessano i rilasci, ad esempio 'onDnInvio', 'onDnDestra' ecc).

Un'alternativa un po' più breve, che può essere applicata paro paro alla lettura da unico pin analogico e gestisce un pulsante alla volta, è creare prima uno scancode dalle letture degli ingressi (ad esempio 0=niente premuto, 1=sotto premuto, 2=ecc) e poi lavorare solo con lo scancode:

byte    precedente = 0;      //scancode precedente
boolean giaPremuto = false;  //se true disabilita tasti fino a rilascio

void loop()
{
    boolean onGiu    = false;
    boolean onSu     = false;
    boolean onDest   = false;
    boolean onSinist = false;
    boolean onInvio  = false;

    byte scancode;
    if(digitalRead(PULS_GIU)         == PULS_PRESS_LEVEL) scancode = 1;
    else if(digitalRead(PULS_SU)     == PULS_PRESS_LEVEL) scancode = 2;
    else if(digitalRead(PULS_DEST)   == PULS_PRESS_LEVEL) scancode = 3;
    else if(digitalRead(PULS_SINIST) == PULS_PRESS_LEVEL) scancode = 4;
    else if(digitalRead(PULS_INVIO)  == PULS_PRESS_LEVEL) scancode = 5;
    else                                                  scancode = 0;

    if(scancode != precedente)  // se c'e`una variazione
    {
        precedente = scancode;  // aggiorna stato per prossima variazione
        if(giaPremuto)          // se gia`premuto altri tasti sono bloccati
        {
            if(scancode == 0) giaPremuto = false; // sblocca tasti al rilascio
        }
        else                    // altrimenti se non gia`premuto
        {
            if(scancode > 0)    // e tasto valido
            {
                giaPremuto = true;  // blocca fino a rilascio e genera evento
                if(scancode == 1)      onGiu = true;
                else if(scancode == 2) onSu = true;
                //...ecc...
            }
        }

    }

    if(onGiu)
    {
        //...rilevato istante di pressione pulsante giu...
    }

    if(onSu)
    {
        //...rilevato istante di pressione pulsante su...
    }

    //...ecc...

    delay(50);
}

Allora ho deciso di rimuovere un pulsante e utilizzarne solo 4 e sig. Claudio_FF, ho adattato il suo sketch secondo quest'ultima decisione:

/*********************************************************************/
/*********************************************************************/
#define PULS_GIU    	  	A0
#define PULS_SU     		A1
#define PULS_INDIETRO   	A2
#define PULS_INVIO    		A3
#define PULS_PRESS_LEVEL 	LOW  //configuraz.pull-up
/*********************************************************************/
/*********************************************************************/
byte    precedente = 0;      //scancode precedente
boolean giaPremuto = false;  //se true disabilita tasti fino a rilascio
/*********************************************************************/
/*********************************************************************/
void setup()
{
  pinMode(  PULS_GIU    	,   INPUT);
  pinMode(  PULS_SU     	,   INPUT);
  pinMode(  PULS_INDIETRO 	,   INPUT);
  pinMode(  PULS_INVIO    	,   INPUT);
}
/*********************************************************************/
/*********************************************************************/
void loop()
{
  boolean onGiu     	= false;
  boolean onSu      	= false;
  boolean onIndietro  	= false;
  boolean onInvio   	= false;

  byte scancode;
  if (digitalRead(PULS_GIU)          	== PULS_PRESS_LEVEL)  	scancode = 1;
  else if (digitalRead(PULS_SU)      	== PULS_PRESS_LEVEL)  	scancode = 2;
  else if (digitalRead(PULS_INDIETRO)  	== PULS_PRESS_LEVEL)  	scancode = 3;
  else if (digitalRead(PULS_INVIO)   	== PULS_PRESS_LEVEL)  	scancode = 4;
  else 															scancode = 0;

  if (scancode != precedente)           				// se c'e`una variazione
  {
    precedente = scancode;            					// aggiorna stato per prossima variazione
    if (giaPremuto)                   					// se gia`premuto altri tasti sono bloccati
    {
      if (scancode == 0) giaPremuto = false;  			// sblocca tasti al rilascio
    }
    else                              					// altrimenti se non gia`premuto
    {
      if (scancode > 0)             					// e tasto valido
      {
        giaPremuto = true;          					// blocca fino a rilascio e genera evento
        if (scancode == 1)      onGiu = true;
        else if (scancode == 2) onSu = true;
        if (scancode == 4)      onInvio = true;
        else if (scancode == 3) onIndietro = true;
      }
    }

  }

  if (onGiu)
  {
    //...rilevato istante di pressione pulsante giu...
  }

  if (onSu)
  {
    //...rilevato istante di pressione pulsante su...
  }

  if (onIndietro)
  {
    //...rilevato istante di pressione pulsante indietro...
  }

  if (onInvio)
  {
    //...rilevato istante di pressione pulsante invio...
  }

  delay(50);
}
/*********************************************************************/
/*********************************************************************/

Credo di non essermi dimenticato nulla e di non aver sbagliato nulla; ho semplicemente fatto copia-incolla e aggiunto/modificato qualche piccola cosa, per cui non dovrebbero esserci problemi. Se può farmi comunque l'ulteriore gentilezza di verificare questo sketch e dirmi se posso cominciare ad implementare la comunicazione seriale con LCD 1602A I2C così poi da passare allo step successivo che è quello che mi preoccupa di più... la creazione di un menù con relativi sottomenu fino al 5° di appartenenza.

Solo una parte del codice non mi convince: Riga 30; "byte scancode" cosa fa? Non andrebbe inserito assieme a:

byte    precedente = 0;      //scancode precedente
boolean giaPremuto = false;  //se true disabilita tasti fino a rilascio

Perdonate la mia ignoranza ma tante cose non si imparano solo grazie ai libri e tutorial ma anche con l'esperienza di chi ne sa di più.

Per vedere se il codice funziona basta farsi inviare dei messaggi sul monitor seriale.

Sono stati mischiati spazi e tabulazioni, questo in molti editor porta a una visualizzazione errata, meglio usare sempre solo o tab o spazi (in genere si preferiscono gli spazi).

Non vedo errori di logica, a parte nelle righe dove si mettono a true le variabili onGiu onSu ecc, però l'assenza dell'else in questo caso particolare è un "errore" del tutto ininfluente, perché il risultato finale è comunque identico.

In sostanza invece di:
se scancode == x fai questo
altrimenti se scancode == y fai quest'altro
altrimenti se scancode == z fai altro ancora
altrimenti se scancode == w fai altro ancora

hai scritto:
se scancode == x fai questo
altrimenti se scancode == y fai quest'altro
poi
se scancode == z fai altro ancora
altrimenti se scancode == w fai altro ancora

In altre situazioni questa differente logica descriverebbe invece un programma che fa due cose totalmente diverse.

La riga 30 in effetti può sembrare strana. Non è sbagliato metterla assieme alle altre dichiarazioni all'inizio.
Però, siccome viene usata solo dentro la funzione 'loop' E non deve mantenere un valore/stato tra un ciclo e l'altro della loop (che grazie al delay si "riavvia" circa 20 volte al secondo), allora l'ho dichiarata direttamente dentro la funzione (esattamente come onGiu, onSu ecc). L'argomento è: variabili globali e locali.

Ok, quindi così come è, dovrebbe funzionare per il menù. Pensavo e se utilizzassi la funzionalità del "case" al posto di utilizzare gli if e else? Mi spiego meglio... vorrei fare una cosa del genere...

/*********************************************************************/
/*********************************************************************/
#define PULS_GIU          A0
#define PULS_SU           A1
#define PULS_INDIETRO     A2
#define PULS_INVIO        A3
#define PULS_PRESS_LEVEL  LOW  //configuraz.pull-up
/*********************************************************************/
/*********************************************************************/
byte    precedente = 0;      //scancode precedente
boolean giaPremuto = false;  //se true disabilita tasti fino a rilascio
/*********************************************************************/
/*********************************************************************/
void setup()
{
  pinMode(PULS_GIU, INPUT);
  pinMode(PULS_SU, INPUT);
  pinMode(PULS_INDIETRO, INPUT);
  pinMode(PULS_INVIO, INPUT);
}
/*********************************************************************/
/*********************************************************************/
void loop()
{
  boolean onGiu       = false;
  boolean onSu        = false;
  boolean onIndietro  = false;
  boolean onInvio     = false;

  byte scancode;
  if (digitalRead(PULS_GIU)           == PULS_PRESS_LEVEL)    scancode = 1;
  else if (digitalRead(PULS_SU)       == PULS_PRESS_LEVEL)    scancode = 2;
  else if (digitalRead(PULS_INDIETRO) == PULS_PRESS_LEVEL)    scancode = 3;
  else if (digitalRead(PULS_INVIO)    == PULS_PRESS_LEVEL)    scancode = 4;
  else                                                        scancode = 0;

  if (scancode != precedente)                   // se c'e`una variazione
  {
    precedente = scancode;                      // aggiorna stato per prossima variazione
    if (giaPremuto)                             // se gia`premuto altri tasti sono bloccati
    {
      if (scancode == 0) giaPremuto = false;        // sblocca tasti al rilascio
    }
    else                                        // altrimenti se non gia`premuto
    {
      if (scancode > 0)                       // e tasto valido
      {
        giaPremuto = true;                    // blocca fino a rilascio e genera evento
        switch (giaPremuto) {
          case 1:
            if (scancode == 1) onGiu = true;
            break;
          case 2:
            if (scancode == 2) onSu = true;
            break;
          case 3:
            if (scancode == 3) onIndietro = true;
            break;
          case 4:
            if (scancode == 4) onInvio = true;
            break;
          default:
            if (scancode == 0) giaPremuto = false;
            break;
        }
      }
    }

  }

  if (onGiu)
  {
    //...rilevato istante di pressione pulsante giu...
  }

  if (onSu)
  {
    //...rilevato istante di pressione pulsante su...
  }

  if (onIndietro)
  {
    //...rilevato istante di pressione pulsante indietro...
  }

  if (onInvio)
  {
    //...rilevato istante di pressione pulsante invio...
  }

  delay(50);
}
/*********************************************************************/
/*********************************************************************/

utilizzando questa struttura:

switch (var) {
    case 1:
      //do something when var equals 1
      break;
    case 2:
      //do something when var equals 2
      break;
    default:
      // if nothing else matches, do the default
      // default is optional
      break;
  }

Potrebbe essere la migliore scelta per il mio scopo?

Comunque comincio a instaurare una comunicazione con l'lcd i2c e appena finito metto posto qui il codice

Ryan0497:

switch (var) {

case 1:
     //do something when var equals 1
     break;
   case 2:
     //do something when var equals 2
     break;
   default:
     // if nothing else matches, do the default
     // default is optional
     break;
 }



Potrebbe essere la migliore scelta per il mio scopo?

Questa struttura è del tutto equivalente a:

if(var == 1)
{
    //do something when var equals 1
}
else if(var == 2)
{
    //do something when var equals 2
}
else
{
    // if nothing else matches, do the default
    // default is optional
}

Si usa l'una o l'altra forma a seconda di come risulta più chiara da scrivere/leggere nel contesto specifico in cui si usa, ma di per se stessa non aggiunge nuove possibilità.

In particolare messa nel codice dei pulsanti in quel modo non ha alcuna logica. Siccome col copia incolla ci si è già bloccati qui, che è la parte più elementare del progetto, consiglio vivamente di sospendere temporaneamente, dedicare qualche settimana allo studio del C, disegnare bene i flowchart delle proprie istruzioni, fare finta di essere Arduino ed eseguire a mano il proprio codice, e quando tutto quadra riprendere il progetto.