Semplice lanciarazzi Lego

Carissimi, di rientro da una vacanza in Italia, a casa dei miei ho trovato diverso materiale elettronico che avevo accumulato ai tempi del primo lavoro.

Tra le tante cose, c’erano dei display a led numerici, allora io e mio figlio ci siam detti: perché non creare un conto alla rovescia che con il servo attivi qualcosa da lanciare? :grin:

Cosí abbiamo progettato questo semplice sistema che attiva un lanciatore di bastoncini della Lego :joy:

Qui di seguito il codice (ho scritto il post dal telefono e puó essere che non sia “indentato” bene, nel caso lo correggerò poi da casa sul pc per migliore lettura):

#include <Servo.h>
Servo myServo;
unsigned long prevMillis = 0; // variabile per il conteggio del tempo precedente
unsigned long currMillis = 0; // variabile per il conteggio del tempo attuale
const long segLed = 550; // durata di 0,55 sec del segmento led acceso
int pulsanteStato = 0; // variabile per verificare lo stato del pulsante
int angolo = 0; // variabile per impostare l'angolo di rotazione del servo
int ledPin = 0; // variabile per i pin del display
int notes[] = { 392 }; // nota sol
void setup() {
for (int ledPin = 3; ledPin <= 11; ledPin++) { // i led del display numerico e il piezo vanno dal pin 3 al 11
pinMode(ledPin, OUTPUT); // pin dei led e del piezo in output
digitalWrite(ledPin, LOW);// tutti led e piezo spenti
}
ledPin = 4; // imposto il primo segmento del display da accendersi (segmento C)
pinMode(2, INPUT); // imposto il pin 2 del pulsante in input
}
void loop() {
pinMode(12, OUTPUT);
digitalWrite(12, LOW); // comando del servo a zero
currMillis = millis();
pulsanteStato = digitalRead(2); // leggo lo stato del pulsante per verificare se e´ premuto
if (pulsanteStato == LOW) { // se non ho premuto il pulsante
if (currMillis - prevMillis >= segLed) { // controllo se son passati gli 0,55 sec dall'accensione del segmento led di prima
if (ledPin != 9) { // se non ho ancora acceso l'ultimo segmento del display
digitalWrite(ledPin, LOW); // spengo il segmento acceso in precedenza
ledPin++; // incremento la variabile dei pin del display per accendere il segmento successivo
digitalWrite(ledPin, HIGH); // accendo il segmento
} else { // quando ho acceso l'ultimo segmento collegato al pin Arduino 9
digitalWrite(ledPin, LOW);
ledPin = 4; // re-imposto la variabile dei led a 4, pin di Arduino collegato al primo segmento, e inizio nuovamente la
sequenza
digitalWrite(ledPin, HIGH);
}
prevMillis = currMillis;
}
}
if (pulsanteStato == HIGH) { // se ho premuto il pulsante
lanciapinnar(); // vado alla sequenza di lancio
}
}
/*
sequenza di attivazione servo con conto alla rovescia
*/
void lanciapinnar() {
for (int ledPin = 3; ledPin <= 10; ledPin++) { // tutti led e piezo spenti
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
}
digitalWrite(8, HIGH); // scrivo il numero 9, lampeggio DP e suono bip 1 volta
digitalWrite(9, HIGH);
digitalWrite(4, HIGH);
digitalWrite(7, HIGH);
digitalWrite(10, HIGH);
digitalWrite(5, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(900);
digitalWrite(6, HIGH); // scrivo il numero 8, lampeggio DP e suono bip 1 volta
digitalWrite(5, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(900);
digitalWrite(5, LOW); // scrivo il numero 7, lampeggio DP e suono bip 2 volte
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(10, LOW);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(400);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(400);
digitalWrite(8, HIGH); // scrivo il numero 6, lampeggio DP e suono bip 2 volte
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(400);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(400);
digitalWrite(8, HIGH); // scrivo il numero 5,, lampeggio DP e suono bip 3 volte
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
digitalWrite(7, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(8, LOW); // scrivo il numero 4, lampeggio DP e suono bip 3 volte
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(233);
digitalWrite(8, HIGH); // scrivo il numero 3, lampeggio DP e suono bip 4 volte
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(8, HIGH); // scrivo il numero 2, lampeggio DP e suono bip 4 volte
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, LOW);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(100);
digitalWrite(3, LOW);
noTone(11);
delay(150);
digitalWrite(8, LOW); // scrivo il numero 1, accendo DP e suono bip 1 secondo
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(3, HIGH);
tone(11, notes[1]);
delay(1000);
digitalWrite(3, LOW);
noTone(11);
for (int ledPin = 3; ledPin <= 10; ledPin++) { // spengo il display e il piezo
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
}
myServo.attach(12); // imposto il pin di comando del servo sul 12
angolo = 90; // imposto l'angolo di 90 gradi per il servo
myServo.write(angolo); // muovo il servo
delay (1000); // attendo 1 secondo
angolo = 0; // imposto l'angolo a 0 per il servo
myServo.write(angolo); // riposiziono il servo
delay(3000); // attendo 3 secondi
}

Il risultato è stato divertente :face_with_tongue:

Consigli per migliorare o semplificare il codice?

In attesa della correzione...

Questo un po' mi fa sentire in vacanza perenne :grin:

:+1: :rocket:

:scream:

E' ora di cominciare seriamente a parlare di array e lookup tables :wink:
E di autodocumentazione del codice :downcast_face_with_sweat:
E di macchine a stati :scream: :scream: :scream:
ati... ati... ati... eco che si perde tra le montagne....

Il programma, impostato in quel modo, è quasi una logica cablata! :slight_smile:
Sono tollerabili i delay di 100ms per il suono, ma le temporizzazioni di un secondo falle con millis()!

Per pilotare un display è molto comodo metterlo sulla porta D e poi pilotarla con PORT: in una sola riga controlli tutti i segmenti.

Comunque ci vuole poco a mettere gli spazi anche dal telefonino… Basta un po’ di buona volontà.

Eh, si. Apri il progetto nell'IDE (per sicurezza premi Ctrl-T per riformattarlo) quindi copia il codice usando l'opzione di copia per il forum che trovi nel menu Modifica (o premi Ctrl-shift-C). Quindi modifica il tuo post, cancella tutto il blocco col codice ed incollaci quello dell'IDE, che sarà già formattato ed incluso nei tag CODE. :grin:

Oppure si può usare formatter.org (facendo attenzione che con alcuni Coding Style le graffe vengono spaziate in modo non consueto), o ancora chiedere a un'IA di fare il lavoro sporco specificando anche ulteriori varianti, ad esempio: "formatta il seguente codice con una indentazione di 4 spazi, collocando anche le parentesi di inizio e fine struttura su una sola riga indipendente, e crea una chiara separazione visiva tra le diverse funzioni".

Hai ragione, ho copiato il codice ed incollato da un pdf, ma poi mi cadevano gli occhi e perdevo la connessione…e l’interfaccia non era delle migliori, provvederò a breve!

Vero, ho iniziato a digerire il millis per le funzioni dove il programma non si deve bloccare, come all’inizio, nella sequenza di lancio invece non doveva fare niente quindi ho preso la via semplice :grin: controindicazioni particolari nel farlo?

Riguardo la porta D e la funzione PORT, non so cosa siano ma grazie del suggerimento!

Cercherò informazioni e farò delle prove :wink:

:scream:

Devo familiarizzare con il linguaggio piano piano, senza che mi diventi odioso :grin: ma ci arriverò!

Ahahah!

Casa dolce casa, ma per me ora è doppia e l’Italia è la patria delle vacanze :winking_face_with_tongue:

Trovato l’argomento!

Non è una porta fisica, ma un comando che alloca digitalmente i pin da 0 ad 8 e li comanda con una linea di codice in binario.

Mi avrebbe infatti risparmiato tutta la serie di istruzioni digitalWrite(), ma bloccato la porta seriale che comunque in questo programma non uso.

Grazie del suggerimento, proverò il comando anche se dovrò ri-cablare il circuito per testarlo :wink:

Eh, tutto bello, bella la boiserie, bello l'armadio, belle le cassapanche, bello tutto (cit.), ma il codice del post #1 non l'hai ancora sistemato :wink:

Secondo me, anche se hai commentato parecchio, è difficile leggere il codice perchè hai scritto i numeri dei pin come costanti ovunque.
Molto più semplice da leggere se dichiari delle costanti con dei nomi che richiamano l'utilizzo del pin.
Esempio il pin del piezo mi pare il 11. Meglio (anche a costo di aumentare il codice di 2 righe):

const byte pinPiezo=11;
...
pinMode(pinPiezo,OUTPUT);
digitalWrite(pinPiezo, LOW)
for (int ledPin = 3; ledPin <= 10; ledPin++) 
...

Anche il pin del bottone. un bel const byte pinButton=2;
Anche const byte pinDP=3; nel codice usi pinDP e si capisce meglio dove lo "lampeggi"

Le funzioni posso ricevere un parametro. Per iniziare potresti avere una funzione DisplayNum() a cui passi 0-9 e -1 per spegnere. Per ora non ottimizzato:

void DisplayNum(p_Num)
{ switch(p_Num)
  { case -1:      // spengo tutti i segmenti, anche DP
      digitalWrite(pinDP, LOW);     
      for (int i = 4; i <= 10; i++) digitalWrite(ledPin, LOW);
      break;
    case 0:  
      ...
      break;
    case 1:
      digitalWrite(8, LOW); // scrivo il numero 1
      digitalWrite(9, HIGH);
      digitalWrite(10, LOW);
      digitalWrite(4, HIGH);
      digitalWrite(5, LOW);
      digitalWrite(6, LOW);
      digitalWrite(7, LOW);
      break;
etc.
}

Nel programma scriverai:

delay(900);
DisplayNum(7);
digitalWrite(pinDP, HIGH);
tone(pinPiezo, notes[1]);

invece di:

delay(900);
digitalWrite(5, LOW); // scrivo il numero 7, lampeggio DP e suono bip 2 volte
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(10, LOW);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
tone(11, notes[1]);

Son d’accordo e nei programmi precedenti l’avevo fatto.

Poi mi pare qualcuno avesse suggerito che era un’allocazione non necessaria, se non per chiarimenti della lettura del codice da altri, e così in questo caso ho seguito la via semplice.

Ma di base anch’io preferisco dichiarare costanti dedicate così da leggere meglio il codice in futuro.

Ad esempio, un altro programma semplice che abbiamo fatto (tutta l’idea del gioco e come doveva funzionare era di mio figlio, che ha anche costruito il circuito, io ho scritto solo il codice :smiling_face_with_sunglasses: ) e´ questo “gioco delle campane” digitale.

Qui avevo dichiarato meglio le costanti dei pin a seconda della loro funzione:

/*
  GIOCO DELLE CAMPANE DIGITALE
*/

const int P1 = 8; // imposto i piedini dei pulsanti
const int P2 = 9;
const int P3 = 10;
const int P4 = 11;
const int P5 = 12;
const int piezo = 3; // piedino del piezo
const int ledBianco = 4; // imposto i piedini dei led
const int ledVerde = 5;
const int ledRosso = 6;
const int ledBlu = 2;
int P1stato = 0; // variabili per lo stato dei pulsanti
int P2stato = 0;
int P3stato = 0;
int P4stato = 0;
int P5stato = 0;
int dado = 0; // variabile per il sorteggio della pallina
int notes[] = { 262, 440, 330 }; // note do, la, mi
int ledPin = 0;
int pulsantePin = 0;

void setup() {
  for (int ledPin = 2; ledPin <= 5; ledPin++) { 
    pinMode(ledPin, OUTPUT); // pin dei led e del piezo in output
    digitalWrite(ledPin, LOW);// tutti led e piezo spenti
  }
  for (int pulsantePin = 8; pulsantePin <= 12; pulsantePin++) { 
    pinMode(pulsantePin, INPUT); // pin dei pulsanti in input
  }
}

void loop() { // all'inizio attendo che venga premuto il pulsante P5 prima di iniziare il gioco
  P5stato = digitalRead(P5);
  if (P5stato == 1) { // quando premo P5, lampeggio il led bianco e vado alla routine del sorteggio
    digitalWrite(ledBianco, HIGH);
    delay(500);
    digitalWrite(ledBianco, LOW);
    lanciaDado();
  }
}

void lanciaDado() { // routine per il sorteggio di dove sta la pallina sotto la campana
  dado = random(4); // lancio il sorteggio randomico
    switch(dado){
      case 0: // risultato sorteggio 1
      P5stato = 0;
      controllaPulsanti1(); // vado alla routine dove il vincitore e´ 1
      break;

      case 1: // risultato sorteggio 2
      P5stato = 0;
      controllaPulsanti2(); // vado alla routine dove il vincitore e´ 2
      break;

      case 2: // risultato sorteggio 3
      P5stato = 0;     
      controllaPulsanti3(); // vado alla routine dove il vincitore e´ 3
      break;

      case 3: // risultato sorteggio 4
      P5stato = 0;      
      controllaPulsanti4(); // vado alla routine dove il vincitore e´ 4
      break;
    }
  }

void controllaPulsanti1() { // routine per verificare se premo il P1 quando e´ stato sorteggiato l'1
  while (P1stato == 0 || P2stato == 0 || P3stato == 0 || P4stato == 0) { // se nessuno dei pulsanti e´ stato promuto, continuo in loop a controllarli
    P1stato = digitalRead(P1);
    P2stato = digitalRead(P2);
    P3stato = digitalRead(P3);
    P4stato = digitalRead(P4);
    if (P1stato == 1) { // se ho premuto il pulsante 1 corretto
      digitalWrite(ledVerde, HIGH); // accendo il led verde
      tone(piezo, notes[2]); // suono le due note della vittoria
      delay(400);
      tone(piezo, notes[1]);
      delay(1000);
      noTone(piezo);
      digitalWrite(ledVerde, LOW);
      digitalWrite(ledBianco, HIGH); // lampeggio due volte il led bianco per segnalare che ha inizio un nuovo sorteggio
      delay(500);
      digitalWrite(ledBianco, LOW);
      delay(500);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      P1stato = 0;
      lanciaDado(); // ritorno alla routine del sorteggio di un nuovo numero
    } else if (P2stato == 1 || P3stato == 1 || P4stato == 1) { // altrimenti se premo un tasto sbagliato (diverso da 1)
      digitalWrite(ledRosso, HIGH); // accendo il led rosso
      tone(piezo, notes[0]); // suono la nota della sconfitta
      delay(1500);
      noTone(piezo);
      digitalWrite(ledRosso, LOW);
      P2stato = 0; // azzero tutti i registri dei pulsanti e ritorno all'inizio di questa routine finche´ non indovino
      P3stato = 0;
      P4stato = 0;
    }
  }
}

/*
  di seguito le routine per verificare il sorteggio degli altri numeri
*/

void controllaPulsanti2() {
  while (P1stato == 0 || P2stato == 0 || P3stato == 0 || P4stato == 0) {
    P1stato = digitalRead(P1);
    P2stato = digitalRead(P2);
    P3stato = digitalRead(P3);
    P4stato = digitalRead(P4);
    if (P2stato == 1) {
      digitalWrite(ledVerde, HIGH);
      tone(piezo, notes[2]);
      delay(400);
      tone(piezo, notes[1]);
      delay(1000);
      noTone(piezo);
      digitalWrite(ledVerde, LOW);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      delay(500);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      P2stato = 0;
      lanciaDado();
    } else if (P1stato == 1 || P3stato == 1 || P4stato == 1) {
      digitalWrite(ledRosso, HIGH);
      tone(piezo, notes[0]);
      delay(1500);
      noTone(piezo);
      digitalWrite(ledRosso, LOW);
      P1stato = 0;
      P3stato = 0;
      P4stato = 0;
    }
  }
}

void controllaPulsanti3() {
  while (P1stato == 0 || P2stato == 0 || P3stato == 0 || P4stato == 0) {
    P1stato = digitalRead(P1);
    P2stato = digitalRead(P2);
    P3stato = digitalRead(P3);
    P4stato = digitalRead(P4);
    if (P3stato == 1) {
      digitalWrite(ledVerde, HIGH);
      tone(piezo, notes[2]);
      delay(400);
      tone(piezo, notes[1]);
      delay(1000);
      noTone(piezo);
      digitalWrite(ledVerde, LOW);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      delay(500);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      P3stato = 0;
      lanciaDado();
    } else if (P1stato == 1 || P2stato == 1 || P4stato == 1) {
      digitalWrite(ledRosso, HIGH);
      tone(piezo, notes[0]);
      delay(1500);
      noTone(piezo);
      digitalWrite(ledRosso, LOW);
      P1stato = 0;
      P2stato = 0;
      P4stato = 0;
    }
  }
}

void controllaPulsanti4() {
  while (P1stato == 0 || P2stato == 0 || P3stato == 0 || P4stato == 0) {
    P1stato = digitalRead(P1);
    P2stato = digitalRead(P2);
    P3stato = digitalRead(P3);
    P4stato = digitalRead(P4);
    if (P4stato == 1) {
      digitalWrite(ledVerde, HIGH);
      tone(piezo, notes[2]);
      delay(400);
      tone(piezo, notes[1]);
      delay(1000);
      noTone(piezo);
      digitalWrite(ledVerde, LOW);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      delay(500);
      digitalWrite(ledBianco, HIGH);
      delay(500);
      digitalWrite(ledBianco, LOW);
      P4stato = 0;
      lanciaDado();
    } else if (P1stato == 1 || P2stato == 1 || P3stato == 1) {
      digitalWrite(ledRosso, HIGH);
      tone(piezo, notes[0]);
      delay(1500);
      noTone(piezo);
      digitalWrite(ledRosso, LOW);
      P1stato = 0;
      P2stato = 0;
      P3stato = 0;
    }
  }
}

Le funzioni posso ricevere un parametro. Per iniziare potresti avere una funzione DisplayNum() a cui passi 0-9 e -1 per spegnere. Per ora non ottimizzato:

Interessante, grazie!

ecco il codice indentato meglio:

#include <Servo.h>
Servo myServo;

unsigned long prevMillis = 0; // variabile per il conteggio del tempo precedente
unsigned long currMillis = 0; // variabile per il conteggio del tempo attuale
const long segLed = 550; // durata di 0,55 sec del segmento led acceso
int pulsanteStato = 0; // variabile per verificare lo stato del pulsante
int angolo = 0; // variabile per impostare l'angolo di rotazione del servo
int ledPin = 0; // variabile per i pin del display
int notes[] = { 392 }; // nota sol


void setup() {
  for (int ledPin = 3; ledPin <= 11; ledPin++) { // i led del display numerico e il piezo vanno dal pin 3 al 11
    pinMode(ledPin, OUTPUT); // pin dei led e del piezo in output
    digitalWrite(ledPin, LOW);// tutti led e piezo spenti 
  }
  ledPin = 4; // imposto il primo segmento del display da accendersi (segmento C)
  pinMode(2, INPUT); // imposto il pin 2 del pulsante in input
}

void loop() {
  pinMode(12, OUTPUT);
  digitalWrite(12, LOW); // comando del servo a zero
  currMillis = millis();
  pulsanteStato = digitalRead(2); // leggo lo stato del pulsante per verificare se e´ premuto
  if (pulsanteStato == LOW) { // se non ho premuto il pulsante
    if (currMillis - prevMillis >= segLed) { // controllo se son passati gli 0,55 sec dall'accensione del segmento led di prima
      if (ledPin != 9) { // se non ho ancora acceso l'ultimo segmento del display
        digitalWrite(ledPin, LOW); // spengo il segmento acceso in precedenza
        ledPin++; // incremento la variabile dei pin del display per accendere il segmento successivo
        digitalWrite(ledPin, HIGH); // accendo il segmento
      } else { // quando ho acceso l'ultimo segmento collegato al pin Arduino 9
        digitalWrite(ledPin, LOW);
        ledPin = 4; // re-imposto la variabile dei led a 4, pin di Arduino collegato al primo segmento, e inizio nuovamente la sequenza
        digitalWrite(ledPin, HIGH);
      }
      prevMillis = currMillis;
    } 
  }
  if (pulsanteStato == HIGH) { // se ho premuto il pulsante
    lanciapinnar(); // vado alla sequenza di lancio
  }
}

/*
sequenza di attivazione servo con conto alla rovescia
*/

void lanciapinnar() {
  for (int ledPin = 3; ledPin <= 10; ledPin++) { // tutti led e piezo spenti
    pinMode(ledPin, OUTPUT); 
    digitalWrite(ledPin, LOW); 
  }

  digitalWrite(8, HIGH); // scrivo il numero 9, lampeggio DP e suono bip 1 volta
  digitalWrite(9, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(900);

  digitalWrite(6, HIGH); // scrivo il numero 8, lampeggio DP e suono bip 1 volta
  digitalWrite(5, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(900);

  digitalWrite(5, LOW); // scrivo il numero 7, lampeggio DP e suono bip 2 volte
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(10, LOW);
  digitalWrite(8, HIGH); 
  digitalWrite(9, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(400);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(400);

  digitalWrite(8, HIGH); // scrivo il numero 6, lampeggio DP e suono bip 2 volte
  digitalWrite(9, LOW);
  digitalWrite(10, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(400);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(400);

  digitalWrite(8, HIGH); // scrivo il numero 5,, lampeggio DP e suono bip 3 volte
  digitalWrite(9, LOW);
  digitalWrite(10, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);

  digitalWrite(8, LOW); // scrivo il numero 4, lampeggio DP e suono bip 3 volte
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(233);

  digitalWrite(8, HIGH); // scrivo il numero 3, lampeggio DP e suono bip 4 volte
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);

  digitalWrite(8, HIGH); // scrivo il numero 2, lampeggio DP e suono bip 4 volte
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(100);
  digitalWrite(3, LOW);
  noTone(11);
  delay(150);

  digitalWrite(8, LOW); // scrivo il numero 1, accendo DP e suono bip 1 secondo
  digitalWrite(9, HIGH);
  digitalWrite(10, LOW);
  digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(3, HIGH);
  tone(11, notes[1]);
  delay(1000);
  digitalWrite(3, LOW);
  noTone(11);

  for (int ledPin = 3; ledPin <= 10; ledPin++) { // spengo il display e il piezo
    pinMode(ledPin, OUTPUT); 
    digitalWrite(ledPin, LOW);
    }

  myServo.attach(12); // imposto il pin di comando del servo sul 12
  angolo = 90; // imposto l'angolo di 90 gradi per il servo
  myServo.write(angolo); // muovo il servo
  delay (1000); // attendo 1 secondo
  angolo = 0; // imposto l'angolo a 0 per il servo
  myServo.write(angolo); // riposiziono il servo
  delay(3000); // attendo 3 secondi
}

Inizierei con il dare nomi espliciti ai pin tramite apposite costanti, perché pur guardando ho capito solo che il 3 è il punto (in questo senso il codice non è autodocumentante, immagina di rileggerlo tra un anno senza il circuito sotto mano).

Diamo per scontato che i segmenti hanno questa disposizione?

//      A
//     ---
//  F |   | B
//     -G-
//  E |   | C
//     --- .DP
//      D

Compiliamo allora una serie di costanti iniziali per usare i nomi dei segmenti nel programma al posto dei numeri dei pin:

const uint8_t A_PIN  = 
const uint8_t B_PIN  = 
const uint8_t C_PIN  = 
const uint8_t D_PIN  = 
const uint8_t E_PIN  = 
const uint8_t F_PIN  = 
const uint8_t G_PIN  = 
const uint8_t DP_PIN = 3;

Poi possiamo creare un array di pin utile per scorrere i segmenti con un indice da 0 a 7.
Nota: in questo modo non c'è neppure più bisogno che i pin a cui sono collegati i segmenti siano in sequenza numerica:

const uint8_t SEG_PIN_ARRAY[] = { 
    A_PIN, B_PIN, C_PIN, D_PIN,
    E_PIN, F_PIN, G_PIN, DP_PIN
};

A questo punto le seguenti istruzioni sono equivalenti:

digitalWrite(3, HIGH);
digitalWrite(DP_PIN, HIGH);
digitalWrite(SEG_PIN_ARRAY[7], HIGH);

La prima non la usiamo più, perché lo scopo è non vedere più numeri di pin in giro per il programma (si parametrizza tutto con nomi costanti all'inizio).
La seconda è utile per agire sul singolo segmento.
La terza per scorrere i segmenti in automatico con un ciclo, ad esempio per spegnere tutto:

for (uint8_t i=0; i<=7; i++)
    digitalWrite(SEG_PIN_ARRAY[i], LOW);

Non serve ogni volta specificare il pinMode. Se non ci sono motivi tecnici per volerlo fare, basta una sola volta nel setup e i pin mantengono la "direzione" per tutto il tempo.


Nota: uint8_t indica semplicemente un byte, un intero a 8 bit senza segno (U)nsigned.

Grazie!

Mi ci andrá un attimo per “digerire” tutti i tuoi suggerimenti, sono ancora fermo a livello amatoriale basico e mi manca la conoscenza generale del “portafoglio” istruzioni e dei vari strumenti di programmazione (array, look up table, etc. ):grin: ci vanno anni di studi ed esperienza sul campo per diventare dei pro (cosa a cui non aspiro, mi interessa migliorare, ma sempre a livello amatoriale).

Mi stupisco sempre quando parlo coi colleghi del SW Engineering di come per loro sia tutto chiaro e semplice :joy:

Nel mentre ti ringrazio per il tempo e i consigli, torneranno sicuramente utili👍🏼

Comandando direttamente la porta, invece:

void setup()
{
DDRD = 0xFF; // DDRx imposta la direzione dei pin della porta x.
//              FF in esadecimale equivale al binario 11111111,
//              cioè tutti i pin impostati come uscite.
// ...
}

void disp_1()
{
//        abcdefgp      
PORTD = 0b01100000;
}

void disp_2()
{
//        abcdefgp
PORTD = 0b11011010;
}

// ...

void disp_spento()
{
PORTD = 0b00000000; // o, più brevemente, 0x00, tanto 
//                     si capisce che è tutto a zero.

yes avevo letto poi l’uso di PORTD, piu´ semplice e rapido infatti, grazie!

Ma se volessi installare piu´ display numerici, l’unico modo che mi viene in mente sarebbe inserire degli integrati che gestiscono piu´ linee o creare un bus che comandi diversi integrati come porte logiche collegate ai vari display.

Oppure esistono soluzioni piu´ intelligenti per controllarli direttamente con Arduino (che pero´ e´ limitato a 14 linee output)?

Puoi multiplexarli, con un pin per ciascun catodo (o anodo) comune e un transistor, oppure puoi usare un registro a scorrimento (shift register) o un driver apposito come il MAX7219, che regola anche la corrente nei segmenti.

Multiplexare direttamente da Arduino:

Usare un registro a scorrimento:

Usare driver per LED con moduli già pronti:

Con il TM1637:
https://www.aliexpress.com/p/tesla-landing/index.html?&productId=1005007787036377

Con il bellissimo MAX7219:

https://www.amazon.com/MAX7219-8-Digit-Digital-Display-Raspberry/dp/B0DYD7JM9S

https://www.google.com/search?q=arduino+7+digit+max7219+LED+display+module