Arduino UNO apertura e chiusura automatica di 5 elettrovalvole bistabili

Salve a tutti e grazie in anticipo, vorrei sottoporvi un mio problema di come integrare ulteriori altri 5 pulsanti con altrettante 10 uscite digitali, per questo sistema ho utilizzato un Arduino UNO, faccio una premessa l'elettrovalvola da me usata ha due terminali e necessita di un impulso di 12 volt per aprirsi (impulso minimo di 20 ms) e di un impulso di -12 Volt per chiudersi.
Ho scritto questo codice e mi funziona solo per un comando relativo al PULSANTE1 ed i Led1 e Led2, ma come implemento il resto del codice mi funziona tutto sballato.
Premetto che le due uscite dei led vanno in realtà a comandare due ingressi di un ponte ad H per comandare l'elettrovalvola.
La condizione dovrebbe essere questa;
se P1 è = 0 accendi led1 per 2", se P1 è = 1 accendi led2 per 2".
Ecco il mio codice:

/*
elettrovalvola comandata con un impulso di 1 secondo +12vdc apre
elettrovalvola comandata con un impulso di un secondo invertendo la polarità -12vdc
Le uscite sono collegate in forma on temporizzato e off temporizzato, questo per evitare di alimentare
continuamente l'elettrovalvola.

INGRESSI
A0 = Ingresso comando Valvola 1
A1 = Ingresso comando Valvola 2
A2 = Ingresso comando Valvola 3
A3 = Ingresso comando Valvola 4
A5 = Ingresso comando Valvola 5
USCITE
Pin 2 = OUT VALVOLA 1 ON
Pin 3 = OUT VALVOLA 1 OFF
Pin 4 = OUT VALVOLA 2 ON
Pin 5 = OUT VALVOLA 2 OFF
Pin 6 = OUT VALVOLA 3 ON
Pin 7 = OUT VALVOLA 3 OFF
Pin 8 = OUT VALVOLA 4 ON
Pin 9 = OUT VALVOLA 4 OFF
Pin 10 = OUT VALVOLA 5 ON
Pin 11 = OUT VALVOLA 6 OFF
******************************************************************************
*/





int led1 = 2;
int led2 = 3;
int led3 = 4;
int led4 = 5;
int led5 = 6;
int led6 = 7;
int led7 = 8;
int led8 = 9;
int led9 = 10;
int led10 = 11;
int pinp = 14;  //Indirizzo A0
int pinp1 = 15;  //Indirizzo A1  
int pinp2 = 16;  //Indirizzo A2
int pinp3 = 17;  //Indirizzo A3
int pinp4 = 18;  //Indirizzo A4
int pinp5 = 19;  //Indirizzo A5
int statop = 0;
int statop2 = 1;

// Attiva elettrovalvola con inpulso di 2 sec. e ritorna a riposo mentre l'elettrovalvola è in funzione con flusso d'acqua attivato

void setup() {
 pinMode (led1, OUTPUT);  
 pinMode (led2, OUTPUT);  
 pinMode (led3, OUTPUT);
 pinMode (led4, OUTPUT);  
 pinMode (led5, OUTPUT);  
 pinMode (led6, OUTPUT);  
 pinMode (led7, OUTPUT);  
 pinMode (led8, OUTPUT);  
 pinMode (led9, OUTPUT);  
 pinMode (led10, OUTPUT);
 pinMode (pinp, INPUT);   //Indirizzo A0
 pinMode (pinp1, INPUT);  //Indirizzo A1
 pinMode (pinp2, INPUT);  //Indirizzo A2
 pinMode (pinp3, INPUT);  //Indirizzo A3
 pinMode (pinp4, INPUT);  //Indirizzo A4
 pinMode (pinp5, INPUT);  //Indirizzo A5
 pinMode(A0, INPUT_PULLUP);
 pinMode(A1, INPUT_PULLUP);
 pinMode(A2, INPUT_PULLUP);
 pinMode(A3, INPUT_PULLUP);
 pinMode(A4, INPUT_PULLUP);
 pinMode(A5, INPUT_PULLUP);
}

void loop() {
 statop = digitalRead (pinp);
 if (statop == statop2 ) {
   digitalWrite (led1, LOW);
   delay(2000);
 }
 else {
   digitalWrite (led1, HIGH);
   
 }
 statop2 = digitalRead (pinp);
 if (statop2 == statop) {  
   digitalWrite (led2, LOW);
   delay(2000);
 }
 else {
   digitalWrite (led2, HIGH);
 }
}

Buonasera,
essendo il tuo primo post nella sezione Italiana del forum, nel rispetto del regolamento di detta sezione (… 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 tutto il su citato REGOLAMENTO ...

... poi, in conformità al suddetto regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread e sistemato il codice come da regolamento, nessuno ti potrà rispondere, quindi ti consiglio di fare il tutto al più presto. :wink:

Allora, intanto iniziamo da un dettaglio. Direi che dato che "pinp" l'hai impostato a 14 che è l'indirizzo di A0, non ha senso che tu faccia sia:
pinMode (pinp, INPUT); //Indirizzo A0
sia:
pinMode(A0, INPUT_PULLUP);
Usare "pinp" e "A0" non cambia nulla, vale sempre 14! quindi ti basta fare:
pinMode (pinp, INPUT_PULLUP); //Indirizzo A0
e togliere i pinMode() da A0 ad A5.

Passiamo al loop(). Di fatto leggi due volte il pin "pinp" e confronti il suo valore con lo stato precedente, poi se sono uguali attivi o disattivi i led... Insomma, non ho proprio capito, scusa ma mi sfugge la logica del tuo codice.

A parte che eviterei i delay, ma anche volendoli mantenere dovresti prima cercare di ragionare sul flusso, ed una cosa che faccio anche io spesso è partire scrivendo i soli commenti, per poi iniziare ad inserire le linee di codice che implementano il passo descritto (e tra l'altro ti ritroverai anche il codice già commentato...).

Inoltre per semplificare il tutto, dovresti iniziare a studiare un pochino gli array, perché quando si devono gestire elementi "identici" e questi sono più di un paio, il tutto diventa ancora più semplice.

Per cui iniziamo da qui, definendo gli array dei pin:

byte valvolaOn[5] = { 2, 4, 6, 8, 10 };
byte valvolaOff[5] = { 3, 5, 7, 9, 11 };
byte pulsante[5] = { A0, A1, A2, A3, A5 };

quindi la setup() diventa così, guarda com'è tutto più compatto e chiaro:

void setup() {
  for(int i=0; i<5; ++i) {
    pinMode (valvolaOn[i], OUTPUT);
    pinMode (valvolaOff[i], OUTPUT);
  }
  for(int i=0; i<5; ++i)
    pinMode(pulsante[i], INPUT_PULLUP);
}

A questo punto la tua loop() una volta che avrai scritto il codice per gestire un pulsante, otterrai già il codice per tutti!
Ma non mi è ancora chiara neanche la descrizione del comportamento atteso che hai fatto:

se P1 è = 0 accendi led1 per 2", se P1 è = 1 accendi led2 per 2"

Sarebbe meglio usare sempre i termini LOW e HIGH che sono più immediati, ma dato che i tuoi pulsanti sono a logica invertita, nelle descrizioni usa il termine "premuto" o "non premuto":
se P1 è premuto accendi led1 per 2", se P1 non è premuto accendi led2 per 2"
mentre nel codice se definisci il simbolo PREMUTO puoi usarlo nei test:

#define PREMUTO 0
...
  if ( digitalRead(pin) == PREMUTO ) {
    // faccio cose
  }
...
  if ( digitalRead(pin) != PREMUTO ) {
    // faccio cose quando non è premuto
  }

Per tornare al tuo codice, qualcosa non mi quadra perché se tu questo lo fai in un loop e non premi nulla, di fatto accenderai sempre led2 (ossia elettrovalvola OFF) per 2 secondi, dando quasi continuamente alimentazione.

Ossia se io premo il pulsante P1 mi attiva l'uscita per attivare l'elettrovalvola, e dopo un certo tempo (se l'intervallo minimo è 2ms credo che 2 seondi sia inutilmente lungo, facciamo 500 ms?) abbasso la stessa uscita, e fin qui ci sono (l'elettrovalvola ora è aperta), ma quand'è che devo chiuderla? Non l'hai specificato (bisognerebbe sempre descrivere meglio quale debba essere esattamente il comportamento atteso, per tutti i casi previsti). Immagino che tu intenda dire che premendo nuovamente il pulsante debba chiuderla, quindi la pressione del pulsante apre una valvola chiusa o chiude una aperta, il che significa anche memorizzare il relativo stato

Se è così allora ti dò lo spunto per provare a farlo tu e non dare la "pappa pronta" :wink: ossia:

byte valvolaOn[5] = { 2, 4, 6, 8, 10 };
byte valvolaOff[5] = { 3, 5, 7, 9, 11 };
byte pulsante[5] = { A0, A1, A2, A3, A5 };
bool stato[5] = { false, false, false, false, false );

// Durata in ms dell'impulso per le elettrovalvole
#define IMPULSO 500

#define PREMUTO 0

void setup() {
  for(int i=0; i<5; ++i) {
    pinMode (valvolaOn[i], OUTPUT);
    pinMode (valvolaOff[i], OUTPUT);
  }
  for(int i=0; i<5; ++i)
    pinMode(pulsante[i], INPUT_PULLUP);
}

void loop() {
  byte uscita;
  // Ciclo pulsanti
  for(int i=0; i<5; ++i) {
    // Leggo lo stato del pulsante "i" esimo
    // Verifico se è premuto (LOW)
      // E' premuto, qual è lo stato dell'elettrovalvola "i" ossia stato[i]?
        // E' off, devo attivare l'elettrovalvola con valvolaOn[] quindi uso il psuo pin
        uscita = valvolaOn[i];
      else
        // E' on, devo disattivare l'elettrovalvola con valvolaOff[]
        uscita = valvolaOff[i];
      // quindi alzo l'uscita a HIGH
      // poi attendo il tempo necessario
      delay(IMPULSO);
      // e riporto a LOW l'uscita
      // Infine memorizzo il nuovo stato[i], negando quello precedente
  }
}

Grazie della spiegazione ben dettagliata ed anche molto interessante e giustamente non conoscendo il processo funzionale iniziale diventa piu’ difficile consigliare il codice piu’ appropriato.
Per semplificare il tutto da ora dirò di avere 6 interruttori bistabili ON/OFF che controlleranno le elettrovalvole (Interruttore 1, Interruttore 2 ecc..), questi interruttori saranno collegati alle porte di ARDUINO UNO da ora dichiarati come INPUT “A0-A1-A2-A3-A4-A5”
Mentre i terminali 2-3 -4-5-6-7-8-9-10-11-12-13 verranno dichiarati con OUTPUT

La mappatura è questa:
Interruttore 1 va collegato al pin A0(PIN14) che gestisce l’OUTPUT1 (PIN2) e OUTPUT2 (PIN3)
Interruttore 2 va collegato al pin A1(PIN15) che gestisce l’OUTPUT3 (PIN4) e OUTPUT4 (PIN5)
Interruttore 3 va collegato al pin A2(PIN16) che gestisce l’OUTPUT5 (PIN6) e OUTPUT6 (PIN7)
Interruttore 4 va collegato al pin A3(PIN17) che gestisce l’OUTPUT7 (PIN8) e OUTPUT8 (PIN9)
Interruttore 5 va collegato al pin A4(PIN18) che gestisce l’OUTPUT9 (PIN10) e OUTPUT10 (PIN11)
Interruttore 6 va collegato al pin A5(PIN19) che gestisce l’OUTPUT11 (PIN12) e OUTPUT12 (PIN13)

Funzionamento
Se l’interruttore 1 viene commutato in posizione ON (livello logico HIGH) porta l’ingresso A0 a livello logico HIGH, Arduino riconosce che l’ingresso A0 è HIGH e comanda l’OUTPUT1 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 ancora in condizione HIGH.

Invece se l’interruttore 1 viene commutato in posizione OFF (livello logico LOW) porta l’ingresso A0 in condizione LOW, Arduino riconosce che l’ingresso A0 è LOW e comanda l’OUTPUT2 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 con un livello logico LOW.

Queste due uscite OUTPUT1 e OUTPUT2 si andranno a collegare ad un ponte ad H per invertire le polarità della bobina dell’elettrovalvola.
Il tutto poi si replicherà per tutte le altre OUTPUT.

elontesnl:
Per semplificare il tutto da ora dirò di avere 6 interruttori bistabili ON/OFF

Un attimo, tu hai sempre parlato di
che controlleranno le elettrovalvole (Interruttore 1, Interruttore 2 ecc..), questi interruttori saranno collegati alle porte di ARDUINO UNO da ora dichiarati come INPUT “A0-A1-A2-A3-A4-A5”
Mentre i terminali 2-3 -4-5-6-7-8-9-10-11-12-13 verranno dichiarati con OUTPUT

La mappatura è questa:
Interruttore 1 va collegato al pin A0(PIN14) che gestisce l’OUTPUT1 (PIN2) e OUTPUT2 (PIN3)
Interruttore 2 va collegato al pin A1(PIN15) che gestisce l’OUTPUT3 (PIN4) e OUTPUT4 (PIN5)
Interruttore 3 va collegato al pin A2(PIN16) che gestisce l’OUTPUT5 (PIN6) e OUTPUT6 (PIN7)
Interruttore 4 va collegato al pin A3(PIN17) che gestisce l’OUTPUT7 (PIN8) e OUTPUT8 (PIN9)
Interruttore 5 va collegato al pin A4(PIN18) che gestisce l’OUTPUT9 (PIN10) e OUTPUT10 (PIN11)
Interruttore 6 va collegato al pin A5(PIN19) che gestisce l’OUTPUT11 (PIN12) e OUTPUT12 (PIN13)

Funzionamento
Se l’interruttore 1 viene commutato in posizione ON (livello logico HIGH) porta l’ingresso A0 a livello logico HIGH, Arduino riconosce che l’ingresso A0 è HIGH e comanda l’OUTPUT1 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 ancora in condizione HIGH.

Invece se l’interruttore 1 viene commutato in posizione OFF (livello logico LOW) porta l’ingresso A0 in condizione LOW, Arduino riconosce che l’ingresso A0 è LOW e comanda l’OUTPUT2 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 con un livello logico LOW.

Queste due uscite OUTPUT1 e OUTPUT2 si andranno a collegare ad un ponte ad H per invertire le polarità della bobina dell’elettrovalvola.
Il tutto poi si replicherà per tutte le altre OUTPUT.

elontesnl:
Per semplificare il tutto da ora dirò di avere 6 interruttori bistabili ON/OFF

Ah, ecco, tu hai sempre parlato di "pulsanti" non hai mai parlato di "interruttori" ON/OFF!

Se l’interruttore 1 viene commutato in posizione ON (livello logico HIGH) porta l’ingresso A0 a livello logico HIGH, Arduino riconosce che l’ingresso A0 è HIGH e comanda l’OUTPUT1 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 ancora in condizione HIGH.

Invece se l’interruttore 1 viene commutato in posizione OFF (livello logico LOW) porta l’ingresso A0 in condizione LOW, Arduino riconosce che l’ingresso A0 è LOW e comanda l’OUTPUT2 a livello HIGH per una durata di circa 20 sec. per poi ritornare LOW dopo i 20 ms. pur rimanendo A0 con un livello logico LOW.

Ora è tutto chiaro. Quindi non hai dei pulsanti ma degli interruttori, per cui tu non devi agire sulla pressione, ma sul cambio di stato.

Prima domanda: necessiti proprio di interruttori? Perché con la soluzione che ti ho indicato ti bastano dei comuni pulsanti (che magari puoi associare ad un LED che indichi lo stato dell'uscita ON).

Seconda domanda: all'inizio parlavi di un intervallo ON di almeno 20ms, poi nei commenti hai scritto 1 secondo, e nel codice hai messo delay da 2 secondi, ora sono diventati 20! Deciditi... :wink:

Diamo comunque per scontato che siano interruttori. Per agire sul cambiamento di stato devi memorizzare il precedente, per cui ti serve un altro array.

Una cosa del genere quindi (ti ho lasciato i puntini dove devi provare a completare tu le istruzioni):

byte valvolaOn[5] = { 2, 4, 6, 8, 10 };
byte valvolaOff[5] = { 3, 5, 7, 9, 11 };
byte pulsante[5] = { A0, A1, A2, A3, A5 };
bool statoValvola[5];
bool statoInt[5];

// Durata in ms dell'impulso per le elettrovalvole
#define IMPULSO 500

// Valore del pin quando l'interruttore è su ON
#define IS_ON 0

void setup() {
  for(int i=0; i<5; ++i) {
    pinMode (valvolaOn[i], OUTPUT);
    pinMode (valvolaOff[i], OUTPUT);
    statoValvola[i] = false;
  }
  for(int i=0; i<5; ++i)
    pinMode(pulsante[i], INPUT_PULLUP);
    statoInt[i] = false;
}

void loop() {
  byte uscita;
  // Ciclo pulsanti
  for(int i=0; i<5; ++i) {
    // Leggo lo stato del pulsante "i" esimo
    byte stato = digitalRead(pulsante[i]);
    // Verifico se lo stato attuale è diverso dal precedente (statoInt[i])
    if ( ... ) {
      // Cambiamento di stato!
      // Verifico se l'interruttore ora è nella posizione ON (IS_ON)
      if ( ... ) // Se adesso è on, devo attivare l'elettrovalvola con valvolaOn[] quindi uso il suo pin
        uscita = valvolaOn[i];
      else  // Se è off, devo disattivare l'elettrovalvola con valvolaOff[]
        uscita = valvolaOff[i];
      // Ok, alzo l'uscita a HIGH
      digitalWrite(uscita, HIGH);
      delay(IMPULSO); // attendo il tempo necessario
      digitalWrite(uscita, LOW);        
      // Infine memorizzo il nuovo statoValvola[i], negando quello precedente
      ...
      // Quindi memorizzo in statoInt[i] il nuovo stato dell'interruttore
      ...
    }
  }
}

Se hai difficoltà a completarlo, chiedi pure.

Grazie. Ci sbatto un'altro po la testa e ti aggiorno. Ho preparato lo schema elettronico funzionale, appena termino le ultime modifiche te lo allego.

Non vedo il collegamento tra GND dell'alimentazione valvole e GND Arduino, è sottointeso o è una dimenticanza? Per evitare disturbi la connessione è meglio realizzarla direttamente unendo i GND degli alimentatori.

All'accensione a causa del bootloader il pin 13 genera uno o due impulsi a HIGH, in questo caso non dovrebbero dare fastidio perché comunque finché il pin 12 è ancora sconfigurato (in alta impedenza) il primo ponte non dovrebbe attivarsi.

Le resistenze da 10k di pull-down si potrebbero evitare se venissero usate le pull-up interne degli ingressi e gli interruttori chiudessero verso massa invece che verso +5V. Piuttosto meglio collegare tra ingressi e massa dei condensatori da 100nF così da avere il debounce hardware ma soprattutto un filtro contro i disturbi impulsivi.

Ci sono due o tre cose da chiarire:
Arduino, oltre a ripetere i comandi degli interruttori, cosa altro fa?
È previsto che diventi un timer, un telecomando, un qualche automatismo oppure semplicemente ripete i comandi?

Durante il tempo di attesa per l'azionamento di una valvola, le altre devono potersi comandare o no?

Tu hai già l'impianto idrico? Per poter fare prove oppure no?

Si certo l'alimentatore è unico, quindi il GND è lo stesso che alimenta Arduino, ci avevo pensato anche io per le resistenze di pull-down se inserirle ed aggiungere un condensatore sugli ingressi è sicuramente utile per creare un filtro contro i disturbi impulsivi. Mi spieghi meglio questa istruzione:

// Valore del pin quando l'interruttore è su ON
#define IS_ON 0

Ho allegato lo schema elettrico corretto.

Standardoil:
Ci sono due o tre cose da chiarire:
Arduino, ........

Allora Arduino sostanzialmente diventa una piccola interfaccia, in realtà gli collegherò una centralina esistente ma non adatta al tipo di valvola già installata. La centralina ha un App che gestisce l'irrigazione e la parte hardware ha le sue uscite per l'attivazione delle elettrovalvole a 24Vac, questo può essere superato utilizzando come ho fatto gli ingressi analogici ed un partitore di tensione non inserito nello schema. Il funzionamento di questa centralina è quello che comanda un tipo di valvola ON-Off, cioè dai tensione e la valvola si attiva, togli tensione e la valvola si disattiva. Per le valvole già installate purtroppo questo tipo di centralina no è adatta in quanto le stesse valvole installate sono di tipo impulsive, mi spiego devi dargli una tensione per 20-100ms. e la valvola si commuta come aperta per poi dopo i 20ms riportare la tensione ai suoi capi a 0V pur rimanendo l'interruttore sull'app attivo (Utilissimo questo stato in quanto mi da il feed-back che è attiva o disattiva), invece quando la spegni devi invertirgli le polarità (ecco l'utilizzo del ponte ad H) ma sempre con un impulso massimo tra i 20-100ms e poi ritornare a OV. Questo tipo di valvola è interessante in quanto non riscalda e a riposo se attiva o no non assorbono corrente, questo nel caso di sistemi controllati a batteria. Il range della mia valvola parte dai 5V fino a 24Vdc, io per praticità ho scelto una tensione di 12Vdc. Altro fattore che ho tenuto conto che sull'App ci sono 6 pulsanti con funzione ad interruttore, quindi essendo un unico comando ho pensato di utilizzarlo con il fronte di salita e di discesa dello stato della commutazione del pulsante. Io in realtà l'ho già realizzato con un PLC della Siemens giusto per testare l'idea e mi funziona, ma la programmazione è completamente diversa da Arduino. Certo che le valvole le posso controllare singolarmente ed in maniera indipendente es.. tipo 2 attive e le altre spente ecc.. L'impianto, lo posso testare perché è tutto montato.

Guarda, per fare quello che ti serve non hai bisogno né di arduino né di elettronica

Per ogni uscita della centralina metti un rele a uno scambio a 24 vac

E comandi le valvola a scarica di condensatore
https://forum.arduino.cc/index.php?topic=545604.0

Fine, semplicissimo

elontesnl:
Mi spieghi meglio questa istruzione:

// Valore del pin quando l'interruttore è su ON

#define IS_ON 0

Con la #define definisci una stringa che ti aiuta nella lettura del codice a cui associ un valore.
In questo caso la stringa è IS_ON e il valore è 0. Ma potresti usare XE_IMPISA o ACCESO o PREMUTO o IN_POSIZIONE_ALTA, come preferisci e come ti ricorda meglio la situazione che stai implementando.
In fase di pre-compilazione, questa stringa viene sostituita con il valore e poi il codice viene compilato.
Non occupa spazio nel programma e ti permette di usare termini per te significativi invece di valori che possono creare confusione.

Ho letto la tua presentazione, complimenti per i tuoi interessi e l'entusiasmo che traspare.
Mi pare di intuire, però, che al momento attuale, un tuo punto debole sia il software, ti stai addentrando da poco in questo mondo? E' giusto per capire il tuo livello per affrontare meglio le discussioni future.

La domanda "È previsto che diventi un timer, un telecomando, un qualche automatismo oppure semplicemente ripete i comandi?" era per capire se si poteva fare anche a meno di Arduino, perchè se deve solo ripetere i comandi senza fare altro, si potrebbe fare anche solo con componenti elettronici, se invece ci devi fare elaborazioni nel mezzo, ha senso mantenerlo.
Comunque, non sta scritto da nessuna parte che se si può fare senza si debba fare senza, puoi comunque usare Arduino per fare pratica e imparare a svilupparci qualcosa.

Perdonami, ma non ho avuto tempo di analizzare il tuo codice, ma mi ha colpito questa tua frase: "Ho scritto questo codice e mi funziona solo per un comando relativo al PULSANTE1 ed i Led1 e Led2, ma come implemento il resto del codice mi funziona tutto sballato."
Cosa ti succede quando aggiungi i pulsanti successivi? cioè cosa significa esattamente "funziona tutto sballato"?
Da una descrizione esatta del sintomo, a volte, si può capire molto del problema anche senza analizzare il codice.

Il mio primo suggerimento, visto che ti stai lanciando in questo mondo e potresti averne delle belle soddisfazioni, è di iniziare fin da subito a bandire il delay() e di abituarti ad usare la funzione millis()
E anche se non l'hai usata, sempre per partire con il piede giusto, ti consiglio anche di far finta che non esista proprio la classe String :wink: altro IED seminato nel mondo Arduino da evitare per non avere brutte sorprese.

Cercando sul forum troverai articoli su articoli che spiegano il motivo di questi due suggerimenti iniziali.

Maurizio

P.S.
Socio, ci siamo sovrapposti :wink:

maubarzi:
La domanda "È previsto che diventi un timer, un telecomando, un qualche automatismo oppure semplicemente ripete i comandi?" era per capire se si poteva fare anche a meno di Arduino, perchè se deve solo ripetere i comandi senza fare altro, ....

P.S.
Socio, ci siamo sovrapposti :wink:

Esatto, socio

Anche sovrapporsi accade spesso, perché abbiamo i cervelli sincroni e attaccati alla stessa centrale Enel, evidentemente

Comunque c'è da considerare che il comando a scarica di condensatore garantisce che in caso di mancanza di energia le valvole si chiudano da sole

Con il ponte H rimarrebbero aperte

elontesnl:
Mi spieghi meglio questa istruzione:

// Valore del pin quando l'interruttore è su ON

#define IS_ON 0

Dato che gli ingressi li definisci con INPUT_PULLUP sono a "logica inversa" ossia la posizione "OFF" (ossia interruttore non in conduzione) corrisponde al valore HIGH (ossia 1, comunque diverso da zero) mentre quando è su "ON" (interruttore in conduzione) porta il pin a GND per cui leggerai LOW (ossia zero).

Quel simbolo è quindi non solo per rendere più "parlante" il codice, ma anche per evitare errori quando si tratta di logica inversa:

...
      // Verifico se l'interruttore ora è nella posizione ON (IS_ON)
      if ( stato == IS_ON ) // Se adesso è on, devo attivare l'elettrovalvola con valvolaOn[] quindi uso il suo pin
        uscita = valvolaOn[i];
      else  // Se è off, devo disattivare l'elettrovalvola con valvolaOff[]
        uscita = valvolaOff[i];
...

A parte quindi ora le connessioni ed il circuito, estendi il codice che ti ho impostato e troverai tutto molto più semplice.

elontesnl:
Ho allegato lo schema elettrico corretto

Se i pulsanti/interruttori chiudono verso i 5V allora servono anche le resistenze di pull-down che c'erano prima, altrimenti quando sono aperti che livello stabile hanno gli ingressi?

Se chiudono verso GND allora venno bene le pull-up interne.

Standardoil:
Guarda, per fare quello che ...

Sono d'accordo, che facendo come hai consigliato si semplifica, ma alla fine mi ritrovo a non aver imparato nulla nella programmazione e siccome io sono curioso e approfondisco la mia conoscenza con nuovi metodi e istruzioni che oggi possono essere complicate mi sicuramente mi potranno aiutare su altri progetti. :slight_smile:

docdoc:
Dato che gli ingressi li definisci con INPUT_PULLUP sono a "logica inversa" ossia la posizione "OFF" ............

Ho impostato dei valori, ma sicuramente ci sono un bel po di errori:

byte valvolaOn[6] = { 2, 4, 6, 8, 10, 12 };
byte valvolaOff[6] = { 3, 5, 7, 9, 11, 13 };
byte pulsante[6] = { A0, A1, A2, A3, A4, A5 };
bool statoValvola[6];
bool statoInt[6];


// Durata in ms dell'impulso per le elettrovalvole
#define IMPULSO 500

// Valore del pin quando l'interruttore è su ON
#define IS_ON 0

void setup() {
	for(int i=0; i<6; ++i) {
		pinMode (valvolaOn[i], OUTPUT);
		pinMode (valvolaOff[i], OUTPUT);
		statoValvola[i] = false;
	}
	for(int i=0; i<6; ++i) 
		pinMode(pulsante[i], INPUT_PULLUP);
	statoInt[i] = ( pulsante, LOW);
	
}

void loop() {
	byte uscita;
	// Ciclo pulsanti
	for(int i=0; i<6; ++i) {
		// Leggo lo stato del pulsante "i" esimo
		byte stato = digitalRead(pulsante[i]);
	}
	// ? Verifico se lo stato attuale è diverso dal precedente (statoInt[i]) *********
	if (statoInt[i] == false) {
		pulsante[i] = HIGH;
	}
	// Cambiamento di stato!
	// Verifico se l'interruttore ora è nella posizione ON (IS_ON)
	if (stato == IS_ON ); // ? Se adesso è on, devo attivare l'elettrovalvola con valvolaOn[] quindi uso il suo pin
		uscita = valvolaOn[i];
	
	else  // Se è off, devo disattivare l'elettrovalvola con valvolaOff[]
		uscita = valvolaOff[i];
	// Ok, alzo l'uscita a HIGH
	digitalWrite(uscita, HIGH);
	delay(IMPULSO); // attendo il tempo necessario
	digitalWrite(uscita, LOW);       
	// Infine memorizzo il nuovo statoValvola[i], negando quello precedente
	digitalWrite(!statoValvola[i]);
	// Quindi memorizzo in statoInt[i] il nuovo stato dell'interruttore
	digitalWrite(statoInt[i]);
   }
  }
}

elontesnl:
in realtà l'ho già realizzato con un PLC della Siemens giusto per testare l'idea e mi funziona, ma la programmazione è completamente diversa da Arduino

Magari meno diversa da quello che pensi, un programma in KOP (ma anche a blocchi funzionali o SFC) si può benissimo tradurre quasi uno a uno in corrispondenti istruzioni C. Infatti il C è un linguaggio generale con cui si possono costruire tutti gli altri. Se c'è un KOP funzionante magari la traduzione è semplice.


Ulteriore considerazione: nel caso in cui io muova velocemente l'interruttore più volte a caso, mi aspetto che alla fine la valvola si porti sempre in uno stato coerente con l'interruttore (e che ovviamente le uscite mutuamente esclusive non si possano mai attivare contemporaneamente). Secondo me il programma (KOP, C o altro che sia) deve tenere conto anche di questa eventualità.

Quindi prima sarebbe da scrivere la logica impostata con una serie di if che analizzano i vari casi, da cui si ricavano anche quali quante variabili di stato sono necessarie.

Qualcosa del genere:

  leggo ingresso

  se int chiuso e valvola chiusa e valvola disattiva:
      attivo valvola apertura
      memorizzo valvola aperta
      memorizzo valvola attiva
      memorizzo tempo

  se int aperto e valvola aperta e valvola disattiva:
      attivo valvola chiusura
      memorizzo valvola chiusa
      memorizzo valvola attiva
      memorizzo tempo

  se valvola attiva e trascorsi 500ms:
      disattivo valvole
      memorizzo valvola disattiva

In particolare con questa logica per ogni valvola serve una variabile che indica se è aperta o chiusa, una che indica se è in fase di attività (è alimentata), e una variabile tempo per memorizzare il tempo di sistema quando la valvola viene attivata.

Con l'ingresso e lo stato aperta o chiusa sappiamo se ci dobbiamo muovere, e con il controllo sull'attività sappiamo se dobbiamo attendere che finisca un impulso in corso.

Nel caso di più valvole queste variabili possono essere array, rendendo tutto più compatto come suggerito da Doc.

Una logica più semplice che non aspetta la fine dell'impulso corrente, ma inverte subito il movimento se si sposta rapidamente l'interruttore può essere questa (molto più simile a quella che stai cercando di impostare e che richiede solo la variabile temporale):

  leggo ingresso

  se variato
      aggiorno stato precedente
      memorizzo tempo sistema
      se int chiuso
          comando valvola in apertura
      altrimenti
          comando valvola in chiusura

  se trascorsi 500ms
    disattivo comandi valvole

elontesnl:
Ho impostato dei valori, ma sicuramente ci sono un bel po di errori:

Eh si, perché devi tenere conto anche delle indentazioni che ti avevo messo, ma anche delle graffe.

Ad esempio perché hai chiuso la graffa dopo la lettura?

	for(int i=0; i<6; ++i) {
		// Leggo lo stato del pulsante "i" esimo
		byte stato = digitalRead(pulsante[i]);
	}  <--- QUESTA!

Quella istruzione for() deve finire dove te l'ho fatta finire io, ossia alla fine del loop(), che poi uello di implementare la stessa logica per tutti i pulsanti ed uscite è anche lo scopo della for (e degli array).

Stesso discorso per la if() successiva:

    // ? Verifico se lo stato attuale è diverso dal precedente (statoInt[i]) *********
    if (statoInt[i] == false) {
		pulsante[i] = HIGH;
	}  <--- QUESTA!

Devi togliere quelle graffe.

Inoltre la condizione "statoInt[i] == false" non traduce quello che è scritto nel commento, verifica solo se lo stato precedente sia "false" o meno. Devi invece verificare se lo stato attuale, ossia il valore presente nella variabile "stato", sia diverso da quello precedente, ossia statoInt[i]. Quindi:

    // ? Verifico se lo stato attuale è diverso dal precedente (statoInt[i]) *********
    if ( stato != statoInt[i] ) {
		pulsante[i] = HIGH;

Poi vediamo anche questo:

      // Infine memorizzo il nuovo statoValvola[i], negando quello precedente
      digitalWrite(!statoValvola[i]);

Per "memorizzo" si intende che imposto il valore dell'elemento statoValvola[i] con l'opposto del suo valore (se è true metto false, se è false metto true), mentre tu così non solo non stai stai facendo questo ma è anche una chiamata errata (digitalWrite richiede due parametri: il numero di pin e lo stato desiderato del pin),segno che hai ancora un bel pò di confusione nella programmazione su Arduino (ma non solo, credo che tu debba anche cerare di capire come funzionano gli array...).

Quello che avresti dovuto fare è questo:

      // Infine memorizzo il nuovo statoValvola[i], negando quello precedente
      statoValvola[i] = !statoValvola[i];

Una cosa analoga anche per il successivo, nel quale devi memorizzare in statoInt[i] lo stato attualme dell'interruttore (ossia la variabile "stato"):

      // Quindi memorizzo in statoInt[i] il nuovo stato dell'interruttore
      statoInt[i] = stato;

Ora se hai più o meno capito gli errori, rimetti insieme queste cose che ti ho indicato, fai girare lo sketch e vedi se va o se c'è ancora qualcosa da cambiare.