Esercizio 'Starte Kit' - Progetto 8: Clessidra digitale

Buonasera a tutti,
ho eseguito l'esercizio 'clessidra digitale' (Libro dei Progetti - Progetto 8; da pagina 86 a 93) come indicato e, una volta ultimato l'esercizio, mi sono divertito ad aggiungere un piezo che mi avvertisse con un suono lo scadere del tempo. Ho inserito il piezo nel circuito ed una riga di codice: ho inserito la riga di codice proprio dove il libro lasciava solamente un if (led == 7){ //inserirecodice } specificando di lasciare l'istruzione 'if' vuota per decidere in seguito. Ho deciso che i sei led si devono accendere uno alla volta a distanza di un minuto dall'altro e ho notato che allo scoccare del quinto minuto, il piezo suonava in anticipo invece che suonare al sesto minuto. Ho risolto modificando la riga di codice proposta if (led == 7){ //codicedainserire } con la riga if (led == 8){ //codice da inserire }. Quindi la mia domanda è: sono io che sbagliavo a scrivere qualcosa nel codice oppure c'è stato un errore di trascrizione sul libro?
Inoltro il codice che ho scritto e la foto del circuito.

const int switchPin = 8; 
unsigned long previousTime = 0; 
int switchState = 0;
int prevSwitchState = 0; 
int led = 2; 

long interval = 60000; 

void setup() {
  // put your setup code here, to run once:
  for(int x = 2;x<8;x++){
    pinMode(x, OUTPUT);
  }
  pinMode(switchPin, INPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long currentTime = millis();

  if(currentTime - previousTime > interval){
    previousTime = currentTime;
    digitalWrite(led, HIGH);
    led++;

    if (led == 8){
      tone(12,1000,2000);
      
    }
  }
  switchState = digitalRead(switchPin);

  if(switchState != prevSwitchState){
    for(int x = 2;x<8;x++){
      digitalWrite(x, LOW);
    }
    led = 2;
    previousTime = currentTime;
  }

  prevSwitchState = switchState;


}

Questa è la scansione fatta dal libro: CLESSIDRADIGITALE_20250301_0001.pdf (733,4 KB)

Si c'è un errore nel pdf che hai allegato.
C'è altro che non mi torna.
La seguente condizione:

if(currentTime - previousTime > interval)

Risulta vera ogni minuto, dopo 6 minuti tutti i led sono accesi, ma dal settimo minuto in poi la variabile led cresce, sarà 8, poi 9, 10 ecc e con il tempo assumerà valori negativi poiché led è dichiarata int, fino al momento in cui giri la clessidra.

Comunque è possibile che nel libro questo venga spiegato in seguito.

Tornando all'errore, prova anche così:

if(currentTime - previousTime > interval){
    previousTime = currentTime;
    digitalWrite(led, HIGH);
    // ora appena led è uguale a 7 suona
    if (led == 7) {
      tone(12,1000,2000);
    }
    led++; // valeva 7, dopo questa led assume il valore 7 + 1.

  }

Ciao.

Oppure si parte con led impostata a 1 e si aggiorna prima della write:

const int switchPin = 8; 
unsigned long previousTime = 0; 
int switchState = 0;
int prevSwitchState = 0; 
int led = 1;   // <----------- parte da 1

long interval = 60000; 

void setup() {
  for(int x=2; x<8; x++){
    pinMode(x, OUTPUT);
  }
  pinMode(switchPin, INPUT);

}

void loop() {
  unsigned long currentTime = millis();

  if(currentTime-previousTime > interval){
    previousTime = currentTime;
    led++;  // <---------- spostato prima
    digitalWrite(led, HIGH);
    if(led == 7){
      tone(12, 1000, 2000);
    }
  }

  switchState = digitalRead(switchPin);
  if(switchState != prevSwitchState){
    for(int x=2; x<8; x++){
      digitalWrite(x, LOW);
    }
    led = 1;  // <---------- reimpostato a 1
    previousTime = currentTime;
  }
  prevSwitchState = switchState;
}

Meglio ancora disabilitare completamente la gestione dei tempi una volta che si è raggiunto il tempo massimo:

  if(led < 7){
    if(currentTime-previousTime > interval){
      previousTime = currentTime;
      led++;  // <---------- spostato prima
      digitalWrite(led, HIGH);
      if(led == 7){
        tone(12, 1000, 2000);
      }
    }
  }

ciao a tutti, ho avuto anch'io lo stesso problema di marco-tornani e risolto cambiamo il valore da 7 a 8 il valore da verificare nella variabile "led" con la condizione "if (led == 8)"

Quello che pero´ ancora non mi torna e´ che, se non sbaglio, nel codice di questo progetto la variabile "led" identifica il pin digitale su cui e´ collegato il led da accendere.
Quindi quando si accende il led numero 5 collegato al piedino 6, la variante led dovrebbe contenere appunto il numero 6: allora perche´ attiva gia´ la condizione if e fa suonare il piezo se scriviamo "if (led == 7)" come da libro?? :tired_face:

premetto che sono al mio terzo giorno di smanettamento con Arduino e programmazione C :wink: quindi non sono un esperto, ma sta cosa mi fa scervellare e se poteste spiegarmi il perche´ ve ne sarei grato

Così ti risulta più chiaro?

Ciao.

giusto grazie!
In effetti non avevo notato che "led++" la eseguiva subito dopo aver acceso il led e prima di iniziare un nuovo conteggio :woozy_face: per cui ovviamente quando accende il penultimo led sul pin 6, incrementa la variabile a 7 e con quel valore di riferimento nella condizione "if (led == 7) " fa subito suonare il piezo prima di finire il conteggio dell'ultimo led...

Ho anche provato a far "bippare" il piezo per 5 secondi mentre il programma continua, cercando in rete un ciclo con "millis", ma non funziona, suona solo due volte come se ripetesse un solo ciclo della routine.

qui di seguito il codice:

digita o incolla il codice qui

const int switchPin = 8;
unsigned long previousTime = 0;  // store the last time an LED was updated
unsigned long previousMillis = 0;
const long buzzInterval = 5000; // buzzer suona 5 secondi
int switchState = 0;             // the current switch state
int prevSwitchState = 0;         // the previous switch state
int led = 2;                     // a variable to refer to the LEDs
int notes [] = {330};            // variable for the single tone note
long interval = 20000;  // interval at which to light the next LED
void setup() {
  // set the LED pins as outputs
  for (int x = 2; x < 8; x++) {
    pinMode(x, OUTPUT);
  }
  // set the tilt switch pin as input
  pinMode(switchPin, INPUT);
}
void loop() {
  // store the time since the Arduino started running in a variable
  unsigned long currentTime = millis();
  unsigned long currentMillis = millis();

  if (currentTime - previousTime > interval) {
    previousTime = currentTime;
    digitalWrite(led, HIGH);
    led++;

    if (led == 8 ) {
      if (currentMillis - previousMillis >= buzzInterval) {
        previousMillis = currentMillis;
        tone(12, notes[0]);
        delay(100);
        noTone(12);
        delay(60);
        tone(12, notes[0]);
        delay(100);
        noTone(12);
        delay(740);
      }
      else {
        noTone(12);
      }
      }
    }

  // read the switch value
  switchState = digitalRead(switchPin);

  // if the switch has changed
  if (switchState != prevSwitchState) {
    // turn all the LEDs low
    for (int x = 2; x < 8; x++) {
      digitalWrite(x, LOW);
    }

    // reset the LED variable to the first one
    led = 2;

    //reset the timer
    previousTime = currentTime;
  }
  // set the previous switch state to the current state
  prevSwitchState = switchState;
}

diciamo che non ho ancora speso troppo tempo ad analizzare la funzione millis ed i relativi richiami/formule, magari ci arrivo poi da solo :sweat_smile: ma se avete tempo di correggermi prima, vi ringrazio!

Senza usare millis() il massimo che puoi fare è di inserire un ciclo for più o meno così:

    if (led == 8 ) {
      for (uint8_t i = 0; i < 255; i++) {
          tone(12, notes[0]);
          delay(100);
          noTone(12);
          delay(60);
      } // end for
    } else {
        noTone(12);
    }
       

Il conteggio fino a 255 è messo a caso al valore massimo che può essere contenuto in una variabile di tipo uint8_t che è grande 1 byte.

Però ti consiglio di leggere bene e comprendere il post al link:

Ciao.

Questo purtroppo è un problema comune a tutti i tutorial per principianti: per essere chiari e non sovraccaricare di concetti, finiscono con il dare un "imprinting" procedurale sbagliato sulla programmazione di microcontroller, e non sono affatto propedeutici a comprendere come scrivere programmi che "fanno qualcosa mentre il resto del programma continua". Questo arriva di consueto più tardi come un muro preso in faccia, chiamato programmazione a stati finiti, dove i beginners (ancora alle prese con difficoltà sulla sintassi e semantica delle istruzioni) svengono :downcast_face_with_sweat:

Suona solo due volte perché quel frammento di codice è posto all'interno di due condizioni che si verificano solo in un preciso momento. Al successivo ciclo di esecuzione (della funzione loop) le condizioni non sono più vere.

Come si risolverebbe?

  • Spostando quel codice fuori dalle condizioni che ne determinano l'attivazione.
  • Usando come segnale di attivazione una variabile flag (bandierina) opportunamente settata quando le condizioni sono vere.
  • Variabile flag che viene poi resettata quando il codice bip bip è stato eseguito il numero di volte desiderato.
  • E che deve essere opportunamente inizializzata all'avvio (o riavvio) del programma in modo da non partire subito con bip-bip attivi.
  • E quindi servirà anche una variabile per contare i bip.
  • E anche questa sarà da (re)inizializzare all'avvio o riavvio.

Questo è il tipo di difficoltà concettuale sui processi da gestire, che un tutorial per principianti non affronta.

Grazie a tutti per le risposte.

In effetti io ero abituato alla programmazione del PIC16C84 ad inizio anni 2000: le istruzioni in assembler a linguaggio macchina erano molto basiche, ma capivi esattamente che succedeva.
Ovviamente per programmazioni più complesse non eran l’ideale, ma all’epoca la mente era anche più fresca :sweat_smile:
Infatti qui il primo muro su cui mi son scontrato è che non esistono funzioni di “loop” da richiamare nel programma, ma ho inteso che bisogna usare “while” o “for” o altro che concettualmente mi sembra più complesso :thinking: ma forse è solo questione di abituarsi al metodo.

In ogni caso con calma arriveró a comprendere meglio, anche grazie al vostro aiuto.
Ciao!