Interruttore realizzato con un bottone non totalmente funzionante

Ciao a tutti, ho cercato molto su internet ma non sono riuscito a trovare un singolo tutorial funzionante per realizzare un interruttore con un bottone. Avete dei consigli per farlo?
Grazie in anticipo

Cioè ? Lo premi una volta è ON, lo ripremi è OFF, lo ripremi è ON, etc. ??

Se si, usi una variabile di stato associata al pulsante (associata in maniera logica da te)
https://www.arduino.cc/en/tutorial/switch
In italiano non saprei, cerca "arduino button as toggle switch"
Si trovano anche delle librerie già fatte. Ad esempio qui

grazie, era questo che cercavo, solo che su internet ci sono tutti algoritmi complessi, adesso provo a realizzare questo sketch e integrarlo con quello che voglio realizzare

Una volta capito il concetto... tutte quelle righe (che hanno un'evidente scopo didattico) le puoi sostituire con un codice più snello ed efficiente.

 if (digitalRead(inPin)== HIGH && millis() - time > debounce) {
  state = !state;   // L'operatore ! inverte lo stato di state (0 diventa 1 e viceversa);
  time = millis();    
}

Se parliamo di didattica e efficenza mi sento di segnalare all'OP che, come sempre detto sul forum, il debounce dei pulsanti è meglio farlo via hardware con condensatore e resistenza o con integrati appositi, nei casi in cui è necessario usarlo, che si evitano un sacco di complicazioni via software e, cosa non meno importante, se il pulsante è agganciato ad un interrupt la soluzione harware è quasi sempre l'unica via.
Con il debounce hardware il codice si riduce a:

if(digitalRead(inPin)== HIGH){
...
}

o LOW se il pulsante è collegato a GND e, quindi, ha la pullup

cotestatnt:
tutte quelle righe (che hanno un'evidente scopo didattico) le puoi sostituire con un codice più snello ed efficiente.

Si ma in quel modo tenendo premuto il pulsante (per più tempo del debounce, che in genere è sui 50-100 ms) continuerà ad invertire lo stato.... Deve farlo solo nella transizione da LOW a HIGH (se la logica è quella normale e non invertita), quindi deve memorizzare il precedente stato.

Anche se il debounce hardware è sempre consigliato, diciamo che facendone senza e dando per scontato che non abbia problemi ad avere un delay (ed essendo agli inizi non credo stia realizzando qualcosa "mission critical" :wink: ), basta una cosa del tipo:

...
byte prevState = LOW;
...
  byte curState = digitalRead(inPin);
  if (curState== HIGH && prevState ==LOW) {
    state = !state;   // L'operatore ! inverte lo stato di state (0 diventa 1 e viceversa);
    delay(50); // Rimuovere questo se si usa il debounce hardware
  }
  prevState = curState;
...

Cosi pero' ti funziona solo se curstate e' high e prevstate e' low ... forse e' meglio fare semplicemente

void loop() {
  curState = (digitalRead(inPin));
  if ((digitalRead(inPin) != prevState) && (prevState == 0)) {
    state = !state;
    prevState = curState;
  }
  else if ((digitalRead(inPin) != prevState) && (prevState == 1)) prevState = curState;
}

EDIT: ah, no, aspetta, e' indifferente in quel caso perche' e' un pulsante ... ok, come non detto

RIEDIT: (:P) ... mi sa pero' che avrebbe lo stesso un problema ... rimetti subito prevstate = curstate appena fuori dall'if senza controllare che il pulsante sia rilasciato, quindi la tua condizione e' valida solo la prima volta ... alla fine il secondo else if ci va in ogni caso, mi sa ... :wink:

Ragasssiiii, ufficio complicazione affari semplici ? :slight_smile:

byte curState = digitalRead(inPin);
state ^= curState && !prevState;
prevState = curState;

... traduca, prego ... possibilmente non in Aramaico con sottotitoli in Sanscrito :stuck_out_tongue: :smiley:

La variabile state viene invertita con uno xor solo nel ciclo di programma in cui l'espressione curState && !prevState vale 1, e cioè quando curState viene riscontrato 1 con prevState che vale zero (fronte di salita). È la stessa identica logica applicata da voi, solo scritta in modo meno prolisso.

268971.png

268971.png

... e per l'antirimbalzo basta un condensatore da circa 100nF in parallelo al pulsante.

Claudio_FF:
byte curState = digitalRead(inPin);
state ^= curState && !prevState;
prevState = curState;

Che mirabile bellezza racchiudono queste 3 righe di codice!
P.S.
Ma l'OP ce lo siamo perso? Federico batti un colpo se ci sei ancora.

Beh... Forse nelle ultime 24 ore ha avuto qualche altra cosa da fare... :slight_smile:

Ho realizzato questo codice che serve per usare un pulsante come se fosse un interruttore, all'accensione funziona sempre ma quando voglio spegnerlo non sempre funziona
Suggerimenti per risolvere il problema?

int inPin =7;
int stato =  LOW;
int reading;
const int Y_pin = 1;
int a = 999;
int punt = 0;
int led = 0;
void setup() {
  Serial.begin(9600);
  pinMode(inPin, INPUT);
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop() {
  if (digitalRead(7)== HIGH) {
    stato = !stato;
    delay(200);
  }
  if (stato == HIGH) {
         int b = analogRead (Y_pin);
 if (b < 300){
    a = 13;
    Serial.println(a);
  }
  else if (b > 700){
    a = 12;
    Serial.println(a);
}
else {
   a = 11;
    Serial.println(a);
}
  }
else {
  a = 0;
    Serial.println(a);
    delay(5);
    digitalWrite(11, LOW);
    delay(5);
    digitalWrite(12, LOW);
    delay(5);
    digitalWrite(13, LOW);
delay(5);
}
if (stato == HIGH) {
      led = random(1,4);
      if (led == 1){
  delay(400);
  digitalWrite(13, HIGH);
  digitalWrite(12, LOW);
   digitalWrite(11, LOW);
}
if (led == 3){
    delay(400);
      digitalWrite(13, LOW);
  digitalWrite(12, LOW);
   digitalWrite(11, HIGH);
}
if (led == 2){
    delay(400);
      digitalWrite(13, LOW);
  digitalWrite(12, HIGH);
   digitalWrite(11, LOW);
}
}
}

>federicofrasca: il cross-posting è proibito dal regolamento e tu stai discutendo di questo argomento (Interruttore realizzato con un bottone) già in questo thread.

Ho riunito io il tuo nuovo thread che avevi aperto sullo stesso argomento con questo e ti prego di proseguire qui senza aprire ulteriori thread. Grazie.

Guglielmo

si ok...ma il problema è completamente diverso...

NO, il problema è lo stesso, è il TUO codice che non funziona come dovrebbe, ma sempre di un bottone che deve accendere e spegnere di tratta ... ::slight_smile:

Guglielmo

federicofrasca:
Ciao a tutti..

Io direi che se tu usassi un 'bottone totalmente funzionante ' troveresti meno problemi...

Allora, una cosa per volta.
Il codice di federicofrasca
Non è molto chiaro ciò che deve essere eseguito quando l'interruttore è acceso/spento. Per tale motivo semplificherei rendendo chiara l'azione da eseguire; ad esempio semplicemente accendendo e spegnendo il led on board.

Riguardo ai delay, c'è da dire che soffrono di effetto lato, cioè risolvono un problema introducendone un altro.
Già è stato consigliato il debounce hardware che per vari motivi andrebbe sempre impiegato anche quando si decide di introdurne uno software per sicurezza. Quindi almeno un condensatore da 100nF (nanofarad) tra pin e GND, posizionato vicino al pin e poi anche un filo lungo a cui collegare il pulsante.

Il codice di Claudio_FF
Nel post compare un codice già mostrato e spiegato sempre da Claudio_FF che però o è passato inosservato oppure non è stato metabolizzato. Riguardo a questo punto mi sono preso la briga di testare il codice e ho scritto un piccola classe, per adesso trovo interessante mostrare lo stream binario di ingresso e il relativo stream di uscita.

Lo stream di ingresso è il risultato della digitalRead eseguita per ogni loop.
0000 1111 0000 1111 0000 1111

Lo stream di uscita è lo stato dell'interruttore, sempre per ogni ciclo di loop.

0000 11111111 0000 0000 1111

Se continuiamo a stampare lo stato dell'interruttore senza premere il pulsante avremo 1111111 all'infinito.

Funziona quindi, però si riferisce al pulsante collegato con pull-down, non è evidente ma basta poco per farlo funzionare anche con pull-up, mantenendo lo stesso stream di uscita.

Il codice arduinesco dovrebbe essere il seguente (non testato)

// Serve un debounce hardware, quindi almeno il già citato condensatore da 100nF
boolean state; // lo stato di uscita (stream binario di uscita)
boolean prevState; // lo stato precedente 

const byte inPin = 5;  // pin di ingresso pulsante
void loop() {
    boolean curState = digitalRead(inPin);
    state ^= curState && !prevState;
    prevState = curState;

    digitalWrite(13, state);
    
    }
}

Sempre di Cladio_FF c'è anche l'esempio di edge detect che credo non sia stato metabolizzato. L'edge detect è utilissimo perché lo stato di uscita vale 1 per un solo ciclo di loop.

PS: testato non con arduino, ma usando il PC e una digitalRead() che legge da un array locale.

Ciao.

federicofrasca:
Suggerimenti per risolvere il problema?

Se non usi un CTRL+T nell'IDE che indenta in maniera decente e mostra i blocchi in maniera decente io personalmente mi rifiuto di fare ulteriori commenti
E poi spiega cosa dovrebbe fare oltre a gestire lo switch come interruttore perchè non si capisce nulla. Non puoi pretendere che capiamo cosa fa quel codice (senza uno straccio di commento) senza info.

Ti consiglio di fare un programma con solo il bottone come interruttore per 1 led, POI piano piano aggiungiamo quello che ti serve. Un passo alla volta.