Lo sketch è corretto ma non funziona come dovrebbe.

Salve a tutti, come già scritto nella mia presentazione sono un appassionato che si diletta a giocare con componenti elettronici e arduino, cerco sempre di capire dove sbaglio ma in questo caso non trovo il mio errore.
Cercando informazioni anche qui sul forum, ho creato uno sketch che dovrebbe far funzionare il mio progetto che si articola in questo modo:

1° sensore PIR
10 led
2° sensore PIR

I due sensori si trovano all'inizio e alla fine di un corridoio di circa 4 metri senza illuminazione naturale, e questa soluzione eviterebbe di dover camminare al buio, (si il corridoio è provvisto di luci) ma principalmente dovrebbe servire come segnapasso per degli eventuali spostamenti notturni.

Comunque dovrebbe funzionare in questo modo, quando i led vengono attivati dal sensore 1 si accendono in sequenza dal led 1 al led 10 e restano accesi per un tempo x, dopodiché iniziano a spegnersi con la stessa sequenza dal led 1 al led 10.
Quando i led vengono attivati dal sensore 2 si accendono in sequenza dal led 10 al led 1 e restano accesi per un tempo x, dopodiché iniziano a spegnersi con la stessa sequenza dal led 10 al led 1.

Sono riuscito a far funzionare tutto tranne la sequenza finale in cui i led si dovrebbero spegnere dal 10 all'1, invece accade il contrario.

So per certo che avrei potuto fare di meglio e che si potrebbe compattare studiandolo più approfonditamente, ma vi prego di avere pietà delle mie scarse capacità di programmazione.

byte StatoSensore = 0;
unsigned long previousMillis = 0;
unsigned long interval = 3000;          //timer
byte ritardo = 50;                      //attesa.

void setup() {

  pinMode(2, OUTPUT);                   //uscita LED
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT); 
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT); 
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);  
  pinMode(12, INPUT);                   //ingresso sensore 1
  pinMode(13, INPUT);                   //ingresso sensore 2
}

void loop() {

  StatoSensore = digitalRead(12);       //leggo i dati del sensore 1
   if (StatoSensore == HIGH) {          //sensore attivo
    digitalWrite(2, HIGH);              //accendi led
    previousMillis = millis();          //ricorda il momento in cui lo hai acceso
    delay(ritardo);                     //attendi prima di accendere il led successivo
    digitalWrite(3, HIGH); 
    previousMillis = millis();
    delay(ritardo); 
    digitalWrite(4, HIGH); 
    previousMillis = millis();
    delay(ritardo);  
    digitalWrite(5, HIGH);   
    previousMillis = millis();  
    delay(ritardo);         
    digitalWrite(6, HIGH);   
    previousMillis = millis(); 
    delay(ritardo);        
    digitalWrite(7, HIGH);  
    previousMillis = millis();
    delay(ritardo);  
    digitalWrite(8, HIGH);
    previousMillis = millis(); 
    delay(ritardo);  
    digitalWrite(9, HIGH);  
    previousMillis = millis(); 
    delay(ritardo);       
    digitalWrite(10, HIGH);  
    previousMillis = millis(); 
    delay(ritardo);    
    digitalWrite(11, HIGH); 
    previousMillis = millis(); 

} else {
   if (millis() - previousMillis > interval) {
    digitalWrite(2, LOW);               //intervallo di tempo passato, spegni il led
    delay(ritardo);                     //attendi prima di spegnere il led successivo
    digitalWrite(3, LOW);
    delay(ritardo);      
    digitalWrite(4, LOW);  
    delay(ritardo);  
    digitalWrite(5, LOW); 
    delay(ritardo);      
    digitalWrite(6, LOW);
    delay(ritardo);  
    digitalWrite(7, LOW);
    delay(ritardo);  
    digitalWrite(8, LOW);  
    delay(ritardo);   
    digitalWrite(9, LOW); 
    delay(ritardo);   
    digitalWrite(10, LOW);  
    delay(ritardo);   
    digitalWrite(11, LOW);  
    }
    delay(ritardo);                     //aspetta

  StatoSensore = digitalRead(13);       //leggo i dati del sensore 2
   if (StatoSensore == HIGH) {          //sensore attivo
    digitalWrite(11, HIGH);             //accendi led
    previousMillis = millis();          //ricorda il momento in cui lo hai acceso
    delay(ritardo);                     //attendi prima di accendere il led successivo
    digitalWrite(10, HIGH);   
    previousMillis = millis();  
    delay(ritardo);   
    digitalWrite(9, HIGH); 
    previousMillis = millis(); 
    delay(ritardo);  
    digitalWrite(8, HIGH);
    previousMillis = millis();  
    delay(ritardo);     
    digitalWrite(7, HIGH);  
    previousMillis = millis();   
    delay(ritardo);      
    digitalWrite(6, HIGH);  
    previousMillis = millis();  
    delay(ritardo);         
    digitalWrite(5, HIGH); 
    previousMillis = millis(); 
    delay(ritardo);  
    digitalWrite(4, HIGH);  
    previousMillis = millis(); 
    delay(ritardo);   
    digitalWrite(3, HIGH);
    previousMillis = millis(); 
    delay(ritardo); 
    digitalWrite(2, HIGH); 
    previousMillis = millis(); 

} else {
   if (millis() - previousMillis > interval) {
    digitalWrite(11, LOW);              //intervallo di tempo passato, spegni il led
    delay(ritardo);                     //attendi prima di spegnere il led successivo
    digitalWrite(10, LOW);            
    delay(ritardo);                    
    digitalWrite(9, LOW);              
    delay(ritardo);                   
    digitalWrite(8, LOW);              
    delay(ritardo);                   
    digitalWrite(7, LOW);               
    delay(ritardo);                    
    digitalWrite(6, LOW);             
    delay(ritardo);                    
    digitalWrite(5, LOW);             
    delay(ritardo);                  
    digitalWrite(4, LOW);             
    delay(ritardo);                    
    digitalWrite(3, LOW);               
    delay(ritardo);                    
    digitalWrite(2, LOW);               
    }
    }
    delay(ritardo);                     //aspetta
  }
}

Grazie.

Visto al volo dal telefono mi pare che le graffe non tornino... È corretto che il secondo sensore sia dentro l'else del primo?

Perchè salvi il valore di millis continuamente se a te serve solo l'ultimo?
Poi un consiglio: per renderlo più intuitivo compatta le sequenze ogni una in un ciclo for almeno diventa più leggibile tutto il codice.

Inoltre serve di identificare ulteriori comportamenti:

Se durante la sequenza dovuta al primo sensore intervenisse il secondo?
Oppure nuovamente il primo?
Inoltre se una persona entra nel corridoio il primo sensore la sente

Quando arrivato in fondo esce la sente il secondo sensore, chiaramente non deve di accendere a rovescio la luci, ma...
Cosa bisogna fare?

Potresti fare così:

Dichiara la variabile attivo:
byte attivo=0;
normalmente a valore 0; il sensore 1 la pone a 1, il sensore 2 la pone a 2.
Dichiara anche la variabile t_start:
unsigned long t_start;
Nel momento in cui attivo diventa diversa da zero (solo nel momento in cui cambia stato, quindi) prendi millis():
t_start=millis();

Poi, con la variabile byte contatore, conti i LED da accendere: se attivo==1, inizi con contatore=1 e incrementi; se, invece, attivo==2, inizi con contatore=10 e decrementi fino a raggiungere 10 o 0. Con byte PASSO=999 o 1499 (1 secondo o 1,5s o altro, scegli tu…), ogni volta che millis()-t_start>PASSO incrementi o decrementi e attivi il LED corrispondente:
digitalWrite (contatore, HIGH);

Poi verifichi se è trascorso il tempo previsto e, quando è trascorso, inizi a fare l’inverso e, alla fine, poni attivo=0.
In questo modo hai un programma che scorre continuamente, lasciando anche libero il microcontrollore per fare altre cose, e molto più compatto.

Per i pinMode inziali puoi semplificare scrivendo:
for (byte n=2; n<12; n++) {pinMode (n, OUTPUT);}

Anche il tuo codice diventerebbe molto più semplice, seppure ancora bloccante, se impostato così (l’ho modificato direttamente da qui, perciò posso aver sbagliato l’indentazione… :frowning: ):

byte StatoSensore = 0;
unsigned long previousMillis = 0;
unsigned long interval = 3000;          //timer
byte ritardo = 50;                      //attesa.

void setup()
{
  for (byte n=2; n<12; n++) {pinMode (n, OUTPUT);} // Uscite

  pinMode(12, INPUT);                   //ingresso sensore 1
  pinMode(13, INPUT);                   //ingresso sensore 2
}

void loop()
{
  StatoSensore = digitalRead(12); // leggo i dati del sensore 1
   if (StatoSensore == HIGH)  // sensore attivo
  {
    for (byte n=2; n<12; n++) {digitalWrite (n, HIGH); previousMillis=millis(); delay (ritardo);}
  }
  else
  {
   if (millis()-previousMillis>interval)
    {
      for (byte n=2; n<12; n++) {digitalWrite (n, LOW); previousMillis=millis(); delay(ritardo);}
    }
   delay(ritardo);  // aspetta

  StatoSensore=digitalRead(13);       // leggo i dati del sensore 2
   if (StatoSensore==HIGH)           // sensore attivo
    {
      for (byte n=11; n>1; n++) {digitalWrite (n, HIGH); previousMillis=millis(); delay (ritardo);}
    }
  } // END else
else
  {
   if (millis()-previousMillis>interval)
     {
      for (byte n=11; n>1; n++) {digitalWrite (n, LOW); previousMillis=millis(); delay (ritardo);}
     }
    delay(ritardo); // aspetta
  } // END else
} // END loop()

Però devi anche verificare che la persona abbia attraversato il secondo sensore per concludere il ciclo, altrimenti quando arriva alla fine del percorso fa partire le luci al contrario!

C’è da dire che il codice bloccante, in questo caso, è utile per evitare che accadano cose strane se, durante una sequenza, un’altra persona attraversa il sensore dal lato opposto.

fratt:
Visto al volo dal telefono mi pare che le graffe non tornino… È corretto che il secondo sensore sia dentro l’else del primo?

Grazie, l’avrò guardato e riguardato mille volte e non trovavo quale fosse il problema, ah! la competenza o c’è o non c’è.

nello79:
Perchè salvi il valore di millis continuamente se a te serve solo l’ultimo?
Poi un consiglio: per renderlo più intuitivo compatta le sequenze ogni una in un ciclo for almeno diventa più leggibile tutto il codice.

Grazie per la tua osservazione e ti rispondo perché non sapevo farlo diversamente.

Hai ragione, infatti ho specificato nel post che sono un umile apprendista e so perfettamente che si sarebbe potuto fare meglio, ma le mie competenze attuali si fermano qui per il momento.

Standardoil:
Inoltre serve di identificare ulteriori comportamenti:

Se durante la sequenza dovuta al primo sensore intervenisse il secondo?
Oppure nuovamente il primo?
Inoltre se una persona entra nel corridoio il primo sensore la sente

Quando arrivato in fondo esce la sente il secondo sensore, chiaramente non deve di accendere a rovescio la luci, ma…
Cosa bisogna fare?

Ti ringrazio per la tua risposta, e sono consapevole che bisognerebbe aggiungere alcune variabili come da te notato, ma al momento non sono in grado di fare meglio.
Comunque per quello di cui necessito non è fondamentale specificare troppe variabili, inoltre l’eventuale ulteriore attivazione del primo o del secondo sensore, non fa altro che prolungare il tempo in cui i led restano accesi.

Datman:
Anche il tuo codice diventerebbe molto più semplice, seppure ancora bloccante, se impostato così (l’ho modificato direttamente da qui, perciò posso aver sbagliato l’indentazione… :frowning: ):

byte StatoSensore = 0;

unsigned long previousMillis = 0;
unsigned long interval = 3000;          //timer
byte ritardo = 50;                      //attesa.

void setup()
{
 for (byte n=2; n<12; n++) {pinMode (n, OUTPUT);} // Uscite

pinMode(12, INPUT);                   //ingresso sensore 1
 pinMode(13, INPUT);                   //ingresso sensore 2
}

void loop()
{
 StatoSensore = digitalRead(12); // leggo i dati del sensore 1
  if (StatoSensore == HIGH)  // sensore attivo
 {
   for (byte n=2; n<12; n++) {digitalWrite (n, HIGH); previousMillis=millis(); delay (ritardo);}
 }
 else
 {
  if (millis()-previousMillis>interval)
   {
     for (byte n=2; n<12; n++) {digitalWrite (n, LOW); previousMillis=millis(); delay(ritardo);}
   }
  delay(ritardo);  // aspetta

StatoSensore=digitalRead(13);       // leggo i dati del sensore 2
  if (StatoSensore==HIGH)           // sensore attivo
   {
     for (byte n=11; n>1; n++) {digitalWrite (n, HIGH); previousMillis=millis(); delay (ritardo);}
   }
 } // END else
else
 {
  if (millis()-previousMillis>interval)
    {
     for (byte n=11; n>1; n++) {digitalWrite (n, LOW); previousMillis=millis(); delay (ritardo);}
    }
   delay(ritardo); // aspetta
 } // END else
} // END loop()



Però devi anche verificare che la persona abbia attraversato il secondo sensore per concludere il ciclo, altrimenti quando arriva alla fine del percorso fa partire le luci al contrario!

C'è da dire che il codice bloccante, in questo caso, è utile per evitare che accadano cose strane se, durante una sequenza, un'altra persona attraversa il sensore dal lato opposto.

Complimenti hai fatto veramente un ottimo lavoro, semplificando al massimo il pastrocchio che ho fatto io. ahahah
Non c’è niente di meglio di qualche buon esempio per capire ed imparare questi concetti.
Comunque ho fatto diverse prove con il tuo sketch ma ho riscontrato dei problemi, a parte una graffa di troppo prima del secondo “else”, la tua soluzione funziona solo con uno dei due sensori, appena attivo l’altro si blocca tutto e devo resettare arduino, ma non riesco a capire perché.
Grazie anche a te per il tuo tempo.

E' sbagliato il for decrescente, dove c'è ugualmente n++ anziché n--! :slight_smile:

Così è ancora con tutti i delay bloccanti, ma funziona come desideri?
Ore 19.40: ho fatto un paio di cambiamenti.

unsigned long ATTESA = 3000; // Attesa prima dello spegnimento progressivo
unsigned int PASSO = 1000;  // Tempo tra un LED e l'altro (in millisecondi)

void setup()
{
for (byte n=2; n<12; n++) {pinMode (n, OUTPUT);} // Uscite
pinMode(12, INPUT);                   //ingresso sensore 1
pinMode(13, INPUT);                   //ingresso sensore 2
}

void loop()
{
if (digitalRead(12)==HIGH) // Sensore 1 attivo
  {
  for (byte n=2; n<12; n++) {digitalWrite (n, HIGH); delay (PASSO);} // Accende in sequenza da 2 a 11.
  delay(ATTESA-PASSO); // Aspetta (PASSO sta già nel delay precedente).
  for (byte n=2; n<12; n++) {digitalWrite (n, LOW); delay (PASSO);} // Spegne in sequenza da 2 a 11.
  )
  
else if (digitalRead(13)==HIGH) // Sensore 2 attivo
  {
  for (byte n=11; n>1; n--) {digitalWrite (n, HIGH); delay(PASSO);} // Accende in sequenza da 11 a 2.
  delay(ATTESA-PASSO); // Aspetta (PASSO sta già nel delay precedente).
  for (byte n=11; n>1; n--) {digitalWrite (n, LOW); delay (PASSO);} // Spegne in sequenza da 11 a 2.
  }
} // END loop()

Attento, però: se entri dal sensore 1 ed esci dal sensore 2 dopo che si sono già spente tutte le luci, parte la sequenza opposta! Dopo ogni sequenza, dovresti ignorare il primo passaggio dal sensore opposto, perché è l’uscita della persona che ha attivato la sequenza.
Se vuoi essere rigoroso, devi mettere due sensori in fila per ogni lato e attivare la sequenza solo se viene attivato quello all’inizio o alla fine del corridoio e, entro 2 secondi, viene attivato l’altro, che vuol dire che una persona sta entrando nel corridoio.

Datman:
E’ sbagliato il for decrescente, dove c’è ugualmente n++ anziché n–! :slight_smile:

Ti giuro che mi ero ripromesso che sarebbe stata la prima modifica che avrei fatto quando mi ci sarei potuto cimentare di nuovo.

Datman:
Così è ancora con tutti i delay bloccanti, ma funziona come desideri?
Ore 19.40: ho fatto un paio di cambiamenti.

unsigned long ATTESA = 3000; // Attesa prima dello spegnimento progressivo

unsigned int PASSO = 1000;  // Tempo tra un LED e l’altro (in millisecondi)

void setup()
{
for (byte n=2; n<12; n++) {pinMode (n, OUTPUT);} // Uscite
pinMode(12, INPUT);                   //ingresso sensore 1
pinMode(13, INPUT);                   //ingresso sensore 2
}

void loop()
{
if (digitalRead(12)==HIGH) // Sensore 1 attivo
 {
 for (byte n=2; n<12; n++) {digitalWrite (n, HIGH); delay (PASSO);} // Accende in sequenza da 2 a 11.
 delay(ATTESA-PASSO); // Aspetta (PASSO sta già nel delay precedente).
 for (byte n=2; n<12; n++) {digitalWrite (n, LOW); delay (PASSO);} // Spegne in sequenza da 2 a 11.
 )
 
else if (digitalRead(13)==HIGH) // Sensore 2 attivo
 {
 for (byte n=11; n>1; n–) {digitalWrite (n, HIGH); delay(PASSO);} // Accende in sequenza da 11 a 2.
 delay(ATTESA-PASSO); // Aspetta (PASSO sta già nel delay precedente).
 for (byte n=11; n>1; n–) {digitalWrite (n, LOW); delay (PASSO);} // Spegne in sequenza da 11 a 2.
 }
} // END loop()



Attento, però: se entri dal sensore 1 ed esci dal sensore 2 dopo che si sono già spente tutte le luci, parte la sequenza opposta! Dopo ogni sequenza, dovresti ignorare il primo passaggio dal sensore opposto, perché è l'uscita della persona che ha attivato la sequenza.
Se vuoi essere rigoroso, devi mettere due sensori in fila per ogni lato e attivare la sequenza solo se viene attivato quello all'inizio o alla fine del corridoio e, entro 2 secondi, viene attivato l'altro, che vuol dire che una persona sta entrando nel corridoio.

Le tue ultime modifiche funzionano alla grande, c’era una tonda al posto di una graffa ma ora è perfetto, leggero e funzionale.
Ora me lo studio un po’ per capire meglio le tue modifiche.
Solo un’ultima delucidazione, in questo modo si sfrutta ancora la funzione “millis”, oppure è una funzione supplementare per gestire il tempo?
grazie a tutti per i vostri consigli.

chicco72:
... Solo un'ultima delucidazione, in questo modo si sfrutta ancora la funzione "millis", oppure è una funzione supplementare per gestire il tempo? ...

>Datman: vedi a che serve fornire la "pappa fatta"? ... a un bel nulla >:( ... tanto, come puoi ben constatare, fanno solo copia/incolla senza entrare nel merito ... ::slight_smile:

Guglielmo

Caro Guglielmo,
se io non avessi mangiato tanta pappa fatta da altri mi starei ancora chiedendo da che parte cominciare...

Datman:
Caro Guglielmo,
se io non avessi mangiato tanta pappa fatta da altri mi starei ancora chiedendo da che parte cominciare...

... ti ricordo che è contrario al punto 16.13 del REGOLAMENTO e, pertanto, in futuro ... non vorrei dover ricorre mezzi che non mi piacciono ... quindi, cortesemnete, regolati ... ::slight_smile:

Guglielmo

Torno nell’oblio.