Memorizzare stato degli output inseriti in un indice array

Salve a tutti, torno ad usare questo utilissimo forum dopo un po’ di tempo.

Vorrei accendere e spegnere 4 output con dei pulsanti normali, ovviamente la chiamata da parte degli input deve essere casuale, cioè io dovrò accendere 4 dispositivi non in un ordine preciso ma nell’ordine che ritengo opportuno al momento, anche tutti insieme ecc ecc… Ho pensato quindi di avvalermi dell’uso degli array che consentono di creare dei gruppi di funzioni esterne al loop o al controllo del flusso.

Ho trovato questo code che potrebbe fare al caso mio, solo che in questo modo la funzione ‘else’ mi fa spegnere il led quando rilascio il pulsante, invece vorrei che il led rimanga acceso fino a che non ripremo il pulsante nuovamente, come fosse un interruttore. E questo deve essere applicato a tutti e 4 i led. Qualcuno ha un’idea di come possa memorizzare gli stati utilizzando gli indici?

vi incollo il code attuale e vi ringrazio moltissimo per l’attenzione!

int pinPulsanti[] = {2,3,4,5};    // crea un array di pin per gli input  
                                  // costituiti dai pulsanti  
  
int pinLed[] = {10,11,12,13};     // crea un array di pin di output per il LED  
  
void setup()  
{  
  for(int indice = 0; indice < 4; indice++)  
  {  
    pinMode(pinLed[indice], OUTPUT);            // dichiara il LED come output  
    pinMode(pinPulsanti[indice], INPUT);        // dichiara il pulsante come input  
    digitalWrite(pinPulsanti[indice],HIGH);     // abilita la resistenza di pull-up  
  
    // l'abilitazione della resistenza di pull-up mi permette di non utilizzare  
    // una resistenza esterna in serie al pulsante  
  }  
}  
  
void loop(){  
  for(int indice = 0; indice < 4; indice++)  
  {  
    int stato = digitalRead(pinPulsanti[indice]);  // legge il valore di input  
    if (stato == LOW)                              // controlla se il pulsante è premuto  
    {  
      digitalWrite(pinLed[indice], HIGH);        // accende il LED il pulsante è premuto  
    }  
    else  
    {  
      digitalWrite(pinLed[indice], LOW);          // spegne il LED  
    }  
  }  
}

ciao,

breve opinione personale...in questo caso non c'è differenza da avere un array tipo:

byte pulsanti[4];

e 4 variabili:

byte pulsante0, pulsante1, pulsante2, pulsante3;

se non quella di avere un unico "nome" e lavorare sul suo [indice].

detto questo...per far lavorare un pulsante come un interruttore devi gestire nello sketch un flag per ogni uno di questi che memorizza il passaggio tra "non premuto" e "premuto" cambiando il valore del flag.

EDIT: scusa vedo adesso che usi un for per verificare lo stato dei pin...non so perchè pensavo ad altro quando hai scritto "gruppi di funzioni"...quindi anche i flag ti converrebbe gestirli in un array e quindi tutto andrebbe nello stesso ciclo for.

Grazie veramente per la risposta, cercherò di approfondire la funzione flag.

Grazie!

almax85:
... cercherò di approfondire la funzione flag.

flag NON è una funzione !!! ... Con il termine "flag" si suole chiamare un "indicatore" (una "bandierina") che ti permette di ricordarti se una cosa è avvenuta o meno.

Puoi usare una variabile di tipo "byte", e metterla a 0 o a 1 a seconda se la cosa è avvenuta o meno. Al posto di 0 ed 1 puoi usare "false" e "true" ... la cosa non cambia, ti serve sempre per ricordarti se un evento è avvenuto o meno o se sei in una certa situazione o un altra, ecc. ecc.

Guglielmo

ciao,

flag (tradotto = bandiera) non è una funzione...è un "concetto"; cioè utilizzi una variabile , generalmente una boolean ma dipende da cosa voi fare, per segnalare che un'azione è avvenuta....esempio (pseudocodice):

se(pulsante==HIGH && flagPulsante==false){ // prima volta che il pulsante viene premuto
digitalWrite(pinOut,!digitalRead(pinOut)); // cambio stato al pinOUT
flagPulsante = true; // così esegue questo if solo una volta
}
se(pulsante==LOW && flagPulsante==true){ // ci entro solo se ho cambiato una prima volta flagPulsante
flagPulsante=false; // mi permette di rientrare nel primo if
}

Chiedo scusa ragazzi mi sono espresso male!
Seguirò le vostre preziose dritte, vi aggiorno prestissimo!
Grazie davvero.

Salve,
Non capisco perché é necessario l'array. Io credo basti dire
Se legge il pulsante
{
Allora carico una variabile con millis();
}
Fino a che non é passato un certo tempo
{
Controllo se non sento il tasto
{
Il tempo é passato
La flag diventa un numero (non usare booleana, troppo scomoda)
}
}
Se la flag é x
{
Inverto stato pin
La flag diventa y
}
Se la flag é y
{
Fino a che sento il tasto
}
La flag torna 0

Può inserire tutto questo in una forma che legge un array di pulsanti 1 a 1. Così bastano 2 array (pulsanti e led) collegati 1=1 (pulsante 1 led 1.... E haibrisolto.
Con gli array ricorda che il primo elemento é lo 0 e che non ci sono controlli sulla lettura, quindi metticeli tu.
Una flag, un selettore, un tempo, un fisso di lunghezza array, due array, un fisso di tempo necessatio (anche se non é richiesto un tempo preciso di pressoine usslo per evitate false letture) ed é fatta

scusate se mi intrometto, io ho fatto così
non sono capace di incollare il codice, ci ho provato ma non riesco...

void P3manual()
{
if (digitalRead(P3pin))
{
if (P3set == 0) //se P3 era spenta la accendo
P3set = 1;
else
P3set = 0; //altrimenti spengo
}
if (P3set == 1) digitalWrite (P3pin, Accesa); //parte P3
else digitalWrite (P3pin, Spenta); //spengo P3
}
}

...se può servire....

Grazie ancora per la vostra disponibilità, infatti non dubitavo della tempestività dei vostri aiuti. giovepluvio in effetti è quello che vorrei fare, creare due indici array uno 0 - 3 per i pulsanti e l'altro sempre 0 - 3 per i led( che poi non saranno dei led, dovrò far partire 4 trenini lima da 4 postazioni diverse con pulsanti) ma questo poco importa a me serve che gli output si attivino alla pressione del puls e si disattivino alla pressione successiva.
Il mio problema è proprio quello di simulare gli interruttori. Non ho ben chiaro come usare la flag, dovrei metterne una associandola a un numero dopo la lettura del pulsante e l'altra con altro numero dopo il cambiamento di stato? questo per tutti e quattro gli stati? quindi a questo punto elimino il ciclo for?

Nello 'pseudo code' postato da ORSO2001 non ho chiaro perché usi un digitalRead sotto digitalWrite per cambiare lo stato del led, non basterebbe mettere il pinout a 1?

grazie ancora

Grazie MircoZ, scusa non capisco cosa intendi per P3, è input o output?
scusate le troppe domande.. due anni senza toccare arduino mi hanno arrugginito :frowning:

P3 per il mio programma (questo è lo stralcio di un programma notevolmente più grosso) è l'identiicativo di un Relè, P3set è una variabile di appoggio e P3pin il pin dove è collegato il relè.
Tu dovresti mettere un ciclo for che ripete il codice sui tuoi 4 pulsanti e imposta a 0 o 1 il tuo array[n] invece di p3set e poi con una cosa di questo genere accendi i LED...

digitalWrite (P1pin, array[1]);
digitalWrite (P2pin, array[2]);
digitalWrite (P3pin, array[3]);
digitalWrite (P4pin, array[4]);

mi raccomando di mettere una pausa nel ciclo for in modo da evitare i rimbalzi del pulsante, ameno un centinaio di millisecondi al giro....

ciao almax85,

se guardi bene ho scritto:

digitaWrite(pinOut,!digitalRead(pinOut));

c'è quel "!" prima del digitalRead(pinOut)...il "!" in questo caso significa "l'opposto", in genere significa diverso, cioè nella posizione di dove si mette lo stato da impostare nella digitalWrite() io gli dico: imposti l'opposto di come è adesso. Facendo così non mi servono variabili locali o globali per salvare lo stato di come ho precedentemente impostato il pinOut...e riduco il numero di istruzioni da inserire...con due if() ho chiuso il cerchio...suggerimento...il debounce (l'antirimbalzo del pulsante) fallo hardware e non software con verifica tempi etc...

Ok Orso2001 ora mi è chiaro! tutta l'operazione va ripetuta per i vari pulsanti e pinout nel void loop?

ciao almax85,

si ...ovvio che le inizializzazione (stato di partenza) vanno dichiarate nel setup()...es.: pin1==LOW; pin2==HIGH etc...flag1==flase; flag2==false; etc...come prassi.

nel loop() i due if() per ogni pulsante/pin

Altrimenti se io impostassi l'else dopo uno stato associato al pinOut dopo l'avvenuta lettura del pulsante e del conseguente stato precedente del pinOut, a quel punto l'accensione del pin sarebbe come la voglio io, o accesa o spente a seconda di com'era prima? sbaglio? provo a mettere un piccolo code..

if (digitalRead(pulsante) == LOW && (statoPinout0 == LOW))
 { 
       statoPinout0 = HIGH;

  else   statoPinout0 = LOW;
  digitalWrite(Pinout, statoPinout0);
 
 }

In questo caso l'accensione del pin è lo stato attuale quindi mi va sempre bene

chiaramente mettendo un integer in cui richiamo 'statoPinout' e lo pongo a LOW

questo lo farei per tutti e quattro gli eventi con 4 statoPinout0 - 3 potrebbe funzionare?

if (digitalRead(pulsante) == LOW && (statoPinout0 == LOW))

{
      statoPinout0 = HIGH;

else  statoPinout0 = LOW;
  digitalWrite(Pinout, statoPinout0);

}

hmmm…controlla meglio quello che hai scritto in quanto non corretto e forviante…else{} non può essere all’interno dell’if() in questo modo…else senza le “{}” esegue solo la riga di codice immediatamente successiva…le altre saranno fuori dall’else e quindi eseguite per le condizione precedenti…

Dopo alcune verifiche il codice consigliato da Orso mi pare che funzioni molto bene! Per adesso ho provato con due pulsanti e due led ma mi sembra ok..
posto qui il codice affinché possa essere d'aiuto a chi s'imbatte in un progetto analogo, chiaramente consigliate pure se ritenete che possa essere migliorato

int flag1 = 1;
int flag2 = 1;


void setup() {
  // put your setup code here, to run once:
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
flag1==false;
flag2==false;


}

void loop() {
  // put your main code here, to run repeatedly:
if (digitalRead(1) == HIGH && flag1==false)
{ digitalWrite(12, !digitalRead(12));
flag1 = true;
delay(200);
}
if(digitalRead(1)==LOW && flag1==true)
{ flag1=false;
}
if (digitalRead(2) == HIGH && flag2==false)
{ digitalWrite(13, !digitalRead(13));
flag2 = true;
delay(200);
}
if(digitalRead(2)==LOW && flag2==true)
{ flag2=false;
}
}

Ho aggiunto i delay per stabilizzare la pressione, anche se questo è tutto da vedere perché il progetto è destinato alla scheda Arduino yun (con scheda di rete integrata wi-fi) quindi il progetto non sarà controllato da pulsanti fisici ma da un'applicazione per smartphone collegata all'indirizzo IP assegnato dal router alla scheda arduino yun.

Volevo comunque aggiungere il codice alternativo che testandolo pare sia anch'esso funzionante..

int statoLed0 = LOW;
int statoLed1 = LOW;




void setup() {
  // put your setup code here, to run once:

  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);

  digitalWrite(12, statoLed0);
  digitalWrite(13, statoLed1);

}

void loop() {
  // put your main code here, to run repeatedly:

if (digitalRead(1) == HIGH )
 { 
  if (statoLed0 == LOW) statoLed0 = HIGH;
  else                  statoLed0 = LOW;
  digitalWrite(12, statoLed0);
  delay(400);
 }
 if (digitalRead(2) == HIGH )
 { 
  if (statoLed1 == LOW) statoLed1 = HIGH;
  else                  statoLed1 = LOW;
  digitalWrite(13, statoLed1);
  delay(400);
 }
}

invertendo lo stato del led (in questo caso) dentro l'if mi da la possibilità di svolgere le condizioni precedenti quindi l'effettivo stato del led avendo messo digitalWrite(pin, statoLed)
non lo so forse concettualmente è errato ma per il mio caso funziona, nel caso risulti forviante invito i visitatori a non tener conto del code.

ancora grazie per i vostri indispensabili consigli
a presto!

int statoLed0 = LOW;
int statoLed1 = LOW;




void setup() {
  // put your setup code here, to run once:

  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);

  digitalWrite(12, statoLed0);
  digitalWrite(13, statoLed1);

}

void loop() {
  // put your main code here, to run repeatedly:

if (digitalRead(1) == HIGH )
 { 
  if (statoLed0 == LOW) statoLed0 = HIGH;
  else                  statoLed0 = LOW;
  digitalWrite(12, statoLed0);
  delay(400);
 }
 if (digitalRead(2) == HIGH )
 { 
  if (statoLed1 == LOW) statoLed1 = HIGH;
  else                  statoLed1 = LOW;
  digitalWrite(13, statoLed1);
  delay(400);
 }
}

questo ha senso...infatti è diverso dal primo esempio che avevi postato...per forviante intendevo che, anche cercando di immaginare quello che volevi fare, le variabili erano troppe.
felice di essere stato d'aiuto.

Grazie Orso2001, si ho modificato soprattutto l'if, nel senso che ne ho eliminato and && e ho messo un altro if dopo la graffa dove ho poi inserito l'else.

grazie a tutti

Io credo ci sia ancora qualcosina che si può migliorare.

  1. Attento che ,i pin a0 e a1 sono usati dalla seriale hardware, non so se la compresenza di qualcosa crea problemi, ma comunque meglio saperlo.
  2. una riga di codice può farti eliminare l'else.
digitalWrite (2, ! digitalRead (2));

Così facendo puoi anche eliminare le due variabili globali. Infatti ti leggo la riga
Metti (il pin 2, come NON leggi (il pin2))fine
Si, si possono leggere le uscite, e ti restituiscono lo stato.
3) Comunque per variabili di piccoli valori credo sia preferibile il tipo byte, più piccolo di un int ma egualmente efficace in questo caso.
Questa credo sia la forma migliore (a meno di non volerla accorciare stravolgendo la ed usando gli array).
Scusa se faccio il precisino, ma bel programma, complimenti