Progetto prova riflessi

Buongiorno a tutti, vorrei creare un progetto dove quattro led si accendono casualmente e devono essere spenti passando la mano sopra un sensore pir. Lo scopo di questo progetto e' testare i riflessi quindi si dovrebbero accendere i led casualmente vicino al led c'e' il sensore , magari anche aggiungendo un lcd dove ci dice la velocita' per ogni "spegnimento".
Ho visto un progetto che potrebbe fare al mio caso con le opportune modifiche "https://www.labdomotic.com/2017/03/08/youtube-gioco-prova-riflessi-fai-da-te/"

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

// ATTENZIONEEEEEEEEEEEEEEEEEE  se avete problemi nel visualizzare i caratteri SUL DISPLAY 
// al posto di "" LiquidCrystal_I2C lcd(0x3F, 16, 2); "" scrivete  ""LiquidCrystal_I2C lcd(0x3F, 16, 2);


// COSTANTI MODIFICABILI PER PARAMETRI GIOCO

int PUNTEGGIOstep = 150; // Assegna il punteggio per pressione corretta/errata
int TEMPOpenalita = 1000; // Assegna il tempo in secondi per la penalità pressione errata
int TEMPOrilancio = 100; // Assegna il tempo di rilancio a pressione corretta
int TIMERgiocoCOUNTdown = 50; // Assegna il tempo per il contatore COUNTDOWN durante il gioco (Minore valore, velocità maggiore)
int PunteggioRecord = 1500; // Imposta il punteggio record iniziale
int velocitaBarra = 10; //  Inserire la velocità del tempo


const int pin_PULSANTE_START = 10;
int RANDOM = 0;
int FLAGgioco = 0;



int qualeLAMPADAaccesa = 1;
int FLAGtime = 0;
int previousRandomInt = 0;
int randomInt = 0;
int tempoLampeggio = 0;

// ASSEGNA PULSANTI COLORATI
const int pin_pulsanteGIALLO = 6;
const int pin_pulsanteBLU = 7;
const int pin_pulsanteVERDE = 8;
const int pin_pulsanteROSSO = 9;

// ASSEGNA PIN RELè O LAMPADE
int PIN_relayGIALLO = 2;
int PIN_relayBLU = 3;
int PIN_relayVERDE = 4;
int PIN_relayROSSO = 5;

int DEMOEFFECT = 0;
int DEMOTIME = 0;
int STEP_DEMO = 1;

unsigned long time;
unsigned long timeCASUALE;
unsigned long lampeggio_time = 0;
unsigned long lampeggio_timeCASUALE = 0;


int buttonState = 0;
int buttonStateROSSO = 0;
int buttonStateVERDE = 0;
int buttonStateBLU = 0;
int buttonStateGIALLO = 0;

// CUSTOM CARACTER PER BIG DISPLAY
uint8_t uno[8] = {0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,};
uint8_t due[8] = {0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,};
uint8_t tre[8] = {0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,};
uint8_t quattro[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07,};
uint8_t cinque[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F,};
uint8_t sei[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1C,};
uint8_t sette[8] = {0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x1F,};
uint8_t otto[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,};

int StepFunzione = 0;
int TempoBarra = 0;
int kecerahan = 0;
int progressBari = 0;
int punteggioReale = 0;
int i = 0;

int punteggioMax = 0;
int punteggioGioco = 1000;



/*
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX      VOID SETUP   

*/

void setup()
{


  Serial.begin(9600);
  // CONFIGURAZIONE PULSANTI / USCITE
  pinMode(pin_PULSANTE_START, INPUT_PULLUP);

  pinMode(pin_pulsanteGIALLO, INPUT_PULLUP);
  pinMode(pin_pulsanteBLU, INPUT_PULLUP);
  pinMode(pin_pulsanteVERDE, INPUT_PULLUP);
  pinMode(pin_pulsanteROSSO, INPUT_PULLUP);

  pinMode(PIN_relayGIALLO, OUTPUT);
  pinMode(PIN_relayBLU, OUTPUT);
  pinMode(PIN_relayVERDE, OUTPUT);
  pinMode(PIN_relayROSSO, OUTPUT);


  // FORZA I PIN OUT DEI RELè A LOW

  digitalWrite( PIN_relayGIALLO, HIGH );
  digitalWrite( PIN_relayBLU, HIGH );
  digitalWrite( PIN_relayVERDE, HIGH );
  digitalWrite( PIN_relayROSSO, HIGH );


  lcd.begin();
  lcd.createChar(0, uno); // Sends the custom char to lcd
  lcd.createChar(1, due); // Sends the custom char to lcd
  lcd.createChar(2, tre); // Sends the custom char to lcd
  lcd.createChar(3, quattro); // Sends the custom char to lcd
  lcd.createChar(4, cinque); // Sends the custom char to lcd
  lcd.createChar(5, sei); // Sends the custom char to lcd
  lcd.createChar(6, sette); // Sends the custom char to lcd
  lcd.createChar(7, otto); // Sends the custom char to lcd


  // INTRODUZIONE SCRITTE
  lcd.setCursor(0, 0);
  lcd.print ("Gioco riflessi");
  lcd.setCursor(0, 1);
  lcd.print ("T.D channel");
  delay (2000);
  lcd.setCursor(0, 0);
  lcd.print ("Vers. Beatrice ");
  lcd.setCursor(0, 1);
  lcd.print ("Firm 0.1b     ");
  delay (2000);


}

void custom0()
{ // uses segments to build the number 0
  lcd.setCursor(0, 0); // set cursor to column 0, line 0 (first row)
  lcd.write(0);  // call each segment to create
  lcd.write(1);  // top half of the number
  lcd.write(2);
  lcd.setCursor(0, 1); // set cursor to colum 0, line 1 (second row)
  lcd.write(3);  // call each segment to create
  lcd.write(4);  // bottom half of the number
  lcd.write(5);
}

void custom1()
{
  lcd.setCursor(0, 0);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(0, 1);
  lcd.write(4);
  lcd.write(7);
  lcd.write(4);
}

void custom2()
{
  lcd.setCursor(0, 0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(0, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(4);
}

void custom3()
{
  lcd.setCursor(0, 0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(0, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom4()
{
  lcd.setCursor(0, 0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(7);
  lcd.setCursor(2, 1);
  lcd.write(7);
}

void custom5()
{
  lcd.setCursor(0, 0);
  lcd.write(3);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(0, 1);
  lcd.write(4);
  lcd.write(4);
  lcd.write(5);
}

void custom6()
{
  lcd.setCursor(0, 0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(0, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom7()
{
  lcd.setCursor(0, 0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(2, 1);
  lcd.write(7);
}

void custom8()
{
  lcd.setCursor(0, 0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(0, 1);
  lcd.write(3);
  lcd.write(4);
  lcd.write(5);
}

void custom9()
{
  lcd.setCursor(0, 0);
  lcd.write(0);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(2, 1);
  lcd.write(7);
}

void clearnumber()
{ // clears the area the custom number is displayed in
  lcd.setCursor(0, 0);
  lcd.print("   ");
  lcd.setCursor(0, 1);
  lcd.print("   ");
}


/*
  
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX      VOID LOOP   

*/


void loop() {

  //  STRUTTURA DEL PROGRAMMA

  switch (StepFunzione) {
    case 0:    // your hand is on the sensor
      DEMO_INIZIALE();
      break;
    case 1:    // your hand is close to the sensor
      COUNTDOWN();
      break;
    case 2:    // your hand is a few inches from the sensor
      GAMEPLAY();
      break;
    case 3:    // your hand is nowhere near the sensor
      FINE_GIOCO();
      break;
  }
  delay(1);        // delay in between reads for stability
}


/*
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX      DEMO INIZIALE  
*/

void DEMO_INIZIALE() {

  progressBari = 0;
  punteggioReale = 0;
  lcd.setCursor (0, 1);
  lcd.print("Max score: ");
  lcd.print(PunteggioRecord);


  //  lampeggio start    ----------------------
  time = millis();
  if (time > lampeggio_time + 500)
  {
    lcd.setCursor (2, 0);
    lcd.print("Press start");
  }
  if (time > lampeggio_time + 1000)
  {
    lcd.setCursor(0, 0);
    lcd.print("                ");
    lampeggio_time = millis();
  }

  //  EFFETTO DEMO (Possibile espansione usando altri "case"

  switch (DEMOEFFECT) {
    case 0:    // your hand is on the sensor
      delay (300);
      DEMOTIME++;
      if (DEMOTIME == 1)digitalWrite(PIN_relayGIALLO, LOW);
      if (DEMOTIME == 2)digitalWrite(PIN_relayBLU, LOW);
      if (DEMOTIME == 3)digitalWrite(PIN_relayVERDE, LOW);
      if (DEMOTIME == 4)digitalWrite(PIN_relayROSSO, LOW);
      if (DEMOTIME == 5)digitalWrite(PIN_relayGIALLO, HIGH);
      if (DEMOTIME == 6)digitalWrite(PIN_relayBLU, HIGH);
      if (DEMOTIME == 7)digitalWrite(PIN_relayVERDE, HIGH);
      if (DEMOTIME == 8)digitalWrite(PIN_relayROSSO, HIGH);
      if (DEMOTIME >= 8)
        DEMOTIME = 0;

      if (STEP_DEMO > 3) DEMOTIME = 1;

      break;
      delay (300);
      DEMOTIME++;
      if (DEMOTIME == 1) {
        digitalWrite(PIN_relayGIALLO, LOW);
        digitalWrite(PIN_relayROSSO, LOW);
      }
      if (DEMOTIME == 2)digitalWrite(PIN_relayBLU, LOW);
      if (DEMOTIME == 3)digitalWrite(PIN_relayVERDE, LOW);
      if (DEMOTIME == 4)digitalWrite(PIN_relayROSSO, LOW);
      if (DEMOTIME == 5)digitalWrite(PIN_relayGIALLO, HIGH);
      if (DEMOTIME == 6)digitalWrite(PIN_relayBLU, HIGH);
      if (DEMOTIME == 7)digitalWrite(PIN_relayVERDE, HIGH);
      if (DEMOTIME == 8)digitalWrite(PIN_relayROSSO, HIGH);
      if (DEMOTIME >= 8)
        DEMOTIME = 0;

      if (STEP_DEMO > 3) DEMOTIME = 1;
      break;
    case 2:    // your hand is a few inches from the sensor
      Serial.println("medium");
      break;
    case 3:    // your hand is nowhere near the sensor
      Serial.println("bright");
      break;
  }


  //  ALLA PRESSIONE DEL TASTO START, VAI ALLA FUNZIONE: COUNTDOWN()

  buttonState = digitalRead(pin_PULSANTE_START);
  if (buttonState == LOW) {
    lcd.clear();
    delay(500);
    StepFunzione = 1;
    lcd.clear();


  }



}


/*
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX      COUNT DOWN     
*/


void COUNTDOWN()
{
  //SPEGNI TUTTI RELE
  if (DEMOTIME == 5)digitalWrite(PIN_relayGIALLO, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayBLU, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayVERDE, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayROSSO, HIGH);


  // CONTATORE AL' INDIETRO CON BIG DISPALY

  lcd.setCursor(5, 0);
  lcd.print("Inizio tra:");
  lcd.setCursor(9, 1);

  clearnumber();
  custom4();
  delay(500);
  clearnumber();
  custom3();
  delay(500);
  clearnumber();
  custom2();
  delay(500);
  clearnumber();
  custom1();
  delay(500);
  clearnumber();
  custom0();
  delay(500);
  clearnumber();


  lcd.clear();
  delay(200);
  
  //SPEGNI TUTTI RELE
  if (DEMOTIME == 5)digitalWrite(PIN_relayGIALLO, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayBLU, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayVERDE, HIGH);
  if (DEMOTIME == 5)digitalWrite(PIN_relayROSSO, HIGH);
  StepFunzione = 2;
}

//----------------------------------------------       GAME PLAY            --------------------------------------------------

void GAMEPLAY () {


  lcd.setCursor (0, 0);
  lcd.print("punteggio: ");
  lcd.print(punteggioReale);

  lcd.setCursor(0, 1);
  kecerahan = map(TempoBarra, 0, 1024, 0, 255);

  progressBari = map(kecerahan, 0, 255, 0, 17);
  for (i = 0; i < progressBari; i++)
  {
    lcd.setCursor(i, 1);
    lcd.write(byte(0));
  }



  //  TEMPORIZZATORE PROGRESSIVO CON MILLIS (PER EVITARE DELAY)

  time = millis();
  if (time > lampeggio_time + TIMERgiocoCOUNTdown)
  {
    TempoBarra = TempoBarra + velocitaBarra;
    lampeggio_time = millis();
  }



 
  //  PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO   PUNTEGGIO  PUNTEGGIO



  // ASSEGNA NUMERO CASUALE UNA VOLTA SOLA ATTRAVERSO UN FLAG CHE INTERROMPE IMMEDIATAMENTE

  if (FLAGtime == 0) {
    randomInt = random(1, 5);
    FLAGtime = 1;
  }


  // ACCENDI RELè
  if (randomInt == 1)digitalWrite(PIN_relayGIALLO, LOW);
  if (randomInt == 2)digitalWrite(PIN_relayBLU, LOW);
  if (randomInt == 3)digitalWrite(PIN_relayVERDE, LOW);
  if (randomInt == 4)digitalWrite(PIN_relayROSSO, LOW);



  ///////    PULSANTE ROSSO ------------------PULSANTE ROSSO ------------------

  buttonStateROSSO = digitalRead(pin_pulsanteROSSO);
  if (buttonStateROSSO == LOW)
  {
    if (randomInt == 4)
    {
      punteggioReale = punteggioReale + PUNTEGGIOstep;
      FLAGgioco = 1;
    }

  }

  if (buttonStateROSSO == LOW)
  {
    if (randomInt != 4)

    {
      punteggioReale = punteggioReale - PUNTEGGIOstep;
      FLAGgioco = 2;
    }

  }

  ///////    PULSANTE VERDEEE ------------------PULSANTE VERDEEE ------------------


  buttonStateVERDE = digitalRead(pin_pulsanteVERDE);
  if (buttonStateVERDE == LOW)
  {

    if (randomInt == 3)

    {
      punteggioReale = punteggioReale + PUNTEGGIOstep;
      FLAGgioco = 1;
    }

  }

  if (buttonStateVERDE == LOW)
  {
    if (randomInt != 3)

    {
      punteggioReale = punteggioReale - PUNTEGGIOstep;
      FLAGgioco = 2;
    }

  }

  ///////    PULSANTE BLUUUU ------------------PULSANTE BLUUUU------------------

  buttonStateBLU = digitalRead(pin_pulsanteBLU);
  if (buttonStateBLU == LOW)
  {

    if (randomInt == 2)

    {
      punteggioReale = punteggioReale + PUNTEGGIOstep;
      FLAGgioco = 1;
    }

  }

  if (buttonStateBLU == LOW)
  {
    if (randomInt != 2)

    {
      punteggioReale = punteggioReale - PUNTEGGIOstep;
      FLAGgioco = 2;
    }

  }

  // porta a zero il valore se ha valori negativi
  if (punteggioReale < 0)
    punteggioReale = 0;

  ///////    PULSANTE GIALLO ------------------PULSANTE GIALLO------------------

  buttonStateGIALLO = digitalRead(pin_pulsanteGIALLO);
  if (buttonStateGIALLO == LOW)
  {

    if (randomInt == 1)

    {
      punteggioReale = punteggioReale + PUNTEGGIOstep;
      FLAGgioco = 1;
    }

  }

  if (buttonStateGIALLO == LOW)
  {
    if (randomInt != 1)

    {
      punteggioReale = punteggioReale - PUNTEGGIOstep;
      FLAGgioco = 2;
    }

  }




  // RESETTA LA FLAG  --- PRESSIONE CORRETTA
 
  if (FLAGgioco == 1) {
    delay(TEMPOrilancio);
    lcd.setCursor (9, 0);
    lcd.print("       ");
    FLAGgioco = 0;
    FLAGtime = 0;
    digitalWrite(PIN_relayGIALLO, HIGH);
    digitalWrite(PIN_relayBLU, HIGH);
    digitalWrite(PIN_relayVERDE, HIGH);
    digitalWrite(PIN_relayROSSO, HIGH);
  }


  // RESETTA LA FLAG ---  PPRESSIONE ERRATA
 
  if (FLAGgioco == 2) {
    digitalWrite(PIN_relayGIALLO, LOW);
    digitalWrite(PIN_relayBLU, LOW);
    digitalWrite(PIN_relayVERDE, LOW);
    digitalWrite(PIN_relayROSSO, LOW);
    delay(TEMPOpenalita);
    lcd.setCursor (9, 0);
    lcd.print("       ");
    FLAGgioco = 0;
    FLAGtime = 0;
    digitalWrite(PIN_relayGIALLO, HIGH);
    digitalWrite(PIN_relayBLU, HIGH);
    digitalWrite(PIN_relayVERDE, HIGH);
    digitalWrite(PIN_relayROSSO, HIGH);
  }






  // TEMPO GIOCO FINITO...VAI A GAME OVER
  if (progressBari > 16) {
    lcd.clear();
    delay(1000);
    TempoBarra = 0;
    digitalWrite(PIN_relayGIALLO, LOW);
    digitalWrite(PIN_relayBLU, LOW);
    digitalWrite(PIN_relayVERDE, LOW);
    digitalWrite(PIN_relayROSSO, LOW);
    delay(200);
    digitalWrite(PIN_relayGIALLO, HIGH);
    delay(200);
    digitalWrite(PIN_relayROSSO, HIGH);
    delay(200);
    digitalWrite(PIN_relayBLU, HIGH);
    delay(200);
    digitalWrite(PIN_relayVERDE, HIGH);

    // ASSEGNA ALLA VARIABILE PUNTEGGIO RECORD, IL PUNTEGGIO RAGGIUNTO SE MAGGIORE
    if (punteggioReale >= PunteggioRecord)
      PunteggioRecord = punteggioReale;
    StepFunzione = 3;

  }
}


/*
  
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX     FINE GIOCO      
*/


void FINE_GIOCO() {
  if  (punteggioReale >= PunteggioRecord) {

    lcd.setCursor (0, 0);
    lcd.print ("NewRecord: ");
    lcd.print (punteggioReale);
    lcd.setCursor (0, 1);
    lcd.print ("   Finegioco   ");
    delay (300);
    lcd.clear();
    delay (300);
    tempoLampeggio++;
  }


  if  (punteggioReale < PunteggioRecord) {
    lcd.setCursor (0, 0);
    lcd.print ("score: ");
    lcd.print (punteggioReale);
    lcd.setCursor (0, 1);
    lcd.print ("   Finegioco   ");
    delay (4300);
    StepFunzione = 0;

  }

  if (tempoLampeggio > 6) {
    tempoLampeggio = 0;
    StepFunzione = 0;
  }



  digitalWrite(PIN_relayGIALLO, HIGH);
  digitalWrite(PIN_relayBLU, HIGH);
  digitalWrite(PIN_relayVERDE, HIGH);
  digitalWrite(PIN_relayROSSO, HIGH);


}

Di fatto una cosa simile al vecchio gioco "Simon", giusto?

Ok, quindi qual è la tua domanda?

PS: chi ha scritto e che significa sta cosa?

// ATTENZIONEEEEEEEEEEEEEEEEEE  se avete problemi nel visualizzare i caratteri SUL DISPLAY 
// al posto di "" LiquidCrystal_I2C lcd(0x3F, 16, 2); "" scrivete  ""LiquidCrystal_I2C lcd(0x3F, 16, 2);

Grazie per la risposta.
Si tipo il vecchio Simon.
Considera che sia il codice che il progetto l'ho trovato su internet, penso che quel pezzo di codice si riferisca ad eventuali problemi sul funzionamento della libreria per lcd.

Ok, ignoriamo comunque quel commento (che non ha comunque senso).

Ripeto: qual è quindi la tua domanda?

PS: a proposito di giochi e Arduino, se hai (o trovi come usato, anche non funzionante) un vecchio "Quizzettone", prova a dare un'occhiata a questo "retrofit" per trasformare il "Quizzettone" in "Quizzettino" (nel mio caso controllabile da PC ma puoi implementare il gioco direttamente nel Nano):

per quanto riguarda il vecchio simon, la c'e' una sequenza da seguire ogni volta da capo invece a me servirebbe "semplicemente" dei led che casualmente volta per volta si accendono , e per per spegnere il led devo andare vicino ad un sensore pir collocato vicino al led corrispondente e farlo spegnere. Quindi 4 led e 4 pir .

progetto luci
questo e' il progetto che potrebbe essere al caso, solo che anziche' i pulsanti per spegnerei led dovrei utilizzare i pir (4) e vicino i rispettivi led che si accenderanno casualmente

Beh nessun problema, ma ovviamente va modificato quel codice.
Ma prima domanda: hai già il materiale? E l'hai iniziato a collegare? Hai provato a modificare il codice immagino/spero, quindi servirebbe il TUO codice modificato (insieme a qual è la difficoltà che stai incontrando, così possiamo aiutarti)? Non penserai mica che te lo modifichiamo noi, vero? ;-)

Scusa, ma perché parli di PIR? In che modo dovresti usare il gioco? Se pensi ad un pannello su cui passare una mano, ti bastano 4 sensori di prossimità ad infrarosso (tipo QUESTI, usati per irlevare ostacoli), non dei PIR (che si usano per rilevare movimenti più "ampi" di una mano).
Spiega meglio il tuo obiettivo ossia descrivi bene come dovrebbe funzionare il gioco, e vediamo. Poi una volta chiarita la parte hardware si può parlare di software.

Il codice ancora non l'ho modificato perche' devo prima sistemare la parte hardware . Appena ho modo vi posto il disegno del circuito su arduino.

Ok, bene. Ma prendi in considerazione quei sensori IR perché se il gioco è come credo di aver capito dalla tua descrizione, ti servono quelli e non i PIR.
Per lo schema disegnalo con Wokwi o Tinkercad, così oltre ad impratichirti con un utile strumento puoi fare il "tuo" progetto da condividere qui.

immagine
quest'immagine grezza per farvi capire . Al centro c'e' una persona ai quattro lati (destra,sinistra,avanti e dietro) ci sono le postazioni con sensore e led. Con casualita' si devono accendere i led , la persona una volta visto il led acceso si sposta verso la postazione e con un gesto con la mano fa spegnere il led corrispondente.
Spero di essere stato chiaro, grazie mille a tutti.

Beh allora se non deve rilevare altro, confermo, io al posto tuo userei quei sensori IR che ti ho linkato.

Ciao. Avevo fatto un progetto "simile" però wireless (mi serviva mettere i sensori lontani tra loro). Se serve posso condividerlo anche se ti si complica un pochino la vita... Un arduino per ogni sensore, un modulo hc12 per ogni sensore, alimentazione separata per ogni sensore... Lato software gestione della comunicazione tra master e slave...

per me va bene, potrei prendere spunto per poi portalo via cavo?


Questo e' il progetto riportato su tinkercad, lo so e' incasinato e' il mio primo progetto... :dizzy_face:
abbiate pieta'.....

Onestamente credo che dovresti stravolgerlo...
Comunque appena accendo il pc posto tutto

Eccomi.
Cerco di riassumere il tutto... sarà un post lunghetto... porta pazienza...
Essendo wireless c'è un master con N slave. Il master ovviamente comanda e gli slave poveracci ubbidiscono.

MASTER
L'idea era quella di "allenare" i riflessi e la reattività, quindi ho previsto la possibilità di inserire un tempo massimo di risposta e un tempo di attesa tra gli stimoli. Il master gestisce i tempi, invia i comandi di accensione led allo slave corretto, legge lo stato di risposta.
Ho usato un arduino mega, un modulo hc12, un ldc e 5 pulsanti.

SLAVE
Lo slave si limita ad aspettare i comandi dal master. Quando riceve il comado di accensione accende i led e verifica se il sensore di prossimità rileva qualcosa entro il tempo impostato. Se non si reagisce in tempo o se si reagisce allo slave sbagliato segna l'errore. Quando riceve il comando per leggere lo stato risponde col numero di errori commessi.
Ho usato un arduino nano, un modulo hc12, un ldc, un buzzer e diversi led bicolore.

Il tutto funziona a batteria.

Riguardo al codice, c'è una parte in comune tra master e slave (questi file devono essere nelle cartelle di entrambi gli sketch):

comunicazione.h

/*
 * Funzioni per l'invio e la ricezione di dati byte / byte 
 * 
 */

#ifndef CHR_START
  #define CHR_START '['
#endif
#ifndef CHR_STOP
  #define CHR_STOP  ']'
#endif
#ifndef CHR_SEP
  #define CHR_SEP   ','
#endif
#ifndef TIMEOUT
  #define TIMEOUT   1000
#endif

// - 0 = ricezione non completata
// - 1 = dati ricevuti correttamente
// - 2 = errore timeout
// - 3 = errore dati in arrivo oltre la dimensione massima
// - 4 = errore dati incompleti
#define RX_WAIT    0
#define RX_OK      1
#define RX_TIMEOUT 2
#define RX_HIGH    3
#define RX_LOW     4

// funzione che trasmette
// i dati vengono trasmessi un byte alla volta
// parametri:
// - seriale = canale su cui trasmettere (serial / HC12)
// - pacchetto = dati da trasmettere. serve un puntatore per scorrere la struttura dati un byte alla volta
// - dimensione = numero di byte da trasmettere
void Trasmetti(Stream &seriale, unsigned char * pacchetto, size_t dimensione) {
  // invio il carattere di start
  seriale.print(CHR_START);
  // invio i dati
  for (byte i=0; i<dimensione; i++) {
    seriale.print(*(pacchetto+i), HEX);
    seriale.print(CHR_SEP);
  }
  // invio il carattere di stop
  seriale.print(CHR_STOP);

  return;
}


// funzion che riceve
// i dati arrivano sotto forma di caratteri che presi a 2 a 2 formano
// un byte rappresentato in HEX
// parametri:
// - seriale = canale da cui ricevere (serial / HC12)
// - pacchetto = contenitore dei dati da ricevere. serve un puntatore per scorrere la struttura dati un byte alla volta
// - dimensione = numero di byte massimo da ricevere
// ritorna:
// - 0 = ricezione non completata
// - 1 = dati ricevuti correttamente
// - 2 = errore timeout
// - 3 = errore dati in arrivo oltre la dimensione massima
// - 4 = errore dati incompleti
byte Ricevi(Stream &seriale, unsigned char * pacchetto, size_t dimensione) {
  // dimensione array di appoggio
  #define MAX 2
  //indice del byte ricevuto all'interno della struttura di destinazione
  //inizializzo con un valore fuori range massimo
  static uint32_t i = dimensione;
  // indice del carattere arrivato dentro l'array di appoggio
  static uint8_t j = 0;
  // array di appoggio per decodificare la stringa HEX in numero
  static char stringa[MAX + 1] = "";
  // valore millis per controllo timeout
  static uint32_t inizio = millis();
  // valore appena ricevuto
  byte valore;

  while (seriale.available()) {
    valore = seriale.read();
    // controllo che carattere è
    switch (valore) {
      case CHR_START:
        // è il carattere di inizio trasmissione
        // azzero gli indici
        i = 0;
        j = 0;
        // azzero l'array di appoggio;
        stringa[0] = '\0';
        stringa[1] = '\0';
        stringa[2] = '\0';
        // faccio partire il tempo per il timeout
        inizio = millis();
        break;
      case CHR_STOP:
        // è il carattere di fine trasmissione
        if (i == dimensione) {
          return RX_OK;
        } else {
          //il terminatore è arrivato troppo presto
          return RX_LOW;
        }
        break;
      case CHR_SEP:
        // è il carattere separatore
        // salvo il byte
        if (i < dimensione) {
          *(pacchetto+i) = strtol(stringa, NULL, 16);
        } else {
          // ho superato la dimensione della struttura
          return RX_HIGH;
        }
        // devo passare al byte successivo
        i++;
        j = 0;
        // azzero l'array di appoggio;
        stringa[0] = '\0';
        stringa[1] = '\0';
        stringa[2] = '\0';
        break;
      default:
        // è un carattere da convertire
        if (j < MAX) {
          stringa[j] = valore;
          j++;
        }
        break;
    }
    // controllo il timeout
    if ((millis() - inizio) > TIMEOUT) {
      // azzero tutto prima di restituire errore
      i = 0;
      j = 0;
      // azzero l'array di appoggio;
      stringa[0] = '\0';
      stringa[1] = '\0';
      stringa[2] = '\0';
      return RX_TIMEOUT;
    }
  }

  return RX_WAIT;
}

datastruct.h

// DEFINIZIONE STRUTTURE DATI - deve essere uguale su trasmettitore e ricevitore

typedef struct {
    // id messaggio = mi serve un valore univoco per avere crc diversi anche con dati uguali
    // è un valore arbitrario deciso dal trasmittente, non viene usato dal ricevente
    // uso il valore di millis()
    uint32_t idmsg;
    // id del destinatario
    uint32_t  destinatario;
    // valori da comunicare al destinatario
    uint32_t comando;
    uint32_t valore;
} t_dati;

#define DIMDATI (sizeof(t_dati))

typedef struct {
  t_dati dati;
  uint32_t crc;
} t_pack;

#define DIMPACK (sizeof(t_pack))

define.h

/*************************************************************************************
 * Comandi:
 *   0 = richiesta stato (errori)
 *   1 = accendi luce
 *   2 = suona beep
 *   3 = accendi + suona
 *   
 * 100 = risposta richiesta stato (errori)
 * 101 = slave comunica rilevazione sensore in tempo 
 * 102 = workout finito
 * 
 * 200 = check presenza slave (ricerca iniziale)
 * 201 = risposta presenza ok
 * 
 * 253 = pacchetto corrotto (crc non valido)
 * 254 = comando sconosciuto
 * 255 = comando ricevuto correttamente
 */

#define CMD_STATUS   0
#define CMD_LIGHT    1
#define CMD_BEEP     2
#define CMD_BOTH     3

#define CMD_REPLY  100
#define CMD_FGHTOK 101
#define CMD_FINISH 102
#define CMD_START  103

#define CMD_CHECK  200
#define CMD_CHKOK  201

#define CMD_ERRCRC 253
#define CMD_ERRCMD 254
#define CMD_TXOK   255

funz-crc32.c

#ifndef __SAM3X8E__
   #ifndef __PGMSPACE_H_
      #include <avr/pgmspace.h>
   #endif
#endif

#ifdef __SAM3X8E__
   const unsigned long crctab32[] =
#else
   const uint32_t crctab32[] PROGMEM =
#endif
{
 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

/*
 * Update a CRC check on the given buffer.
 */

unsigned long calc_crc32(unsigned char* buf, unsigned int len)
{
    unsigned long crc;
    unsigned int i;
    
    crc = 0xffffffff;
    for (i = 0; i < len; i++)
      #if defined(__SAM3X8E__)
        crc = ((crc >> 8) & 0x00ffffff) ^ crctab32[(crc ^ *buf++) & 0xff];
      #else
        crc = ((crc >> 8) & 0x00ffffff) ^ pgm_read_dword_near(&crctab32[(crc ^ *buf++) & 0xff]);
      #endif
    return (crc ^ 0xffffffff);
}

funz-crc32.h

#ifdef __cplusplus
 extern "C" {
#endif

unsigned long calc_crc32(unsigned char*, int);

#ifdef __cplusplus
 }
#endif

Poi c'è la parte specifica del MASTER
sketch principale

/********************************************************************************
PROGETTO LUCI ALLENAMENTO

Trasmissione

- Arduino Mega
- Modulo HC12

Organizzazione:
N 0 = master
N 1..n = slave

Modalità:
- Ciclica 123 123
- Reverse 12321
- Random

Parametri:
- Tempo acceso
- Tempo morto tra uno e l'altro
- Numero ripetizioni
- Tipo avviso (luce / beep)

Elenco pin:
-   0: riservato usb
-   1: riservato usb
-  A8: Button Sx
-  A9: Button Ok
- A10: Button Giu
- A11: Button Su
- A12: Button Dx
-   7: Buzzer
-   6: Hc12 Set
-  14: Hc12 Rx (Serial3)
-  15: Hc12 Tx (Serial3)
-  20: Lcd sda
-  21: Lcd scl
-   0:
-   0:

********************************************************************************/

// funzione calcolo CRC32 - grazie Guglielmo GPB01
#include "funz-crc32.h"

// ******************************************************************************
// DEFINIZIONE STRUTTURE DATI - deve essere uguale su trasmettitore e ricevitore
#include "datastruct.h"

// ******************************************************************************
// DEFINIZIONE COSTANTI COMANDI - STATI - deve essere uguale su trasmettitore e ricevitore
#include "define.h"

// ******************************************************************************
// FUNZIONI INVIO / RICEZIONE - deve essere uguale su trasmettitore e ricevitore
#include "comunicazione.h"

// librerie
#include <Wire.h>
#include <PCF8574_HD44780_I2C.h>
//#include <SoftwareSerial.h>   // su MEGA non serve
#include <EEPROM.h>

// pin modulo HC12
#define HC12RxdPin  14                  // Recieve Pin on HC12
#define HC12TxdPin  15                  // Transmit Pin on HC12
#define HC12SetPin  6                  // Transmit Pin on HC12

HardwareSerial* HC12;
//SoftwareSerial HC12(HC12TxdPin,HC12RxdPin); // Create Software Serial Port

// imposto DISPLAY LCD I2C
//PCF8574_HD44780_I2C lcd(0x27, 20, 4);
PCF8574_HD44780_I2C lcd(0x3F, 20, 4);

// parametri pulsanti
#define BTN_SU  A11
#define BTN_GIU A10
#define BTN_OK  A9
#define BTN_DX  A12
#define BTN_SX  A8
bool btn_su_stato, btn_giu_stato, btn_ok_stato, btn_dx_stato, btn_sx_stato = false;
uint32_t btn_pressione_lunga = 1000;
uint32_t btn_pressione_breve = 150;

// parametri buzzer
#define BEEP_PIN  7
#define BEEP_OK   4000
#define BEEP_ERR  400
#define BEEP_DELAY 100

// numero di slave trovati
uint32_t NumTarget = 0;
// struttura per la trasmissione / ricezione dei dati
t_pack tx, rx;
// variabile per il risultato della trasmissione
uint8_t ricevuto;
// variabili per il timeout della trasmissione
#define TX_TIMEOUT 1000
uint32_t tx_inizio;

// parametri allenamento
// fight   = tempo per raggiungere il target e spegnere la luce
// rest    = intervallo tra un fight e l'altro
// rep_max = ripetizioni
// mode    = modalità
// alert   = tipo avviso luce / beep
#define MODE_MAX 2 //valore massimo modalità
#define MODE_CLC 0
#define MODE_REV 1
#define MODE_RND 2
#define ALERT_MAX   2
#define ALERT_LIGHT 0
#define ALERT_BEEP  1
#define ALERT_BOTH  2
struct t_workout {
  uint32_t fight;
  uint32_t rest;
  uint32_t rep;
  uint32_t mode;
  uint32_t alert;
} workout;
uint32_t errori, bug = 0;
uint32_t rep, target = 0;

// parametri EEPROM
#define EEPROM_START 0
//#define EEPROM_DIM (sizeof(uint32_t))

// parametri stato loop
uint8_t stato = 0;
#define STATO_FIGHT_INVIA 0
#define STATO_FIGHT_WAIT  1
#define STATO_REST        2
// parametri temporizzazione workout
uint32_t workout_inizio, workout_ritardo;
// conto alla rovescia iniziale
#define COUNTDOWN 5

// parametri polling (interrogazione ciclica slave)
bool polling = false;

// variabili varie di appoggio
int32_t i, direzione, inizio;
char stringa[20];
bool finito;


void setup() {
  // seriale a 9600
  Serial.begin(9600);
  // HC12 a 9600
  HC12 = &Serial3;
  (*HC12).begin(9600);
  // impostazione HC12
  pinMode(HC12SetPin,OUTPUT);
  digitalWrite(HC12SetPin,HIGH);  // LOW = AT mode - HIGH = modo normale
  delay(200);

  // pulsanti
  pinMode(BTN_SU, INPUT_PULLUP);
  pinMode(BTN_GIU, INPUT_PULLUP);
  pinMode(BTN_OK, INPUT_PULLUP);
  pinMode(BTN_DX, INPUT_PULLUP);
  pinMode(BTN_SX, INPUT_PULLUP);

  // buzzer
  pinMode(BEEP_PIN, OUTPUT);
  noTone(BEEP_PIN);

  // inizializzo LCD
  lcd.init();
  lcd.backlight();
  // scrivo un messaggio di attesa
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Searching...");
  delay(200);

  // cerco gli slave
  CercaSlave();

  //NumTarget = 1;

  lcd.clear();
  // ricerca slave finita
  // verifico quanti ne ho trovati
  if (NumTarget == 0) {
    // nessuno slave trovato
    lcd.setCursor(0,0);
    lcd.print("No target found");
    lcd.setCursor(0,2);
    lcd.print("Restart & try again");
    Beep(2,BEEP_ERR);
    // mi fermo qua
    while (1);
  }

  // impostazioni allenamento
  Settings();

  lcd.noCursor();
  lcd.noBlink();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Ready to fight?");
  lcd.setCursor(2,1);
  lcd.print("Press OK to start!");
  lcd.setCursor(0,3);
  lcd.print("                <OK>");
  // aspetto il pulsante ok
  while (LeggiPulsante(BTN_OK, &btn_ok_stato) == 0);

  // conto alla rovescia
  lcd.clear();
  for (i=COUNTDOWN; i>0; i--) {
    lcd.setCursor(6,1);
    lcd.print("Wait ");
    dtostrf(i,2,0,stringa);
    lcd.print(stringa);
    Beep(1,BEEP_OK);
    delay(500);
    lcd.clear();
    delay(500);
  }
  lcd.setCursor(8,1);
  lcd.print("GO!");
  Beep(4,BEEP_OK);

  // aggiorno il display
  lcd.clear();
  //AggiornaDisplayRun(false);

  // mando a tutti gli slave il comando di START
  for (i=1; i<=NumTarget; i++) {
    // trasmetto il comando
    tx.dati.idmsg = millis();
    tx.dati.destinatario = i;
    tx.dati.comando = CMD_START;
    tx.dati.valore = 0;
    tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
    Trasmetti((*HC12), (unsigned char *)&tx, DIMPACK);
    // non aspetto la risposta
  } // for

  // si comincia
  randomSeed(analogRead(0));
  stato = STATO_FIGHT_INVIA;
  if (workout.mode == MODE_RND) {
    target = random(NumTarget) + 1;
  } else {
    target = 1;
  }
  direzione = +1;
  rep = 1;
  workout_inizio = millis();
  workout_ritardo = 0;
}

void loop() {

  // verifico lo stato attuale
  switch (stato) {
    case STATO_FIGHT_INVIA:
      if ((millis() - workout_inizio) > workout_ritardo) {
        // devo inviare il comando allo slave - DEVO PREVEDERE DEI RETRY SE NON RICEVO RISPOSTA
        tx.dati.idmsg = millis();
        tx.dati.destinatario = target;
        switch (workout.alert) {
          case ALERT_BEEP:
            tx.dati.comando = CMD_BEEP;
            break;
          case ALERT_BOTH:
            tx.dati.comando = CMD_BOTH;
            break;
          default:
            tx.dati.comando = CMD_LIGHT;
            break;
        }
        tx.dati.valore = workout.fight;
        tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
        Trasmetti((*HC12), (unsigned char *)&tx, DIMPACK);

        // aggiorno il display
        AggiornaDisplayRun(false);

        // controllo se lo slave ha ricevuto il comando entro il timeout
        finito = false;
        tx_inizio = millis();
        while ((!finito) && ((millis() - tx_inizio) <= TX_TIMEOUT)) {
          ricevuto = Ricevi((*HC12), (unsigned char *)&rx, DIMPACK);
          if (ricevuto == RX_OK) {
            // i dati sono arrivati
            // verifico il CRC
            if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
              // i dati sono validi
              // verifico che il comando sia corretto
              if (rx.dati.comando == CMD_TXOK) {
                // lo slave ha risposto
                finito = true;
              }
            }
          }
        } // while
        
        // controllo se sono uscito per risposta o timeout
        if (finito) {
          // faccio partire il tempo
          workout_inizio = millis();
          workout_ritardo = workout.fight * 1000;
          // abilito il polling degli slave
          polling = true;
          // passo allo stato successivo
          stato = STATO_FIGHT_WAIT;
        } else {
          // lo slave non ha risposto
          // aumento il contatore errori trasmissione
          bug++;
          // rimango nello stato invio per riprovare???
          stato = STATO_FIGHT_INVIA;
        } // if
      }
      break;
    case STATO_FIGHT_WAIT:
      // verifico se lo slave comunica la fine anticipata
      if ((millis() - workout_inizio) > workout_ritardo) {
        // tempo scaduto, passo in attesa
        stato = STATO_REST;
      } else {
        ricevuto = Ricevi((*HC12), (unsigned char *)&rx, DIMPACK);
        if (ricevuto == RX_OK) {
          // i dati sono arrivati
          // verifico il CRC
          if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
            // i dati sono validi
            // verifico che il comando sia corretto
            if (rx.dati.comando == CMD_FGHTOK) {
              // lo slave ha comunicato che ha rilevato il sensore entro il tempo previsto
              // quindi passo subito alla fase successiva
              stato = STATO_REST;
              // imposto ritardo 0 per entrare subito nella fase successiva
              workout_inizio = millis();
              workout_ritardo = 0;
            }
          }
        }
      } // else
      break;
    case STATO_REST:
      if ((millis() - workout_inizio) > workout_ritardo) {
        // ciclicamente interrogo gli slave
        if (polling) {
          errori = 0;
          // chiamo tutti gli slave
          for (i=1; i<=NumTarget; i++) {
            // trasmetto il comando
            tx.dati.idmsg = millis();
            tx.dati.destinatario = i;
            tx.dati.comando = CMD_STATUS;
            tx.dati.valore = 0;
            tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
            Trasmetti((*HC12), (unsigned char *)&tx, DIMPACK);
            // aspetto la risposta
            inizio = millis();
            while ((millis() - inizio) <= TX_TIMEOUT) {
              ricevuto = Ricevi((*HC12), (unsigned char *)&rx, DIMPACK);
              if (ricevuto == RX_OK) {
                // i dati sono arrivati
                // verifico il CRC
                if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
                  // i dati sono validi
                  // verifico che il comando sia corretto
                  if (rx.dati.comando == CMD_REPLY) {
                    // lo slave ha risposto
                    // aggiorno gli errori
                    errori += rx.dati.valore;
                    // esco dal while
                    break;
                  }
                }
              }
            } // while
            // devo verificare se sono uscito perché lo slave ha risposto
            // oppure perché è passato troppo tempo
            if ((millis() - inizio) > TX_TIMEOUT) {
              // devo decidere cosa fare se lo slave non risponde...
              ;
            }
          } // for
          // disabilito il polling fino al prossimo fight
          polling = false;
        }
        // aggiorno il display
        AggiornaDisplayRun(false);
        // decido il prossimo slave
        switch (workout.mode) {
          case MODE_CLC: //123123
            target++;
            if (target > NumTarget) {
              target = 1;
            }
            break;
          case MODE_REV: //12321
            target += direzione;
            if (target <= 1) {
              direzione = +1;
            } else if (target >= (NumTarget-1)) {
              direzione = -1;
            }
            break;
          case MODE_RND: //random
            target = random(NumTarget) + 1;
            break;
        }
        // aumento il round
        rep++;
        // faccio partire il tempo
        workout_inizio = millis();
        workout_ritardo = workout.rest * 1000;
        // passo allo stato successivo
        stato = STATO_FIGHT_INVIA;
      }
      break;
    default: // stato sconosciuto
      // devo decidere cosa fare
      ;
  } // switch

  // verifico se ho finito
  if (rep > workout.rep) {
    rep--; // torno indietro di 1 solo per questioni di visualizzazione
    AggiornaDisplayRun(true);
    // comunico a tutti gli slave che abbiamo finito
    for (i=1; i<=NumTarget; i++) {
      // trasmetto il comando
      tx.dati.idmsg = millis();
      tx.dati.destinatario = i;
      tx.dati.comando = CMD_FINISH;
      tx.dati.valore = 0;
      tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
      Trasmetti((*HC12), (unsigned char *)&tx, DIMPACK);
      // non aspetto la risposta
    } // for

    // aspetto in eterno...
    while (1);
  }
}

funzioni messe in un tab separato

// funzione che legge un pulsante
// PIN = pin da leggere
// premuto = puntatore alla variabile premuto riferita al pulsante
// restituisce: 0 = non premuto
//              1 = pressione breve
//              2 = pressione lunga
uint8_t LeggiPulsante(uint8_t PIN, bool *premuto) {
  // variabili gestione pressione
  static uint32_t old_time, new_time;

  if ((digitalRead(PIN) == LOW) && !(*premuto)) {
    old_time = millis();
    *premuto = true;
  }

  if ((*premuto) && (digitalRead(PIN) == HIGH)) {
    new_time = millis();

    if ((new_time - old_time) > btn_pressione_lunga) {
      *premuto = false;
      return 2;
    } else if ((new_time - old_time) > btn_pressione_breve) {
      *premuto = false;
      return 1;
    }
  }

  if (*premuto) {
    if ((millis() - old_time) > btn_pressione_lunga) {
      *premuto = false;
      return 2;
    }
  }
  
  return 0;  
}

// funzione che cerca gli slave
void CercaSlave() {
  bool finito;
  uint8_t i, ricevuto;
  uint32_t inizio;
  
  finito = false;
  i = 1;
  while (!finito) {
    // provo a contattare uno slave
    tx.dati.idmsg = millis();
    tx.dati.destinatario = i;
    tx.dati.comando = CMD_CHECK;
    tx.dati.valore = 0;
    tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
    Trasmetti((*HC12), (unsigned char *)&tx, DIMPACK);
    // aspetto la risposta
    inizio = millis();
    while ((millis() - inizio) <= TX_TIMEOUT) {
      ricevuto = Ricevi((*HC12), (unsigned char *)&rx, DIMPACK);
      if (ricevuto == RX_OK) {
        // i dati sono arrivati
        // verifico il CRC
        if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
          // i dati sono validi
          // verifico che il comando sia corretto
          if (rx.dati.comando == CMD_CHKOK) {
            // lo slave ha risposto
            // aumento il progressivo slave
            NumTarget++;
            i++;
            // esco dal while
            break;
          }
        }
      }
    } // while
    // devo verificare se sono uscito perché lo slave ha risposto
    // oppure perché è passato troppo tempo
    if ((millis() - inizio) > TX_TIMEOUT) {
      // l'ultimo slave provato non ha risposto, quindo ho finito
      finito = true;
    }
  }

}

// funzione per impostare i parametri allenamento
void Settings() {
  #define MAX_OPZIONI 5
  bool finito;
  int8_t direzione;
  int8_t opzione, btn;
  
  // recupero i parametri in EEPROM
  EEPROM.get(EEPROM_START, workout);
  // Visualizzo il numero di slave trovati
  // e chiedo i parametri
  Beep(1,BEEP_OK);
  finito = false;
  direzione = 0;
  opzione = 0;
  AggiornaDisplaySettings(opzione);

  while (!finito) {
    // controllo il pulsante SU
    btn = LeggiPulsante(BTN_SU, &btn_su_stato);
    if (btn != 0) {
      direzione = +1;
    }
    // controllo il pulsante GIU
    btn = LeggiPulsante(BTN_GIU, &btn_giu_stato);
    if (btn != 0) {
      direzione = -1;
    }
    // cambio il valore in base alla posizione i
    if (direzione != 0) {
      switch (opzione) {
        case 0: // rep
          workout.rep += direzione;
          if ((workout.rep < 1) || (workout.rep > 999)) {
            workout.rep = 1;
          }
          break;
        case 1: // fight
          workout.fight += direzione;
          if ((workout.fight < 1) || (workout.fight > 999)) {
            workout.fight = 1;
          }
          break;
        case 2: // rest
          workout.rest += direzione;
          if ((workout.rest < 0) || (workout.rest > 999)) {
            workout.rest = 0;
          }
          break;
        case 3: // mode
          workout.mode += direzione;
          if (workout.mode > MODE_MAX) {
            workout.mode = 0;
          }
          break;
        case 4: // alert
          workout.alert += direzione;
          if (workout.alert > ALERT_MAX) {
            workout.alert = 0;
          }
          break;
      }

      AggiornaDisplaySettings(opzione);
      //Beep(1,BEEP_OK);
      direzione = 0;
    }

    // controllo il pulsante DX
    btn = LeggiPulsante(BTN_DX, &btn_dx_stato);
    if (btn != 0) {
      Beep(1,BEEP_OK);
      opzione = ((opzione+1) % MAX_OPZIONI);
      AggiornaDisplaySettings(opzione);
    }
    // controllo il pulsante SX
    btn = LeggiPulsante(BTN_SX, &btn_sx_stato);
    if (btn != 0) {
      Beep(1,BEEP_OK);
      opzione--;
      if (opzione < 0) {
        opzione = MAX_OPZIONI - 1;
      }
      AggiornaDisplaySettings(opzione);
    }

    // controllo il pulsante OK
    btn = LeggiPulsante(BTN_OK, &btn_ok_stato);
    if (btn != 0) {
      Beep(2,BEEP_OK);
      finito = true;
    }

  } // while

  // salvo i parametri in eeprom
  EEPROM.put(EEPROM_START, workout);

}

// funzione che aggiorna il display delle impostazioni
void AggiornaDisplaySettings(uint8_t pos) {

  lcd.blink();
  // prima riga
  lcd.setCursor(0,0);
  lcd.print("Target ");
  dtostrf(NumTarget,2,0,stringa);
  lcd.print(stringa);
  lcd.setCursor(11,0);
  lcd.print("Round ");
  dtostrf(workout.rep,3,0,stringa);
  lcd.print(stringa);
  // seconda riga
  lcd.setCursor(0,1);
  lcd.print("Fight ");
  dtostrf(workout.fight,3,0,stringa);
  lcd.print(stringa);
  lcd.setCursor(11,1);
  lcd.print("Rest  ");
  dtostrf(workout.rest,3,0,stringa);
  lcd.print(stringa);
  // terza riga
  lcd.setCursor(0,2);
  lcd.print("Mode  ");
  switch (workout.mode) {
    case MODE_CLC:
      lcd.print("CLC");
      break;
    case MODE_REV:
      lcd.print("REV");
      break;
    case MODE_RND:
      lcd.print("RND");
      break;
  }
  lcd.setCursor(11,2);
  lcd.print("Alert ");
  switch (workout.alert) {
    case ALERT_LIGHT:
      lcd.print("LGH");
      break;
    case ALERT_BEEP:
      lcd.print("BIP");
      break;
    case ALERT_BOTH:
      lcd.print("L+B");
      break;
  }
  // quarta riga
  lcd.setCursor(0,3);

  switch (pos) {
    case 0: // rep
      lcd.setCursor(19,0);
      break;
    case 1: // fight
      lcd.setCursor(8,1);
      break;
    case 2: // rest
      lcd.setCursor(19,1);
      break;
    case 3: // mode
      lcd.setCursor(6,2);
      break;
    case 4: // alert
      lcd.setCursor(17,2);
      break;
  }

}

// funzione che aggiorna il display durante l'allenamento
void AggiornaDisplayRun(bool finito) {

  //lcd.noCursor();
  lcd.noBlink();
  // prima riga
  lcd.setCursor(0,0);
  lcd.print("Mode  ");
  switch (workout.mode) {
    case MODE_CLC:
      lcd.print("Cyclic ");
      break;
    case MODE_REV:
      lcd.print("Reverse");
      break;
    case MODE_RND:
      lcd.print("Random ");
      break;
  }
  lcd.setCursor(15,0);
  if ((stato == STATO_FIGHT_INVIA) || (stato == STATO_FIGHT_WAIT)) {
    lcd.print("Fight");
  } else if (stato == STATO_REST) {
    lcd.print("Rest ");
  } else {
    lcd.print("     ");
  }

  // seconda riga
  lcd.setCursor(0,1);
  lcd.print("Round ");
  dtostrf(rep,3,0,stringa);
  lcd.print(stringa);
  lcd.print("/");
  dtostrf(workout.rep,3,0,stringa);
  lcd.print(stringa);

  // terza riga
  lcd.setCursor(0,2);
  lcd.print("Target ");
  dtostrf(target,2,0,stringa);
  lcd.print(stringa);
  lcd.print("/");
  dtostrf(NumTarget,2,0,stringa);
  lcd.print(stringa);

  // quarta riga
  lcd.setCursor(0,3);
  lcd.print("Bug ");
  dtostrf(bug,3,0,stringa);
  lcd.print(stringa);
  lcd.setCursor(11,3);
  lcd.print("Error ");
  dtostrf(errori,3,0,stringa);
  lcd.print(stringa);

  if (finito) {
    lcd.setCursor(14,0);
    lcd.print("FINISH");
  }
}

// funzione che fa il BEEP
void Beep(uint8_t num, uint32_t tipoSquillo) {
  for (int i=0;i<num;i++) {
    tone(BEEP_PIN,tipoSquillo,BEEP_DELAY);  // tone(pin,frequenza,durata);
    delay(BEEP_DELAY*2);
  }
} 

Infine la parte degli SLAVE
skecth principale

/********************************************************************************
PROGETTO LUCI ALLENAMENTO

Ricezione

- Arduino Nano / Pro Mini
- Modulo HC12

Organizzazione:
N 0 = master
N 1..n = slave

Modalità:
- Ciclica 123 123
- Reverse 12321
- Random

Parametri:
- Tempo acceso
- Tempo morto tra uno e l'altro
- Numero ripetizioni
- Tipo avviso (luce / beep)

Elenco pin:
-  0: riservato usb
-  1: riservato usb
-  2: Tm clk
-  3: Tm dio
-  4: Hc12 Rx
-  5: Hc12 Tx
-  6: Hc12 Set
-  7: Buzzer
-  8: Led verde
-  9: Led rosso
- 10: Dip-switch (pull-up)
- 11: Dip-switch (pull-up)
- 12: Dip-switch (pull-up)
- 13: 
- A0: 
- A1: 
- A2: 
- A3: Sensore Sharp
- A4: 
- A5: 
- A6: n/d su pro mini
- A7: n/d su pro mini
********************************************************************************/

// funzione calcolo CRC32 - grazie Guglielmo GPB01
#include "funz-crc32.h"

// ******************************************************************************
// DEFINIZIONE STRUTTURE DATI - deve essere uguale su trasmettitore e ricevitore
#include "datastruct.h"

// ******************************************************************************
// DEFINIZIONE COSTANTI COMANDI - STATI - deve essere uguale su trasmettitore e ricevitore
#include "define.h"

// ******************************************************************************
// FUNZIONI INVIO / RICEZIONE - deve essere uguale su trasmettitore e ricevitore
#include "comunicazione.h"

// librerie
#include <TM1637Display.h>
#include <SoftwareSerial.h>
//#include <avr/wdt.h>

// software reset per pro-mini
void(* SoftwareReset) (void) = 0;


// pin modulo HC12
#define HC12RxdPin  4 // Recieve Pin on HC12
#define HC12TxdPin  5 // Transmit Pin on HC12
#define HC12SetPin  6 // Transmit Pin on HC12

SoftwareSerial HC12(HC12TxdPin,HC12RxdPin); // Create Software Serial Port

// pin display TM1637
#define TMCLK  2
#define TMDIO  3

TM1637Display lcd(TMCLK, TMDIO);

// intervallo lampeggio
#define BLINK 500UL
// variabile millis per lampeggio
uint32_t blink_inizio;
// variabile per il lampeggio
bool vuoto = false;

// led
#define PINGRN  8
#define PINRED  9
#define COLOFF  0
#define COLGRN  1
#define COLRED  2
#define COLYLW  3

// buzzer
#define BEEP_PIN  7
#define BEEP_OK   4000
#define BEEP_DELAY 100

// DIP switch
#define PINDIP1 12
#define PINDIP2 11
#define PINDIP3 10
// numero di questo slave
uint8_t slave_id = 1;
// struttura per la trasmissione / ricezione dei dati
t_pack tx, rx;
// variabile per il risultato della trasmissione
uint8_t ricevuto;

// variabili allenamento
#define STATO_ATTESA 0
#define STATO_FIGHT  1
uint8_t stato;
uint32_t fight_inizio, fight_timeout;
#define ALERTTIMEOUT 900
bool alert = false;
uint32_t alert_inizio = 0;
uint32_t errori;

// variabili controllo sensore
#define SENSORE    A3
#define SENSMEDIA  5
#define SENSSOGLIA 550

// variabili varie di appoggio
bool finito;


void setup() {
  // seriale a 9600
  Serial.begin(9600);
  // HC12 a 9600
  HC12.begin(9600);
  // impostazione HC12
  pinMode(HC12SetPin,OUTPUT);
  digitalWrite(HC12SetPin,HIGH);  // LOW = AT mode - HIGH = modo normale
  delay(200);

  // buzzer
  pinMode(BEEP_PIN, OUTPUT);

  // dip switch
  pinMode(PINDIP1, INPUT_PULLUP);
  pinMode(PINDIP2, INPUT_PULLUP);
  pinMode(PINDIP3, INPUT_PULLUP);

  // leggo il valore del dip switch
  if (digitalRead(PINDIP1) == LOW) {
    slave_id += 1;
  }
  if (digitalRead(PINDIP2) == LOW) {
    slave_id += 2;
  }
  if (digitalRead(PINDIP3) == LOW) {
    slave_id += 4;
  }

  // led
  pinMode(PINGRN,OUTPUT);
  pinMode(PINRED,OUTPUT);
  AccendiLed(COLOFF);
  
  // imposto il display
  lcd.setBrightness(0x0a);
  lcd.clear();
  lcd.showNumberDecEx(slave_id,0b01000000,true,2,0);
  vuoto = false;
  blink_inizio = millis();
  
  // aspetto l'abbinamento col master
  finito = false;
  while (!finito) {
    ricevuto = Ricevi(HC12, (unsigned char *)&rx, DIMPACK);
    if (ricevuto == RX_OK) {
      // i dati sono arrivati
      // verifico il CRC
      if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
        // i dati sono validi
        // verifico che il comando sia corretto
        if (rx.dati.comando == CMD_CHECK) {
          // verifico che la richiesta sia per questo slave
          if (rx.dati.destinatario == slave_id) {
            // devo rispondere per confermare l'abbinamento
            tx.dati.idmsg = millis();
            tx.dati.destinatario = 0;
            tx.dati.comando = CMD_CHKOK;
            tx.dati.valore = 0;
            tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
            Trasmetti(HC12, (unsigned char *)&tx, DIMPACK);
            // posso uscire dal while
            finito = true;
          }
        }
      }
    }
    // lampeggio il numero slave
    if ((millis() - blink_inizio) > BLINK) {
      blink_inizio += BLINK;
      if (vuoto) {
        lcd.showNumberDecEx(slave_id,0b01000000,true,2,0);
      } else {
        lcd.clear();
      }
      vuoto = !vuoto;
    }
  } // while

  // abbinamento master ok
  // visualizzo il numero slave
  lcd.clear();
  lcd.showNumberDecEx(slave_id,0b01000000,true,2,0);  

  // aspetto lo START dal master
  finito = false;
  while (!finito) {
    ricevuto = Ricevi(HC12, (unsigned char *)&rx, DIMPACK);
    if (ricevuto == RX_OK) {
      // i dati sono arrivati
      // verifico il CRC
      if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
        // i dati sono validi
        // verifico che il comando sia corretto
        if (rx.dati.comando == CMD_START) {
          // verifico che la richiesta sia per questo slave
          if (rx.dati.destinatario == slave_id) {
            // posso uscire dal while
            finito = true;
          }
        }
      }
    }
  } // while

  alert = false;
  errori = 0;
  stato = STATO_ATTESA;
}

void loop() {

  switch (stato) {
    case STATO_ATTESA:
      // sono in attesa di comandi dal master
      ricevuto = Ricevi(HC12, (unsigned char *)&rx, DIMPACK);
      if (ricevuto == RX_OK) {
        // i dati sono arrivati
        // verifico il CRC
        if (rx.crc == calc_crc32((unsigned char *)&rx.dati, DIMDATI)) {
          // i dati sono validi
          // verifico che la richiesta sia per questo slave
          if (rx.dati.destinatario == slave_id) {
            // verifico il comando 
            switch (rx.dati.comando) {
              case CMD_LIGHT:
              case CMD_BEEP:
              case CMD_BOTH:
                // devo rispondere per confermare
                tx.dati.idmsg = millis();
                tx.dati.destinatario = 0;
                tx.dati.comando = CMD_TXOK;
                tx.dati.valore = 0;
                tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
                Trasmetti(HC12, (unsigned char *)&tx, DIMPACK);
                // devo eseguire l'azione
                switch (rx.dati.comando) {
                  case CMD_LIGHT:
                    AccendiLed(COLYLW);
                    // disabilito lo spegnimento del led alert
                    alert = false;
                    break;
                  case CMD_BEEP:
                    Beep();
                    break;
                  case CMD_BOTH:
                    AccendiLed(COLYLW);
                    Beep();
                    // disabilito lo spegnimento del led alert
                    alert = false;
                    break;
                }
                // imposto il tempo
                fight_inizio = millis();
                fight_timeout = rx.dati.valore * 1000;
                stato = STATO_FIGHT;                
                break;
              case CMD_STATUS:
                // comando per il polling
                // trasmetto gli errori
                tx.dati.idmsg = millis();
                tx.dati.destinatario = 0;
                tx.dati.comando = CMD_REPLY;
                tx.dati.valore = errori;
                tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
                Trasmetti(HC12, (unsigned char *)&tx, DIMPACK);
                break;
              case CMD_FINISH:
                // il workuot è finito
                // blocco tutto
                AccendiLed(COLOFF);
                while (1) {
                  if (VerificaSensore() > SENSSOGLIA) {
                    // resetto arduino
                    SoftwareReset();
                  }
                }
            } // switch
          } // if
        }
      } else {
        // controllo se devo spegnere il led di avviso
        if (alert && ((millis() - alert_inizio) > ALERTTIMEOUT)) {
          AccendiLed(COLOFF);
          alert = false;
        }
        // verifico se sono passato vicino al sensore mentre la luce è spenta
        if (!alert && (VerificaSensore() > SENSSOGLIA)) {
          // segnalo l'errore col led rosso
          AccendiLed(COLRED);
          // aumento gli errori
          errori++;
          AggiornaDisplay();
          alert = true;
          alert_inizio = millis();
        }
      }
      break;
    case STATO_FIGHT:
      // controllo il sensore entro il timeout previsto
      if ((millis() - fight_inizio) <= fight_timeout) {
        // controllo il sensore
        if (VerificaSensore() > SENSSOGLIA) {
          // se arrivo in tempo avviso che è ok col led verde
          AccendiLed(COLGRN);
          AggiornaDisplay();
          alert = true;
          alert_inizio = millis();
          // devo avvisare il master di non aspettare il resto del tempo 
          // e di passare subito al round successivo
          tx.dati.idmsg = millis();
          tx.dati.destinatario = 0;
          tx.dati.comando = CMD_FGHTOK;
          tx.dati.valore = 0;
          tx.crc = calc_crc32((unsigned char *)&tx.dati,DIMDATI);
          Trasmetti(HC12, (unsigned char *)&tx, DIMPACK);
          // torno nello stato attesa
          stato = STATO_ATTESA;
        }
      } else {
        // non sono arrivato in tempo
        // segnalo l'errore col led rosso
        AccendiLed(COLRED);
        // aumento gli errori
        errori++;
        AggiornaDisplay();
        alert = true;
        alert_inizio = millis();
        // torno nello stato attesa
        stato = STATO_ATTESA;
      }

      break;
  } // switch

}

funzioni mese in un tab separato

// funzione che accende il led del colore desiderato
// colore = colore da accendere
// uso un transistor bc327 per accendere i led, quindi logica invertita
void AccendiLed(uint8_t colore) {
  switch (colore) {
    case COLGRN:
      // logica diretta
      //digitalWrite(PINGRN, HIGH);
      //digitalWrite(PINRED, LOW);
      //logica invertita
      digitalWrite(PINGRN, LOW);
      digitalWrite(PINRED, HIGH);
      break;
    case COLRED:
      // logica diretta
      //digitalWrite(PINRED, HIGH);
      //digitalWrite(PINGRN, LOW);
      //logica invertita
      digitalWrite(PINRED, LOW);
      digitalWrite(PINGRN, HIGH);
      break;
    case COLYLW:
      // logica diretta
      //digitalWrite(PINGRN, HIGH);
      //digitalWrite(PINRED, HIGH);
      //logica invertita
      digitalWrite(PINGRN, LOW);
      digitalWrite(PINRED, LOW);
      break;
    default:
      // logica diretta
      //digitalWrite(PINGRN, LOW);
      //digitalWrite(PINRED, LOW);
      //logica invertita
      digitalWrite(PINGRN, HIGH);
      digitalWrite(PINRED, HIGH);
      break;
  }
}

// funzione che aggiorna il display
void AggiornaDisplay() {
  uint32_t temp;

  temp = ((slave_id % 100) * 100) + (errori % 100);
  lcd.showNumberDecEx(temp,0b01000000,true,4,0);  

}

// funzione che verifica il sensore
uint16_t VerificaSensore() {
  uint16_t media = 0;
  uint8_t i;

  for (i=0; i<SENSMEDIA; i++) {
    media += analogRead(SENSORE);
  }

  //Serial.println(media);
  return (media / SENSMEDIA);
}

// funzione che fa il BEEP
void Beep() {
  // buzzer passivo
  //tone(BEEP_PIN,BEEP_OK,BEEP_DELAY);  // tone(pin,frequenza,durata);

  // buzzer attivo
  digitalWrite(BEEP_PIN, HIGH);
  delay(BEEP_DELAY);
  digitalWrite(BEEP_PIN, LOW);
}

*/

Dovrei aver messo tutto.
Il codice è più o meno commentato. Se però qualcosa non è chiaro chiedi pure.
Ho fatto diversi test e secondo me funziona tutto... comunque se trovi qualcosa che non va segnalamelo che sistemo.

Se può servire posto anche gli schemi "elettrici"... anche se non sono fatti benissimo...

EDIT: dimenticavo... le funzioni per il crc-32 sono di Guglielmo. Lo ho spudoratamente copiate.

... hai fatto bene ... sono li apposta ... :grin:

Guglielmo

intanto ringrazio tutti per la loro disponibilita' e le loro risposte.
Sinceramente pensavo ad una cosa piu semplice tanto per cominciare e in base alle mie conoscenze e competenze.
In rete nel frattempo ho trovato questo gioco che adattato potrebbe fare al mio caso:


In merito ho alcune domande, al posto dei pulsanti posso mettere i sensori ir (che nel frattempo ho acquistato)?
Poi non riesco a capire cos'e' quell'oggetto sotto le tre resistenze a destra del disegno.
Allego anche il codice

int led1 = 2;
int led2 = 3;
int led3 = 4;
int led4 = 5;
int ledOdliczanie = 6;

int buttonPin1 = 10;
int buttonPin2 = 11;
int buttonPin3 = 12;
int buttonPin4 = 13;

int buttonState1;
int buttonState2;
int buttonState3;
int buttonState4;

int i;
int number = 0;
int penalty = 0;
int clickCounter = 0;
int allClicksCounter = 0;
int lvl = 0;
int minRndTime = 0;
int maxRndTime = 0;
int maxLed = 0;
int maxPenalties = 0;
int czasOdliczanie = 1000;
int mode = 0;
int clickFourthModeCounter = 0;
int missedBonks = 0;
int missedBonksInRow = 0;
int numGoodElements = 0;
int numBadElements = 0;

unsigned long actTime = 0;
unsigned long endTime = 0;
unsigned long wholeTime = 0;
unsigned long playerTime = 0;
unsigned long reactionTime = 0;
unsigned long fiveSecTime = 0;
unsigned long bonkRndTime = 0;
unsigned long bonkStartTime = 500;
unsigned long bonkWindowTime = 1000;

int val1 = 0;
int val11 = 0;
int val2 = 0;
int val21 = 0;
int val3 = 0;
int val31 = 0;

bool again = false;
bool btnPressedBefore = false;
bool bonkAdjusted = false;
bool bonkMissed = false;

String goodArray[] = {"Nice!", "Good One", "Excelent", "WOW", "Pure luck"};
String badArray[] = {"Wrong!", "Bad One", "Not Your day", "No luck", "LOL"};

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(0));

  // Deklaracja pinów LED
  for (i = 2; i <= 9; i++){
    pinMode(i, OUTPUT);
  }

  // Deklaracja pinów przycisków
  for (i = 10; i < 14; i++){
    pinMode(i, INPUT);
  }

  numGoodElements = (sizeof(goodArray) / sizeof(goodArray[0]));
  numBadElements = (sizeof(badArray) / sizeof(badArray[0]));
}

void loop() {
  //  **************************************  //
  //  This while is only for testing RGB led  //
  //  **************************************  //
  while (0>1){
    for (int x = 0; x < 1024; x++){
      int val = x;
      val1  = map(val, 0, 200, 0, 255);
      val11 = map(val, 201, 400, 255, 0);
      val2  = map(val, 300, 500, 0, 255);
      val21 = map(val, 501, 700, 255, 0);
      val3  = map(val, 600, 800, 0, 255);
      val31 = map(val, 801, 1023, 255, 0);
  
      // Wyłączenia
      if (val > 200)              {val1   = 0;};
      if (val < 200 || val > 400) {val11  = 0;};
      if (val < 300 || val > 500) {val2   = 0;};
      if (val < 500 || val > 700) {val21  = 0;};
      if (val < 600 || val > 800) {val3   = 0;};
      if (val < 800)              {val31  = 0;};
  
      // Deklaracje
      if      (val > 0    && val <= 200)  {analogWrite(7, val1);}
      else if (val > 200  && val <= 400)  {analogWrite(7, val11);}
      if      (val >= 300 && val <= 500)  {analogWrite(8, val2);}
      else if (val > 500  && val <= 700)  {analogWrite(8, val21);}   
      if      (val >= 600 && val <= 800)  {analogWrite(9, val3);}
      else if (val > 800  && val < 1023)  {analogWrite(9, val31);}
      if      (val == 0   || val == 1023) {analogWrite(7, 0);analogWrite(8, 0);analogWrite(9, 0);}
  
      delay(5);
    }
  }

  delay(1000);
  clickFourthModeCounter = 0;
  waitForAllLowDelay();
  while (mode == 0){
    Serial.println("Choose game mode: ");
    Serial.println("1. 20 moves, final score = average reaction time + penalty point * 20 ms.");
    Serial.println("2. 5 sec, make as many moves as possible, penalty points are substract from your score.");
    Serial.println("3. Infinite mode.");
    switch (clickFourthModeCounter){
      case 0:
        Serial.println("4. There is nothing.");
        break;
      case 1:
        Serial.println("4. There is nothing.");
        break;
      case 2:
        Serial.println("4. Looking for something, huh?.");
        break;
      case 3:
        Serial.println("4. Why You even try'in.");
        break;
      case 4:
        Serial.println("4. rly?");
        break;
    }
    waitForAnyHigh();
    buttonState();
    if (buttonState1 == HIGH) {
      mode = 1;
    } else if (buttonState2 == HIGH) {
      mode = 2;
    } else if (buttonState3 == HIGH) {
      mode = 3;
    }
    if (buttonState4 == HIGH) {
      mode = 0;
      clickFourthModeCounter += 1;
      if (clickFourthModeCounter == 5){
        Serial.println("NOW YOU GONNA PLAY BONK MODE!");
        Serial.println("LET'S GO!");
        mode = 4;
        minRndTime = 50;
        maxRndTime = 500;
        maxLed = 4 + 1;
      } else {
        Serial.println(" ");
        Serial.println("Choose correct mode (1-3): ");
      }
    } else {
      Serial.print("So You chose mode ");
      Serial.println(mode);
      Serial.println(" ");
    }
    waitForAllLowDelay();
  }

  waitForAllLow();
  while (again == false && mode != 4){
    delay(500);
    Serial.println("Choose difficulty level: ");
    switch (mode) {
      case (1):
        Serial.println("1. Easy - 3 LEDs + normal time to prepare.");
        Serial.println("2. Medium - 4 LEDs + normal time to prepare.");
        Serial.println("3. Hard - 4 LEDs + short time to prepare.");
        Serial.println("4. Fast Hard - 2 LEDs + short time to prepare.");
        break;     
      case (2):
        Serial.println("1. Easy - 2 LEDs.");
        Serial.println("2. Medium - 3 LEDs.");
        Serial.println("3. Hard - 4 LEDs.");
        Serial.println("4. Fast Hard - 4 LEDs + no time between LEDs.");
        break;
      case (3):
        Serial.println("1. Easy - 3 LEDs + normal time to prepare + max 7 wrong clicks.");
        Serial.println("2. Medium - 4 LEDs + normal time to prepare + max 5 wrong clicks.");
        Serial.println("3. Hard - 4 LEDs + short time to prepare + max 3 wrong clicks.");
        Serial.println("4. Fast Hard - 2 LEDs + short time to prepare + max 3 wrong clicks.");
        break;     
    }
  
    waitForAnyHigh();
    buttonState();
    if (buttonState1 == HIGH) { 
      lvl = 1;
      minRndTime = 500;
      maxRndTime = 2000;
      maxPenalties = 7;
      if (mode == 2) {maxLed = 2 + 1;} else {maxLed = 3 + 1;}
    } else if (buttonState2 == HIGH) {
      lvl = 2;
      minRndTime = 500;
      maxRndTime = 2000;
      maxPenalties = 5;
      if (mode == 2) {maxLed = 3 + 1;} else {maxLed = 4 + 1;}  
    } else if (buttonState3 == HIGH) {
      lvl = 3;
      minRndTime = 50;
      maxRndTime = 250;
      maxPenalties = 3;
      if (mode == 2) {maxLed = 4 + 1;} else {maxLed = 4 + 1;}    
    } else {
      lvl = 4;
      minRndTime = 50;
      maxRndTime = 250;
      maxPenalties = 3;
      if (mode == 2) {maxLed = 4 + 1;} else {maxLed = 2 + 1;}
    } 
    waitForAllLowDelay();
  
    Serial.print("So You chose lvl ");
    Serial.println(lvl);
    again = true;
  }

  if (mode != 4){
    waitForAllLowDelay();
    Serial.println("Press any button when You are ready!");
    waitForAnyHigh();
    Serial.println("Get READY!");
  }
  odliczanie();

  fiveSecTime = millis() + 5050;

  // Główna pętla gry, program wychodzi z niej w momencie końca gry
  while (true) {
    if (mode == 2){
      if (lvl == 4) {
        delay(5);
        }
      else {
        delay(50);
        } 
    } else {
      delay(random(minRndTime, maxRndTime));
    }
    
    actTime = millis();
    
    if (mode == 4 && allClicksCounter == 5){
      bonkAdjusted = true;
      if (clickCounter == 0){
        bonkWindowTime = 1500;
        bonkStartTime = 500;
        }
      else {
        bonkWindowTime = (wholeTime / clickCounter) * 1.5;
        bonkStartTime = (wholeTime / clickCounter) * 0.7;
        }
    }
    
    if (bonkMissed) {
      bonkMissed = false;
      missedBonks += 1;
      if (bonkAdjusted) {
        bonkWindowTime = bonkWindowTime * 1.2;
        bonkStartTime = bonkStartTime * 1.2;
      }
    }
    
    bonkRndTime = millis() + random(bonkStartTime, (bonkStartTime + bonkWindowTime));   
//    Serial.println(bonkStartTime);
//    Serial.println(bonkWindowTime);
    
    buttonState();
    if (buttonState1 == LOW && buttonState2 == LOW && buttonState3 == LOW && buttonState4 == LOW) {
      lightLED();
      waitForAnyHighInGame();
      switch (number) {
        buttonState();
        case 1:
          if (buttonState1 == HIGH) {
            dobrze();
          } else {
            dodajKare();
          }
          digitalWrite(led1, LOW);
          break;
        case 2:
          if (buttonState2 == HIGH) {
            dobrze();
          } else {
            dodajKare();
          }
          digitalWrite(led2, LOW);
          break;
        case 3:
          if (buttonState3 == HIGH) {
            dobrze();
          } else {
            dodajKare();
          }
          digitalWrite(led3, LOW);
          break;
        case 4:
          if (buttonState4 == HIGH) {
            dobrze();
          } else {
            dodajKare();
          }
          digitalWrite(led4, LOW);
          break;  
    }
    waitForAllLow();
    
    } else {
      Serial.println("Button pressed before the game!");
      btnPressedBefore = true;
      dodajKare();
      waitForAllLow();
    }
//     Serial.println(missedBonksInRow);
    // Pętla kończąca grę
    if ((mode == 1 && allClicksCounter == 20) || 
        (mode == 2 && millis() >= fiveSecTime) || 
        (mode == 3 && penalty == maxPenalties) ||
        (mode == 4 && allClicksCounter == 40) ||
        (mode == 4 && missedBonksInRow >= 4)) {
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      digitalWrite(led4, HIGH);
      if (mode == 3){   
      Serial.println("Game over!");
      } else {
        Serial.println("The end!");
      }
      Serial.print("You did ");
      Serial.print(clickCounter);
      Serial.print("/");
      Serial.print(allClicksCounter);
      Serial.print(" right clicks with average time ");
      if (clickCounter == 0) {
        Serial.print("-");
      } else {
      Serial.print(wholeTime / clickCounter);
      }
      Serial.println(" ms/click");
      
      if (mode == 4) {
        Serial.print("And You missed ");
        Serial.print(missedBonks);
        Serial.println(" Bonks");
      }
      
      if (mode == 1 || mode == 2){
        Serial.print("Your final score is: ");
        if (mode == 1) {
          Serial.println((wholeTime / clickCounter) + (penalty * 20));
        } else if (mode == 2) {
          Serial.println(clickCounter - penalty);
        }
      }
      Serial.println("");
      
      if (mode == 4) {
        Serial.println("Wanna try again?");
        Serial.println("1. Gimme more");
        Serial.println("2. Momy take me from here");
      } else {
        Serial.print("Actual mode ");
        Serial.print(mode);
        Serial.print(" with difficulty ");
        Serial.println(lvl);
        Serial.println("Press button 1 to start again in the same mode and with the same difficulty."); 
        Serial.println("Press button 2 to change only difficulty level in mode You just played."); 
        Serial.println("Press button 3 to change game mode and difficulty level.");
        Serial.println("");
      }
      waitForAllLowDelay();
      delay(1000);

      while (true) {
        waitForAnyHigh();
        if (buttonState1 == HIGH){
          again = true;
          break;
        } else if (buttonState2 == HIGH && mode != 4){
          again = false;
          break;
        } else if (buttonState3 == HIGH && mode != 4){
          again = false;
          mode = 0;
          break;
        } else if (mode == 4 && buttonState2 == HIGH){
          again = false;
          mode = 0;
          break;
        } else if (mode == 4 && (buttonState3 == HIGH || buttonState4 == HIGH )){
          Serial.println("Press correct button (1-2).");
          Serial.println(" ");
          waitForAllLowDelay();
          clickFourthModeCounter += 1;
          if (clickFourthModeCounter == 5){
            Serial.println("FUCK YOU");
            delay(100);
            exit(0);
          }
        } else {
          Serial.println("Press correct button (1-3).");
          Serial.println(" ");
          waitForAllLow();
          clickFourthModeCounter += 1;
          if (clickFourthModeCounter == 5){
            Serial.println("FUCK YOU");
            delay(100);
            exit(0);
          }
        }
      }

      waitForAllLowDelay();
      missedBonksInRow = 0;
      missedBonks = 0;
      penalty = 0;
      wholeTime = 0;
      clickCounter = 0;
      allClicksCounter = 0;
      bonkAdjusted = false;
      bonkStartTime = 500;
      bonkWindowTime = 1000;
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      break;
    }
  }
}

void dobrze() {
  clickCounter += 1;
  allClicksCounter += 1;
  playerTime = Time(actTime);
  wholeTime += playerTime;
  Serial.println(goodArray[random(0, numGoodElements)]);
  Serial.print("Your reaction time: ");
  Serial.print(playerTime);
  Serial.println(" ms");
  Serial.print("Your average reaction time: ");
  Serial.print(wholeTime / clickCounter);
  Serial.println(" ms"); 
  Serial.println("");
  if (bonkAdjusted) {
    if (playerTime <= (wholeTime / clickCounter)){
      bonkStartTime = bonkStartTime * 0.85;
      bonkWindowTime = bonkWindowTime * 0.85;
    }
      bonkStartTime = bonkStartTime * 0.95;
      bonkWindowTime = bonkWindowTime * 0.95;
  }
  missedBonksInRow = 0;
}

void dodajKare() {
  if (btnPressedBefore == false){
    Serial.println(badArray[random(0, numBadElements)]);
  }
  if (bonkMissed) {Serial.println("LOSER");}
  if (bonkAdjusted && !bonkMissed) {
    bonkStartTime = bonkStartTime * 1.2;
    bonkWindowTime = bonkWindowTime * 1.2;
    }
  penalty += 1;
  allClicksCounter += 1;
  Serial.println("1 penalty point has been added.");
  Serial.print("Total penalty points: ");
  Serial.println(penalty); 
  Serial.println("");
  btnPressedBefore = false;
}

void lightLED() {
  switch (number = random(1, maxLed)) {
    case 1:
      digitalWrite(led1, HIGH);
      break;
    case 2:
      digitalWrite(led2, HIGH);
      break;
    case 3:
      digitalWrite(led3, HIGH);
      break;
    case 4:
      digitalWrite(led4, HIGH);
      break;
  }
}

void odliczanie() {
  for (int j = 0; j < 3; j++){
    digitalWrite(ledOdliczanie, HIGH);
    delay(czasOdliczanie);
    digitalWrite(ledOdliczanie, LOW);
    delay(czasOdliczanie);
  }
}

unsigned long Time(unsigned long startTime) {
  endTime = millis();
  reactionTime = endTime - startTime;
  return reactionTime;
}

void waitForAnyHigh() {
  while (buttonState1 == LOW && buttonState2 == LOW && buttonState3 == LOW && buttonState4 == LOW) {
    buttonState();
  }
}

void waitForAnyHighInGame() {
  while (buttonState1 == LOW && buttonState2 == LOW && buttonState3 == LOW && buttonState4 == LOW) {
    buttonState();
    if  (mode == 4 && millis() >= bonkRndTime) {
      bonkMissed = true;
      missedBonksInRow += 1;
      break;
    }
    if ((mode == 2 && millis() >= fiveSecTime) || (millis() >= (actTime + 5000))) {
      break;
    }
  }
}

void waitForAllLow() {
  while (buttonState1 == HIGH || buttonState2 == HIGH || buttonState3 == HIGH || buttonState4 == HIGH) {
    buttonState();
  }
}

void waitForAllLowDelay() {
  waitForAllLow();
  delay(250);
  waitForAllLow();
}

void buttonState() {
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);
  buttonState4 = digitalRead(buttonPin4);
}

grazie a tutti di nuovo

Un led RGB:


Ciao, Ale.

grazie , lo avevo appena individuato e montato, ma non da segni di vita.....

Deve essere a catodo comune.