Problemi di loop

Salve a tutti,
premetto che mi sono avvicinato da poco ad arduino, e lo tovo semplicemente fantastico.
Il mio circuito è il solito circuito standard formato da pulsante e led.
problema: come posso impostare il sw per far si che se premo 1 volta si accende, alla seconda lampeggia ogni sec, alla terza lampeggia ogni mezzo sec, alla 4 si spegne??
Attenzione ovviamente non deve fare solo un lampeggio, ma continuare a lampeggiare per sempre, quindi configurazioni del tipo:

val == digitalread(bottone);
if (val != 0) { //pulsante premuto
cont++;
if (cont=1) {
digitalWrite(led,HIGH);
}
if (cont=2) {
digitalWrite(led,HIGH);
delay(1000);
digitalWrite(led,LOW);
delay(1000);
}
if (cont=3) {
digitalWrite(led,HIGH);
delay(500);
digitalWrite(led,LOW);
delay(500);
}
if (cont=4) {
cont=0;
}
}

le ho provate ma non funzionano, in quanto il led lampeggia 1 sola volta e poi basta

Ringrazio tutti in anticipo:

Tu incrementi count finche hai premuto il pulsante.
Deci vedere il cambio di stato del Pulsante e solo in quel caso incrementare la variabile count.

Ciao Uwe

Il problema dovrebbe derivare dalla velocità del loop che in mancanza di controlli come gestiti nel consiglio di uwe ti fanno incrementare val oltre il dovuto.
Per un test veloce prova a mettere un delay(500) dopo il count++ ed aggiungi una graffa di chiusura dopo questo delay.
count devi dichiararlo globale

Ps modifica il titolo del topic, è assolutamente fuorviante

Per come lo hai scritto, ti lampeggia solo se premi il pulsante infatti le porzioni di codice che accendono il LED sono dentro l'IF che verifica la pressione.

Suddividilo in due parti.

  • Verifica se il pulsante viene premuto, in tal caso incrementa il contatore

  • A seconda del valore del contatore fai quello che devi fare

Esatto, è così che devi fare.
Devi togliere il controllo di count da dentro l'if con cui leggi lo stato del pulsante perché queste operazioni devi farle comunque. Ah, altra cosa, i confronti si fanno con 2 segni di uguale, cioè "if (cont == 3)", tu fai assegnazioni: if (cont=3).
Inoltre ti serve gestire gli intervalli non con delay ma con millis perché se sei ad esempio nel caso di count == 3, tu fai attendere 1000 ms prima che esca da quella operazione.

Ok grazie a tutti x i suggerimenti, posto il nuovo codice:

const int bottone = 7;
const int led = 13;
int cont = 0;
int val = 0;
int vval= 0;

void setup() {
  pinMode(led,OUTPUT);
  pinMode(bottone,INPUT);
}

void loop() {
  val = digitalRead(bottone);
  if (val!= vval) {
    delay(200);
    cont++;
  }

  if (cont == 1) {

    digitalWrite(led,HIGH);
    delay(1000);
    digitalWrite(led,LOW);
    delay(1000);

  }
  if (cont == 2) {
    digitalWrite(led,HIGH);
    delay(500);
    digitalWrite(led,LOW);
    delay(500);
  }

  if (cont == 3) {

    digitalWrite(led,HIGH);
    delay(250);
    digitalWrite(led,LOW);
    delay(250);
  }
  if (cont == 4) {
    cont = 0;
    digitalWrite(led,LOW);
  }
}

Ora il problema è che per cambiare programma (es tra 1 e 2) se non becco la fine del loop non mi legge il cambiamento. Come posso fare x evitare ciò??
Grazie a tutti

Quel vval mi sembra inutile, visto che rimane sempre 0.

Ti avevano suggerito di evitare l'uso del delay ed è proprio questo che provoca il difetto riscontrato.

Imposta l'intervallo fra un cambio di stato e l'altro (fra on ed off del LED) in base alla frequenza del lampeggiamento e poi richiama ad ogni loop una funzione che ti cambia lo stato del pin se è trascorso un intervallo di tempo uguale a quello da te impostato.

confermo, non vedo nessuna utilita' a vval, se lo togli vedrai che il risultato e' lo stesso. in pratica credo tu lo intenda come antibounce, ma l'antibounce vero nel tuo caso e' quel delay che c'e' dopo

per fare quello che dici devi studiarti il millis, e' utile partire dall'esempio presente nell'ide stesso "Blink without delay"

Ho cercato su internet, ed ho trovato questo: Arduino – lezione 03: controlliamo un led con un pulsante | Michele Maffucci.
Purtroppo per quanto mi sforzi, non riesco a capirne il senso, o per meglio dire ne capisco la logica , ma solo se applicata in 2 casi (premo e accendo - premo e spengo il led);
Se qualcuno di voi mi volesse aiutare a capire meglio, o se mi volesse postare il codice corretto (poi da solo tento di capirlo) ne sarei grato. Ricordo a tutti che il mio scopo è di leggere lo stato del bottone mentre il led lampeggia (senza aspettare la fine del loop).

Grazie a tutti

A me sembra errata la premessa, nella lezione che indichi.
Si dice all'inizio che scopo della lezione è realizzare un sistema che accende la luce alla pressione del pulsante e la spegne ad una successiva pressione.

Invece viene realizzato un sistema che tiene la luce accesa se tieni il dito premuto sul pulsante ma la spegne appena lo lasci.

EDIT: nella seconda parte del tutorial viene spiegato come modificare il codice in modo da ottenere l'effetto desiderato. Il codice che stiamo commentando si riferisce alla prima parte del tutorial!
Mi scuso con l'autore per l'inconveniente.

Analizziamo il codice: (lo riporto così come è, con i commenti originali)

// Esempio 01: accendi il led appena è premuto il pulsante  
  
#define LED 13                // LED collegato al pin digitale 13  
#define BUTTON 7              // pin di input dove è collegato il pulsante  
int  val = 0;                 // si userà val per conservare lo stato del pin di input  
  
void setup() {  
  pinMode(LED, OUTPUT);       // imposta il pin digitale come output  
  pinMode(BUTTON, INPUT);     // imposta il pin digitale come input  
}  
  
void loop() {  
  val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva  
  
  // controlla che l'input sia HIGH (pulsante premuto)  
  if (val == HIGH) {  
    digitalWrite(LED, HIGH);  //accende il led  
  }  
  else {  
    digitalWrite(LED, LOW);   //spegne il led  
  }  
}

La prima parte è banale.
Concentriamoci sul loop

si inizia con un
val = digitalRead(BUTTON);
quindi se il bottone è premuto hai alto altrimenti hai basso
e poi con l'if-else accendi il LED se hai alto (quindi il tasto premuto) e lo spegni se hai basso (quindi tasto non premuto)
e poi si riprende da val = digitalRead(BUTTON); e così via.
Considerando che ci vuole un tempo brevissimo per eseguire l'if, il risultato sarà
tasto premuto = LED acceso
tasto non premuto = LED spento
contrariamente alla premessa.

Grazie Paulus per il tuo intervento, ma ti confermo che a circa meta articolo si parla di variazione di stato.
Inoltre chiedo l'aiuto della comunity per capire bene il mio errore, o per meglio dire (l'errore l'ho individuato) come risolvere la questione.
La mia necessità è capire come posso far fare ad Arduino 2 azioni in contemporanea:

  1. far lampeggiare il led
  2. controllare lo stato del bottone senza aspettare la fine del loop di lampegio

personalmente avevo pensato 2 soluzioni:

  1. sostituire il pulsante con un selettore (ma cio mi occupa più input, non risolvo il problema dell'attesa della fine del loop, ma dopo mi cambia in automatico)
  2. inserire nei vari loop un if per il controllo del pulsante tipo:
if (cont == 1) {

    digitalWrite(led,HIGH);
    if(val!=vval) {
      delay(500);   //antirimbalzo
      cont++;
      }
    delay(1000);
    digitalWrite(led,LOW);
    if(val!=vval) {
      delay(500);   //antirimbalzo
      cont++;
      }
    delay(1000);

  }

Accetto consigli e modifiche, ma soprattutto (e molto più volentieri) spiegazioni.

Grazie

Ti suggerisco questo mio articolo:
http://www.leonardomiliani.com/2013/programmiamo-i-compiti-con-millis/

@paulus1969

A me sembra errata la premessa, nella lezione che indichi.

Non è errata la premessa è errato non continuare a leggere tutto il tutorial, dove vengono mostrati tutti i passaggi per arrivare
al codice che svolge il compito specificato nella premessa.

In quel codice c'è anche una possibile modifica da fare:

if (stato == 1) {  
    digitalWrite(LED, HIGH);   // accende il led  
}  
  else {  
    digitalWrite(LED, LOW);    //spegne il led  
}

diventa:

digitalWrite(LED, stato);

Se stato vale 1 il led sarà acceso, se vale 0 si spegne.
Ma il codice è mostrato con le if a fini istruttivi.

Ciao.

Ops... errore mio, in effetti quei tutorial di solito sono fatti bene, correggo il post!

Un sentito ringraziamento a tutti, spero di aver risolto con il consiglio di leo72.
In effetti l'idea di comparare il timer con il ritardo è una buona idea, ora si deve solo applicare al mio caso con il bottone e 4 frequenze diverse di lampeggio.

Solo una cosa ma

ledState ^= 1;

cambia da 0 a 1 se ho letto bene la reference di arduino.
Mi confermate.
Grazie

L'operatore ^ è lo XOR, cioè OR negato esclusivo.
Serve per cambiare il valore da 0 a 1 senza fare un confronto con if.

edit: ops... thank you Mauro...

leo avast mi blocca per virus il tuo sito

Dettagli dell'infezione


URL:
http://www.leonardomiliani.com/|{gzip} 

Processo:
D:\Backup\GoogleChromePortable\App\Chrom... 

Infezione:
JS:Decode-AFL [Trj]

L'operatore ^ è lo XOR, cioè OR negato.
Serve per cambiare il valore da 0 a 1 senza fare un confronto con if.

Aggiungo "e viceversa" come riportato sulla reference

The ^ operator is often used to toggle (i.e. change from 0 to 1, or 1 to 0) some of the bits in an integer expression

Forse ci sono. Posto il codice, aspetto i vostri giudizi. Premetto che l'ho scritto su g-drive col tablet a letto, quindi perdonate i molti errori, è il contenuto che conta.

Led=11 //pwm
Currentmillis = 0
Periodo1=250
Periodo2=50
Val =0

Void loop (){

Val = digitalread (bottone)
Currentmillis=millis
If val==HIGH {
Delay200.    / /debounce
CONT++  //aumenta il contatore
Millis=0. //azzera millis
}
If cont==1 && currentmillis==periodo1 { //se cont=1 ed è il 
//momento giusto
Led state ^=1. //cambia stato
Digitalwrite(led,led state). //accendi e spegni
Millis=0   //azzera millis
}
If cont==2 && currentmillis == periodo2 { //se cont=2 ed è il
// momento giusto
For(i=0; i<255; i+5){   //aumenta di 5 l' I'intensita
Analogwrite( led,i). //accendi analogicamente
Millis=0
}
For(i=255;i>0;i-5){
If currentmillis==periodo2{
Analogwrite(led,i)
Millis=0
}
}
If cont=3{
Digitalwrite( led,low)
Cont=0
}
}

Edit:
Come non detto, da una lettura veloce millis non si può resettare, quindi devo usare delle variabili.

millis si può resettare ma devi agire in questo modo:

extern volatile unsigned long timer0_overflow_count; //serve per accedere al contatore usato da millis();
...
timer0_overflow_count = 0; //mettilo dove devi resettare millis