blink dentro un while loop

Buonasera a tutti, non sono molto esperta su arduino e ho fatto varie ricerche online ma non ho trovato nulla. Vorrei, all’interno di un while loop, far accendere e spegnere un led. Questo servirà per creare un allarme collegato ad un sensore pir.
Ecco la prima prova di codice.

//definisco i vari pin a cui sono collegati i sensori
#define pir_sensor 3
#define led 5

//pause per evitare l'uso di delay
#define pausa 250

int stato = LOW; //stato del led iniziale
bool mov=0;      //variabile per il controllo del pir
unsigned long t0, dt;  //varibili per controllare la pausa

void setup() {
Serial.begin(115200);
pinMode(pir_sensor, INPUT);
pinMode(led, OUTPUT);
t0 = millis();
}

void loop() {
  mov = digitalRead(pir_sensor);
  if(mov>0){   //se rilevo un movimento
    Serial.println("movimento rilevato");
    while (mov = digitalRead(pir_sensor) && mov>0){  //fin quando il movimento è rilevato
     dt = millis() - t0;  
        if (dt >= pausa && mov>0 ) {
          t0 = millis();
          stato = !stato;
          digitalWrite(led, stato);    //cambia lo stato del sensore
          mov = digitalRead(pir_sensor);  //controlla lo stato del pir
          }    
        }
      } 
  else {
    Serial.println("nessun movimento rilevato");
    digitalWrite(led, LOW);
    delay(1000);
  }
}

Con questo ottengo un loop infinito. Il led lampeggia all’infinito e non riesco ad uscire dall’if (sebbene nessun movimento sia apparentemente rilevato). Ho provato con un ciclo for, ma peggio di peggio. Ho poi pensato un’altra alternativa, che effettivamente funziona e mi fa uscire dal loop, l’unico problema è che vorrei il led lampeggiasse per circa 8 secondi, ma non riesco ad ottenerlo. Per di più, una volta eseguito l’if, non riesco a rientrarci nuovamente per far lampeggiare il led in caso di nuovo movimento rilevato. Mi spiego meglio. Il pir rileva un movimento, il led lampeggia (per un numero di secondi che non riesco a controllare), nessun movimento rilevato, il led si spegne. Viene rilevato un nuovo movimento, il led non lampeggia più sebbene l’if sia eseguito. Allego qui il codice.

//definisco i vari pin a cui sono collegati i sensori
#define pir_sensor 3
#define led 5

//pause per evitare l'uso di delay
#define pausa 250

int stato = LOW; //stato del led iniziale
bool mov=0;      //variabile per il controllo del pir
unsigned long t0, dt;  //varibili per controllare la pausa
int i=0;   //variabile per controllare il numero di "passi" dell'if

void setup() {
Serial.begin(115200);
pinMode(pir_sensor, INPUT);
pinMode(led, OUTPUT);
t0 = millis();
}

void loop() {
  mov = digitalRead(pir_sensor);
  if(mov>0){   //se rilevo un movimento
    Serial.println("movimento rilevato");
    while (mov = digitalRead(pir_sensor) && mov>0){  //fin quando il movimento è rilevato
     dt = millis() - t0;  
        if(dt >= pausa && i<50 ) {
          t0 = millis();
          stato = !stato;
          digitalWrite(led, stato);    //cambia lo stato del sensore
          i++;
/*incremento il valore di i, una volta arrivato a 50, il blink si ferma, vorrei però che durasse di più
  cioè fin quando il pir rileva un movimento. Finiti questi 50 "passi", se un nuovo movimento è rilevato, il led
  non lampeggia più
UPDATE: il sensore di movimento rimane attivo per 8 secondi dopo la prima rilevazione, tuttavia questo if,
  apparentemente, lo "congela", finito di lampeggiare per i suoi 50 "passi" poi riprende il conto del pir
  me ne sono resa conto perchè, pur aumentando il numero di "passi", il sensore non rileva nessun movimento
  solo dopo diversi secondi che il led ha smesso di lampeggiare*/
          }    
        }  //ho provato ad inserire un "i=0" qui ma ovviamente resetta il ciclo e riparte l'if
      } 
  else {
    Serial.println("nessun movimento rilevato");
    digitalWrite(led, LOW);
    delay(1000);
  }
}

Grazie in anticipo, spero sia fattibile :confused:

Buonasera e benvenuta/o, :slight_smile:
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… 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 ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Il problema è conosciuto e ogni utente si scontra con queste problematiche. Sai già che la funzione loop è già di per se un ciclo infinito. Innestare un ciclo all'interno di un altro ciclo ha queste conseguenze, per aggirarle ci sono diversi modi, ma sostanzialmente si tratta di sfruttare il ciclo loop e delle variabili verificate con if che selezionano o meno il codice da eseguire ad ogni ciclo.

Come inizio potresti pensare di creare una variabile di nome allarmState di tipo boolean dove salvare lo stato della condizione di allarme.

Ad esempio:

void loop() {
    mov = digitalRead(pir_sensor);
    if (mov > 0) {
        allarmState = true;  // salvo lo stato di allarme (lo accendo)
    } 

    if (allarmState == true) {
       stato = !stato;
       digitalWrite(led, stato);
       delay(1000);
       // qui puoi incrementare una variabile contatore 
       // qui con if (contatore>8) allarmState = false; spegni l'allarme

    }   
}

Questo per avere almeno qualcosa di apparentemente funzionante, in realtà dovremmo accendere l'allarme quando per diciamo 1 secondo viene rilevato del movimento. Ma è meglio aggiungere le funzionalità dopo avere un codice di base funzionante.

Ciao e benvenuta.

Grazie mille! Ho creato il codice come suggerito e funziona. Il problema, al solito, è che il led lampeggia solo fin quando il contatore non è "pieno". Finiti gli 8 conteggi, il led si spegne e l'allarme resta attivo per qualche secondo ancora, poi si disattiva e va avanti. Ho creato una versione differente per fare una prova. Allego il codice.

void loop() {
  mov = digitalRead(pir_sensor);
  if(mov>0){   //se rilevo un movimento
    allarm_state = true;
    dt = millis() - t0;
    if(allarm_state==true && dt >= pausa){
      t0 = millis();
      stato = !stato;
      digitalWrite(led, stato);
      Serial.println("allarme attivo");
    }
  }
  else {
    Serial.println("nessun movimento rilevato");
    digitalWrite(led, LOW);
    delay(1000);
  }
}

Purtroppo in questo caso, se l'allarme viene attivato, il led rimane spento per circa 8 secondi, poi rimane acceso fisso, per circa 8 secondi ed infine l'allarme viene disattivato. La mia idea era quella di far rimanere attivo questo if per la durata della pausa (8 secondi), ma non riesco a far lampeggiare il led.
Grazie mille per l'aiuto.

Questa if:

if(mov>0)

non si sa per quanti cicli di loop() sarà valutata vera, cioè potrebbe essere vera per un solo ciclo e al prossimo ciclo viene valutata falsa. Tu annidi una if dentro questa e se if(mov>0) è falsa la if interna non viene più eseguita. Per questo motivo ho usato allarmState.

Ricorda che delay() impegna la cpu per tutto il tempo specificato nel suo argomento e durante questo tempo nessuna altra riga di codice può essere eseguita. Per tale motivo elimina la delay(1000) o anche meglio la clausola else.

Altra cosa: hai dimenticati di spegnere allarmState dopo 8 secondi, cioè dopo 8 secondi scrivi allarmState = false;

Un passo per volta ricorda.

byte contatore = 0;

void loop() {
  mov = digitalRead(pir_sensor);
  if(mov>0){   //se rilevo un movimento
    allarm_state = true;
  }
  // non ci sono if annidate  
  if(allarm_state==true) {
    
    stato = !stato;
    digitalWrite(led, stato);
    delay(1000);   // resta a questa riga per 1 secondo
    contatore++;   // incrementa il contatore
    if (contatore == 8) {
       allarmState = false; // spendo allarmState
    }
  
  }
}

Non è la soluzione migliore a causa del delay() che impegna la cpu, ma cosa comporta lo devi sperimentare
per poi trovare un modo alternativo impiegando millis(), ma come detto un passo per volta.

Ciao.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.