Go Down

Topic: Led che una volta selezionato, viene escluso dal ciclo (Read 241 times) previous topic - next topic

paolinux78

Ciao a tutti, sto sviluppando un progetto in cui ho 5 led e 2 pulsanti, il primo pulsante mi permette di accendere i led in sequenza (uno alla volta) e un secondo pulsante deve selezionare ed "eliminare" dallo scorrimento questo led, in pratica una volta selezionato rimane acceso e poi col primo pulsante quando ricomincio a premerlo mi fa scorrere gli altri 4 led, e via così.... qual'è la strada migliore? col codice finora scritto sono arrivato a far scorrere i led col primo pulsante:

https://www.youtube.com/watch?v=6dGGKXGvGLs&ab_channel=2pansuper8

Code: [Select]
int led = 0;
byte tasto = 0;

void setup() {
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);

}

void loop() {
  if ((digitalRead(7) == LOW) && (tasto == 0)) {
    led++;
    tasto = 1;
  }
  if ((digitalRead(7) == HIGH) && (tasto == 1)) {
    tasto = 0;
  }

  if (digitalRead(8) == LOW) {

  }


  if (led == 1) {
    digitalWrite(9, HIGH);
    digitalWrite(13, LOW);
  }
  if (led == 2) {
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
  }
  if (led == 3) {
    digitalWrite(11, HIGH);
    digitalWrite(10, LOW);
  }
  if (led == 4) {
    digitalWrite(12, HIGH);
    digitalWrite(11, LOW);
  }
  if (led == 5) {
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    led = 0;
  }
}

fabpolli

Una possibile strada potrebbe essere un array che contenga lo "stato" dei led, quando premi l'altro pulsante sai su che led sei, metti nell'array che quel led è da escludere e alle successive pressioni del primo pulsante prima di accendere il led controlli se nell'array è segnato come da escludere, se si vai al successivo non escluso.
Se poi vuoi migliorare ulteriormente fai un array con i pin a cui sono connessi i led in modo da accendere l'attuale e spegnere il precedente tipo:
Code: [Select]

digitalWrite(pinLed[led], HIGH);
digitalWrite(pinLed[ledPrecedente], low);

dove ledPrecedente lo calcoli in modo che ti restituisca l'indice del led precedente non escluso, e per led precedente devi anche fare attenzione che il precedente del primo è il quinto  ;)

cotestatnt

#2
Feb 23, 2021, 10:12 am Last Edit: Feb 23, 2021, 12:19 pm by cotestatnt
Io sono un fan dei metodi ricorsivi, meno righe di codice ed algoritmo più efficiente.

Ti propongo una possibili soluzione "alternativa" al tuo approccio:
https://www.tinkercad.com/things/3zWVOPG6l1y

Code: [Select]
const byte outputLed[] = {13, 12, 11, 10, 9};
const byte button1 = 3;
const byte button2 = 2;
 

int maxIndex = sizeof(outputLed);
int onIndex = 0 ;
int offIndex = maxIndex -1;

void setup(){
  Serial.begin(9600);
  for (int i=0; i<sizeof(outputLed); i++){
    pinMode(outputLed[i], OUTPUT);
  }   
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);

  delay(1000);
}

void loop(){
 
 if(digitalRead(button1) == LOW){
   // Debounce pulsante (meglio hardware)
   delay(100);
   
   // Accensione/spegnimento del led corrispondente all'indice
   digitalWrite(outputLed[onIndex], HIGH);
   digitalWrite(outputLed[offIndex], LOW);
   
   onIndex = (onIndex +1) % maxIndex;
   offIndex = (offIndex +1) % maxIndex;
 }
 
 // Se l'ultimo led è acceso e premo il pulsante, modifico maxIndex
 // in modo da escludere l'ultimo led dalla sequenza
 if((digitalRead(button2) == LOW)
   && (digitalRead(outputLed[maxIndex]) == HIGH))
 {
   maxIndex = sizeof(outputLed) - 1;
   offIndex = maxIndex -1;   
 }

}
 




fabpolli

Out of bound exception (ok non è java ma per capirsi :) )

cotestatnt

Out of bound exception (ok non è java ma per capirsi :) )
Perdonami, ma non l'ho capita  :o :o :o

fabpolli

Prova a pensare a che indice usi qui:
Code: [Select]

digitalWrite(outputLed[index], LOW);

quando
Code: [Select]

if(index >= maxIndex)

E provando il progetto che hai messo nel link non funziona correttamente, l'ultimo led resta sempre acceso non appena tocchi il secondo pulsante

cotestatnt

Code: [Select]

if(index >= maxIndex)

Ouch!! 
Svista gravissima  :smiley-confuse:
Ora dovrebbe essere più safe (a patto che l'array di outputs è >= 2);



E provando il progetto che hai messo nel link non funziona correttamente, l'ultimo led resta sempre acceso non appena tocchi il secondo pulsante
Scusa, ma non è il comportamento richiesto dall'OP? In caso negativo non ho ben capito la richiesta allora...

fabpolli

no lui vol escludere un led in base a dove è posizionato, ovvero il terzo è acceso? Premo il secondo pulsante e quello non deve più accendersi.
Comunque non hai messo il codice aggiornato sul forum. E poi mi fermo perché l'OP dovrebbe dare qualche riscontro.

cotestatnt

Si in effetti rileggendo meglio la cosa ha senso.
Rimango in stand-by anche io in attesa di @paolinux78


P.S. correggo subito il codice

paolinux78

no lui vol escludere un led in base a dove è posizionato, ovvero il terzo è acceso? Premo il secondo pulsante e quello non deve più accendersi.
Comunque non hai messo il codice aggiornato sul forum. E poi mi fermo perché l'OP dovrebbe dare qualche riscontro.

esattissimo, seleziono per esempio il terzo LED col secondo pulsante, resta acceso e continuano a scorrere gli altri premendo il primo pulsante.... ho provato il codice scritto da cotestatnt ma purtroppo non fa questa cosa...

fabpolli

Ma infatti io ti suggerisco di partire da quello come base (se lo hai capito e non solo copiaincollato) e usare il mio suggerimento per implementare il tuo programma, se puoi non ti funziona siamo qui per aiutarti (Punto 16 del regolamento ;) )

cotestatnt

il codice scritto da cotestatnt ma purtroppo non fa questa cosa...
eeh no, perché io avevo frainteso completamente la tua richiesta.
Però butto li un'altra idea che potrebbe semplificare ulteriormente: 
al posto degli array che complicano un po' la faccenda per la gestione dell'indice, una variabile che fa da shift register ed una che tiene traccia dei n led "bloccati" ( bastano da un byte per la tua applicazione).  

Un pulsante esegue lo shift  e lo mette in or con le uscite sempre on, ed il secondo pulsante mette a 1 il bit associato al led di volta in volta selezionato ad esempio con bitSet(shift_out, index);


 (codice non completo ovviamente)

Code: [Select]
byte shift_out = 0;
byte led_lock = 0;

......
   index = (index +1) % maxIndex;
   shift_out  = 1 << index;    // 0b 0000 0001  => 0b 0000 0010
   shift_out |= led_lock ;  
   Serial.println(shift_out , BIN);  

   for (int i=0; i<maxIndex; i++){    
     digitalWrite(outputLed[i], bitRead(shift_out , i));      
   }  
......





paolinux78

eeh no, perché io avevo frainteso completamente la tua richiesta ....
Grazie 1000 per la risposta, ma sono stra principiante e non so ancora usare i registri a scorrimento purtroppo :(
Fabpolli suggeriva di escludere un valore dall'array, come si fa?

gpb01

>paolinux78: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso. :)

Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia ;)

Guglielmo

P.S.: Ho troncato io il "quote" del tuo post qui sopra ;)
Search is Your friend ... or I am Your enemy !

cotestatnt

Gli array sono oggetti "statici", aggiungere o rimuovere elementi all'array implica la gestione "manuale" della memoria e della sua riallocazione. Operazioni che io mi sentirei proprio di sconsigliarti vivamente in virtù della tua poca esperienza.

Quello che intendeva fabpolli, se non ho frainteso, è creare un array "parallelo" in cui memorizzi se quel led specifico deve rimanere acceso sempre oppure no.

Per quanto riguarda lo shift register è un'operazione più semplice di quello che può sembrare.
 
Ad esempio prendiamo l'operazione shift_out  = 1 << index; e poniamo che indec =2.
L'istruzione significa prendi il valore 1, esegui lo shift a sinistra di 2 posizioni e copialo nella variabile shift_out che tradotto in bit:

Code: [Select]
shift_out  = 0b 0000 0001 << 2   =====>   shift_out diventa uguale a 0b 0000 0100

In pratica quello che io facevo nell'esempio sbagliato con l'indice dell'array lo fai muovendo un solo bit, il concetto è lo stesso.
L'istruzione successiva invece, mette a 1 il bit che a seguito del pulsante deve essere sempre acceso:
Code: [Select]
shift_out |= led_lock  è equivalente a shift_out =  shift_out  | led_lock ;   (il simbolo | è l'operatore booleano OR)
quindi se shift_out uguale a 0b 0000 0100  e ad esempio led_lock  = 0b0000 1000  dove il bit 3 uguale a 1 (corrispondente al led  4) sta ad
indicare che quel led deve essere sempre acceso

0b 0000 0100  |   0b0000 1000  = 0b 0000 1100  quindi il led n.3 ed il led n.4 dovranno essere accesi successivamente


Poi per "lavorare" con i bit, ci sono tutte le macro predefinite per leggere e scrivere il bit "enne" della variabile y.


Per sapere quanto vale il bit bit_number in byte_var:
bool risultato = bitRead( byte_var, bit_number);
Mettere a 1 uno specifico bit di una variabile:
bitSet(byte_var, bit_number);

Mettere a 0 uno specifico bit di una variabile:
bitClear(byte_var, bit_number);

Può sembrare complicato, ma se ci ragioni un po' su lasciando il codice e la sua sintassi da parte per un momento e concentrandoti solo sull'algoritmo, vedrai che cogli immediatamente il senso.

Logica "a bit" o ad elementi dell'array a parte, in generale secondo me è sempre meglio cercare di scrivere del codice che sia il più possibile chiaro, riutilizzabile e facilmente scalabile (non una lista di istruzioni infinita che ripetono sempre le stesse cose).

In questo caso specifico ad esempio, se i led un domani dovessero diventare 20 o 30 o 50, tutto quello che devi fare è modificare l'array iniziale con tutti i pin necessari, e il resto del codice rimarrebbe del tutto identico.

Go Up