// Definizione dei pin per il display a 7 segmenti
const int pinDisplay[] = {2, 3, 4, 5, 6, 7, 8};
const int numRighe = 4; // Numero di righe della matrice dei tasti
const int numColonne = 3; // Numero di colonne della matrice dei tasti
// Matrice dei tasti sulla tastiera
char tasti[numRighe][numColonne] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
// Mappa dei segmenti per visualizzare i numeri da 0 a 9 sul display a 7 segmenti
const byte mappaPunteggio[] = {
0B1000000, // 0
0B1111001, // 1
0B0100100, // 2
0B0110000, // 3
0B0011001, // 4
0B0010010, // 5
0B0000010, // 6
0B1111000, // 7
0B0000000, // 8
0B0010000 // 9
};
// Definizione dei pin per le righe e le colonne della tastiera
const int pinTastiRiga[] = {9, 10, 11, 12};
const int pinTastiCol[] = {0, 1, 13};
extern unsigned long timer0_millis; // Dichiarazione di una variabile esterna per il tempo
volatile unsigned long tempoInizioInput; // Variabile per memorizzare il tempo di inizio dell'input
volatile bool tempoScaduto = false; // Flag per indicare se il tempo è scaduto
volatile bool giocoAttivo = false; // Flag per indicare se il gioco è attivo
volatile bool displayAttivo = false;
bool visualizzazioneNumeriCasuali = true; // Flag per indicare se stanno venendo visualizzati numeri casuali
volatile int punteggio = 0; // Punteggio del giocatore
char codiceGenerato[7]; // Array per memorizzare il codice generato casualmente
char inputUtente[7]; // Array per memorizzare l'input dell'utente
int intervalloIniziale = 1000; // Intervallo iniziale tra la visualizzazione dei numeri casuali
int indiceInputUtente = 0; // Indice per l'input dell'utente
int conteggioVittorie = 0; // Conteggio delle vittorie
static unsigned long ultimoTempo = 0; // Variabile per memorizzare l'ultimo tempo
// Funzione di setup che viene eseguita una sola volta all'avvio
void setup() {
// Configurazione del timer 0 per generare un'interruzione ogni millisecondo
TCCR0A = 0;
TCCR0B = (1 << CS01) | (1 << CS00);
OCR0A = 124;
TIMSK0 |= (1 << OCIE0A);
Serial.begin(115200);
// Inizializzazione dei pin del display e dei tasti
for (int i = 0; i < 7; i++) {
pinMode(pinDisplay[i], OUTPUT);
digitalWrite(pinDisplay[i], HIGH);
}
for (int i = 0; i < numRighe; i++) {
pinMode(pinTastiRiga[i], OUTPUT);
digitalWrite(pinTastiRiga[i], HIGH);
}
for (uint16_t i = 0; i < numColonne; i++) {
pinMode(pinTastiCol[i], INPUT_PULLUP);
}
randomSeed(analogRead(0));
}
void loop() {
unsigned long millisCorrente = millis(); // Ottenimento del tempo attuale in millisecondi
// Gestione del gioco quando non è attivo
if (!giocoAttivo) {
char tasto = verificaTasti(); // Verifica se vengono premuti tasti
// Avvia un nuovo gioco se viene premuto il tasto '*' o reimposta il punteggio se viene premuto il tasto '#'
if (tasto == '*') {
displayAttivo = true;
avviaGioco();
tempoInizioInput = 0;
tempoScaduto = false;
TIMSK0 |= (1 << OCIE0A);
} else if (tasto == '#') {
punteggio = 0;
displayAttivo = true;
visualizzaCifra(punteggio);
}
} else {
// Gestione del gioco quando è attivo
char tasto = verificaTasti(); // Verifica se vengono premuti tasti
if (tasto != '\0') {
inputUtente[indiceInputUtente++] = tasto; // Memorizza l'input dell'utente
// Verifica se è stato superato il tempo limite per l'input
if (indiceInputUtente > 0 && tempoScaduto) {
giocoAttivo = false;
displayAttivo = false;
visualizzazioneNumeriCasuali = false;
indiceInputUtente = 0;
visualizzaCifra(punteggio);
Serial.println("Tempo scaduto!");
}
// Verifica se è stata inserita la sequenza completa
if (indiceInputUtente == 6) {
if (strncmp(inputUtente, codiceGenerato, 6) == 0) {
punteggio++;
conteggioVittorie++;
tempoInizioInput = 0;
tempoScaduto = false;
TIMSK0 |= (1 << OCIE0A);
}
visualizzazioneNumeriCasuali = false;
indiceInputUtente = 0;
giocoAttivo = false;
displayAttivo = false;
visualizzaCifra(punteggio);
}
}
}
}
// Funzione per avviare il gioco
void avviaGioco() {
visualizzazioneNumeriCasuali = true;
// Genera una sequenza casuale di numeri
for (int i = 0; i < 6; i++) {
codiceGenerato[i] = random(10) + '0';
}
// Visualizza il conteggio delle vittorie
visualizzaCifra(conteggioVittorie);
// Visualizza la sequenza casuale di numeri per un breve periodo
for (int i = 0; i < 6; i++) {
visualizzaCifra(codiceGenerato[i]);
attesa(intervalloIniziale );
}
// Imposta lo stato del gioco
giocoAttivo = true;
visualizzazioneNumeriCasuali = false;
indiceInputUtente = 0;
visualizzaCifra(punteggio);
}
// Funzione per visualizzare una cifra sul display a 7 segmenti
void visualizzaCifra(char cifra) {
int indiceCifra = cifra - '0';
// Controlla se la cifra è valida
if (indiceCifra >= 0 && indiceCifra <= 9 ) {
byte valoreDisplay = mappaPunteggio[indiceCifra];
for (int i = 0; i < 7; i++) {
digitalWrite(pinDisplay[i], bitRead(valoreDisplay, i));
}
}
// Visualizza il punteggio se è compreso tra 0 e 9
else if (punteggio >= 0 && punteggio <= 9) {
byte valoreDisplay = mappaPunteggio[punteggio];
for (int i = 0; i < 7; i++) {
digitalWrite(pinDisplay[i], bitRead(valoreDisplay, i));
}
}
}
// Funzione per verificare se vengono premuti dei tasti sulla tastiera
char verificaTasti() {
for (int riga = 0; riga < numRighe; riga++) {
digitalWrite(pinTastiRiga[riga], LOW);
for (int colonna = 0; colonna < numColonne; colonna++) {
if (digitalRead(pinTastiCol[colonna]) == LOW) {
attesa(500);
char tasto = tasti[riga][colonna];
while (digitalRead(pinTastiCol[colonna]) == LOW) {}
digitalWrite(pinTastiRiga[riga], HIGH);
return tasto;
}
}
digitalWrite(pinTastiRiga[riga], HIGH);
}
return '\0';
}
// Funzione per attendere un certo periodo di tempo
void attesa(unsigned long durata) {
unsigned long millisInizio = millis();
while (millis() - millisInizio < durata) {
// Attendi senza fare nulla
}
}
// Interrupt Service Routine (ISR) per gestire l'interruzione del timer 0
ISR(TIMER0_COMPA_vect) {
// Controlla se il gioco è attivo e se si sta visualizzando una sequenza casuale di numeri
if (giocoAttivo && visualizzazioneNumeriCasuali) {
static unsigned long ultimoTempo = 0;
static int indiceNumero = 0;
static unsigned long intervalloVisualizzazione = 500;
// Verifica se è il momento di visualizzare il prossimo numero casuale
if (millis() - ultimoTempo >= intervalloVisualizzazione) {
visualizzaCifra(codiceGenerato[indiceNumero]);
indiceNumero++;
ultimoTempo = millis();
// Se tutti i numeri sono stati visualizzati, disattiva la visualizzazione casuale
if (indiceNumero >= 6) {
visualizzazioneNumeriCasuali = false;
}
if (giocoAttivo) {
verificaTasti(); // Controlla se vengono premuti tasti durante la visualizzazione
}
}
} else if (giocoAttivo && !visualizzazioneNumeriCasuali) {
// Visualizzazione del punteggio
// Spegni il display
for (int i = 0; i < 7; i++) {
digitalWrite(pinDisplay[i], HIGH);
}
// Verifica se è trascorso un certo periodo dall'ultima visualizzazione casuale
if (millis() - ultimoTempo >= 2000) {
visualizzaCifra(punteggio); // Visualizza il punteggio attuale
// Riaccendi il display
for (int i = 0; i < 7; i++) {
digitalWrite(pinDisplay[i], bitRead(mappaPunteggio[punteggio], i));
}
// Aggiorna l'ultimo tempo di visualizzazione casuale
ultimoTempo = millis();
}
// Controlla se è trascorso il tempo massimo per l'input
tempoInizioInput++;
if (tempoInizioInput >= 10000) {
tempoScaduto = true; // Imposta il flag per indicare che il tempo è scaduto
TIMSK0 &= ~(1 << OCIE0A); // Disabilita l'interrupt del timer 0 per evitare ulteriori chiamate all'ISR
}
}
}