IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

1 programme - 1 décompte temps - 2 jeux successifs


Sujet :

Arduino

  1. #1
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut 1 programme - 1 décompte temps - 2 jeux successifs
    Bonjour à vous,
    voici quelques temps, que je programme plusieurs codes afin de réaliser au final, une sorte d'escape game.

    Ce programme pour le moment va se composer de 3 parties:
    - 1 partie décompte, qui va fonctionner, avec affichage sur la première ligne du LCD. La seconde ligne LCD dira quoi faire dans le jeu en cours
    - jeu n° 1: "connexion fils LED"
    - jeu n° 2:"flasher le bon tag/carte sur RFID"


    Je ne sais pas trop comment m'y prendre.

    Pour le début, il faut tout déclarer:
    variable #define include

    Pour void setup(), pareil?

    Ensuite, je pense faire une fonction par jeu du type ConnexFilsLed() et TagRfid()
    Dans la fonction ConnexFilsLed(), fainre un appel TagRfid(), quand tous les fils sont bien connectés.

    Puis dans le void loop()
    -affichage temps
    -ConnexFilsLed(); TagRfid() sera appelé quand tous les fils seront bien connectés.

    Suis-je sur le bon chemin où faut-il s'y prendre différemment?

    Merci pour vos retours

  2. #2
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Citation Envoyé par hugobeauce Voir le message
    Bonjour à vous,
    Ce programme pour le moment va se composer de 3 parties:
    - 1 partie décompte, qui va fonctionner, avec affichage sur la première ligne du LCD. La seconde ligne LCD dira quoi faire dans le jeu en cours
    - jeu n° 1: "connexion fils LED"
    - jeu n° 2:"flasher le bon tag/carte sur RFID"


    Je ne sais pas trop comment m'y prendre.
    Bonjour @hugobeauce

    vous allez emmener de la complication, donc il faut absolument une structuration de code "propre". Qu'est-ce qui fait partie du programme principal, qu'est-ce qu'un jeu etc...

    Tel que vous le décrivez, le programme principal est responsable de la gestion du temps, d'une ligne du LCD, du choix du jeu. Ensuite vous devez passer la main à un jeu. Pour que le jeu + le programme principal tournent en même temps, vous ne pouvez pas avoir une programmation de type bloquant et donc le plus simple est de prendre l'approche d'une machine à états finis de haut niveau, qui ressemblerait à un programme Arduino standard avec un setup() et une loop() par fonction (menu, jeu1, jeu2, ....)

    Le programme principal se charge alors de maintenir les fonctions essentielles du code (la première ligne du LCD, gestion du temps, gestion de la tâche active et transitions entre tâches) et chaque tâche doit être codée proprement pour ne pas être bloquante et tourner sur le principe que sa loop() effectue une petite action à la fois.

    ça pourrait alors ressembler à ce code. Si vous le lancez avec le moniteur Série à 115200 bauds, vous verrez une premiere tâche prend la main, il s'agit d'un menu général qui vous demande de taper (dans la console) 1 pour choisir le jeu 1 ou 2 pour choisir le jeu 2.
    Vous verrez un temps global en secondes qui défile toutes les secondes
    Vous verrez aussi un temps local dans cet état (au sein du menu) qui défile toutes les 5 secondes

    Quand vous tapez 1 et validez, le Menu se termine et vous changez d'état. Un changement d'état consiste à appeler finXXX() pour terminer proprement la tâche en cours, puis d'appeler le setupXXX() du nouvel état et enfin de manière régulière sa loopXXX().

    Dans mon exemple j'ai choisi de faire que JEU1 fait comme JEU2 (et comme le MENU). J'affiche un message disant "tapez F pour finir le Jeu" et puis je compte toutes les 5 secondes le temps passé dans ce JEU (C'est exactement le même code que pour le menu aux variables près).

    Quand vous tapez 'F' et validez, le Jeu #1 se termine et vous changez d'état pour retourner au MENU. Un changement d'état consiste à appeler finXXX() pour terminer proprement la tâche en cours donc ici finJeu1(), puis d'appeler le setupXXX() du nouvel état donc ici setupMenu() et enfin de manière régulière sa loopXXX() donc ici loopMenu().

    Pour le Jeu2 c'est exactement la même chose.

    Je vous laisse regarder le code et jouer un peu avec en tapant 1, F puis 2 puis F etc....

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    const uint16_t battementCoeur = 1000U;
    uint32_t chronometre = 0;
     
    enum t_etatJeu : byte {INCHANGE = 0, MENU, JEU1, JEU2} etatGlobal = MENU;
     
    // ****************************
    //            MENU
    // ****************************
    uint32_t debutChronoMenu;
    uint32_t tickMenu;
     
    void setupMenu()
    {
      debutChronoMenu = millis();
      tickMenu = debutChronoMenu;
      Serial.println(F("\n\n************ MENU ************"));
      Serial.println(F("1\tJEU #1"));
      Serial.println(F("2\tJEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
     
    t_etatJeu loopMenu()
    {
      // faire une étape de la tâche courante
      if (millis() - tickMenu >= battementCoeur * 5) {
        Serial.print(F("\tDANS MENU DEPUIS: "));
        Serial.println((millis() - debutChronoMenu) /  1000);
        tickMenu += battementCoeur * 5;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == '1') return JEU1;
      if (c == '2') return JEU2;
      return INCHANGE;
    }
     
    void finMenu()
    {
      Serial.println(F("\tFIN MENU"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 1
    // ****************************
    uint32_t debutChronoJeu1;
    uint32_t tickJeu1;
     
    void setupJeu1()
    {
      debutChronoJeu1 = millis();
      tickJeu1 = debutChronoJeu1;
      Serial.println(F("\n\n************ JEU #1 **********"));
      Serial.println(F("F\tFIN JEU #1"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
     
    t_etatJeu loopJeu1()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu1 >= battementCoeur * 5) {
        Serial.print(F("\tDANS JEU #1 DEPUIS: "));
        Serial.println((millis() - debutChronoJeu1) /  1000);
        tickJeu1 += battementCoeur * 5;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
    }
     
    void finJeu1()
    {
      Serial.println(F("\tFIN JEU #1"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 2
    // ****************************
    uint32_t debutChronoJeu2;
    uint32_t tickJeu2;
     
    void setupJeu2()
    {
      debutChronoJeu2 = millis();
      tickJeu2 = debutChronoJeu2;
      Serial.println(F("\n\n************ JEU #2 **********"));
      Serial.println(F("F\tFIN JEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
     
    t_etatJeu loopJeu2()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu2 >= battementCoeur * 5) {
        Serial.print(F("\tDANS JEU #2 DEPUIS: "));
        Serial.println((millis() - debutChronoJeu2) /  1000);
        tickJeu2 += battementCoeur * 5;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
    }
     
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
    // ****************************
    //         UTILITAIRES
    // ****************************
    void gestionGlobale()
    {
      // Gestion de l'écran toutes les "battementCoeur"
      if (millis() - chronometre >= battementCoeur) {
        Serial.print(F("TEMPS GLOBAL: "));
        Serial.println(millis() / 1000);
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW); // inverse l'état de la LED, on clignote
        chronometre += battementCoeur;
      }
    }
     
    void etablirNouvelEtat(t_etatJeu nouvelEtat)
    {
      switch (nouvelEtat) {
        case MENU:
          setupMenu();
          etatGlobal = MENU;
          break;
        case JEU1:
          setupJeu1();
          etatGlobal = JEU1;
          break;
        case JEU2:
          setupJeu2();
          etatGlobal = JEU2;
          break;
        default: break; // on reste dans cet état
      }
    }
     
    void gestionEtat()
    {
      switch (etatGlobal) {
        case MENU:      // attente d'un choix
          {
            t_etatJeu nouvelEtat = loopMenu();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le MENU proprement
              finMenu();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
     
        case JEU1:
          {
            t_etatJeu nouvelEtat = loopJeu1();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le JEU1 proprement
              finJeu1();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
     
        case JEU2:
          {
            t_etatJeu nouvelEtat = loopJeu2();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le JEU2 proprement
              finJeu2();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
      }
    }
     
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
      etablirNouvelEtat(MENU);
    }
     
     
    void loop()
    {
      gestionGlobale();
      gestionEtat();
    }
    Notez qu'on voit bien que j'ai bcp dupliqué de code dans et que tout cela serait généralisable à N jeux sans rajouter du code mais en gérant le changement de contexte.
    Pour cela il faudrait introduire un tableau de pointeur sur les fonctions setupXXX(), loopXXX() et finXXX() et simplement gérer un indice courant de la tâche en cours.

    Je ne l'ai pas fait car sa complique la lecture et pour 3 tâches (menu, jeu1, jeu2) ça reste gérable, mais si vous voulez généraliser à 10 tâches alors il sera bon de passer à une structure de tableaux.

    en espérant que ça vous aide à y voir plus clair !

  3. #3
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 017
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 017
    Par défaut
    Bonjour Hugo

    Il faut faire une chose après l'autre et, ensuite, les imbriquer.
    Pour l'affichage, inspires-toi sur un exemple de la bibliothèque, souvent le "Hello Word!", pour initialiser ton affichage (C'est un i2C ?)
    Pour le décomptage, regardes du côté de milli(), mis dans loop().
    Initialises les moyens (boutons poussoir, bouton rotatif...) pour démarrer le décomptage.

    Une fois l'affichage opérationnel, mets le dans un post afin que l'on puisse en discuter.

    A+
    Cordialement
    jpbbricole

  4. #4
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    Bonjour JayM et jpbricole,

    Comme vous avez participé à tous mes posts précédents, vous avez une idée des différentes fonctions.
    Je prends bonne note de vos commentaires.
    J'essaie tout ça et reviens vers vous.

    Au total, je compte 6 "jeux" à la suite. Donc peut être partir sur la base d'un tableau ?

  5. #5
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 017
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 017
    Par défaut
    Citation Envoyé par hugobeauce Voir le message
    Au total, je compte 6 "jeux" à la suite. Donc peut être partir sur la base d'un tableau ?
    Voir même de structures.

    Cordialement
    jpbbricole

  6. #6
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Citation Envoyé par hugobeauce Voir le message
    Au total, je compte 6 "jeux" à la suite. Donc peut être partir sur la base d'un tableau ?
    Oui, dans ce cas partez plutôt avec cette version du code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    typedef  int16_t t_taskID;
    const t_taskID INCHANGE = -1;
    
    typedef void (*t_setupFunc)();      // on défint le type t_setupFunc comme pointeur sur fonction retournant rien
    typedef t_taskID (*t_loopFunc)();  // on défint le type t_loopFunc comme pointeur sur fonction retournant un N°de tâche
    typedef void (*t_cleanupFunc)();    // on défint le type t_cleanupFunc comme pointeur sur fonction retournant rien
    
    // une tâche va consister en 3 pointeurs de fonctions
    struct t_task {
      t_setupFunc taskSetup;
      t_loopFunc taskLoop;
      t_cleanupFunc taskCleanUp;
    };
    
    // *********************************************
    // pour pouvoir définir le tableau des tâches
    // On pré-annonce les fonctions de nos tâches. (forward declaration)
    // Leur code viendra plus tard.
    
    // le Menu
    void setupMenu();
    t_taskID loopMenu();
    void finMenu();
    
    // le jeu 1
    void setupJeu1();
    t_taskID loopJeu1();
    void finJeu1();
    
    // le Jeu2
    void setupJeu2();
    t_taskID loopJeu2();
    void finJeu2();
    // *********************************************
    
    // définir le tableau des tâches
    t_task taskList[] = {
      {setupMenu, loopMenu, finMenu},
      {setupJeu1, loopJeu1, finJeu1},
      {setupJeu2, loopJeu2, finJeu2}
    };
    
    // définir les N° de nos tâches avec un nom parlant, ça simplifie la lecture du code.
    enum : t_taskID {MENU, JEU1, JEU2};
    
    
    // ****************************
    //         UTILITAIRES
    // ****************************
    
    // on calcule le nombre de tâches définies
    uint16_t taskCount = sizeof(taskList) / sizeof(taskList[0]);
    t_taskID currentTask;
    uint32_t currentTaskStartTime;
    
    void etablirNouvelleTache(t_taskID nouvelleTache)
    {
      if (nouvelleTache >= taskCount) return;     // nouvelleTache n'existe pas
      currentTaskStartTime = millis();
      currentTask = nouvelleTache;
      taskList[currentTask].taskSetup();
    }
    
    
    void gestionEtat()
    {
      t_taskID nouvelleTache = taskList[currentTask].taskLoop();   // on fait un tour de loop de la tâche
    
      if (nouvelleTache != INCHANGE) {          // demande de changement
        taskList[currentTask].taskCleanUp();   // on termine la tâche en cours  proprement
        etablirNouvelleTache(nouvelleTache);    // on bascule vers la nouvelle tâche
      }
    }
    
    
    // ****************************
    //     TÂCHE GLOBALE
    // ****************************
    const uint16_t pulsation = 500U; // 1Hz
    uint32_t chronometre = 0;
    
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW); // inverse l'état de la LED, on clignote
        chronometre += pulsation;
      }
      // VOUS POUVEZ FAIRE AUTRE CHOSE ICI, C'EST APPELE A CHAQUE TOUR DE LOOP GLOBALE
    }
    
    
    // ****************************
    //            MENU
    // ****************************
    uint32_t tickMenu;
    
    void setupMenu()
    {
      tickMenu = currentTaskStartTime;
      Serial.println(F("\n\n************ MENU ************"));
      Serial.println(F("1\tJEU #1"));
      Serial.println(F("2\tJEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
    
    t_taskID loopMenu()
    {
      // faire une étape de la tâche courante
      if (millis() - tickMenu >= 5000U) {
        Serial.print(F("\tDANS MENU DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        tickMenu += 5000U;
      }
    
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == '1') return JEU1; // index du Jeu 1
      if (c == '2') return JEU2; // index du Jeu 2
      return INCHANGE;
    }
    
    void finMenu()
    {
      Serial.println(F("\tFIN MENU"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
    
    
    // ****************************
    //            JEU 1
    // ****************************
    uint32_t tickJeu1;
    
    void setupJeu1()
    {
      tickJeu1 = currentTaskStartTime;
      Serial.println(F("\n\n************ JEU #1 **********"));
      Serial.println(F("F\tFIN JEU #1"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
    
    t_taskID loopJeu1()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu1 >= 5000U) {
        Serial.print(F("\tDANS JEU #1 DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        tickJeu1 += 5000U;
      }
    
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
    }
    
    void finJeu1()
    {
      Serial.println(F("\tFIN JEU #1"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
    
    
    // ****************************
    //            JEU 2
    // ****************************
    uint32_t tickJeu2;
    
    void setupJeu2()
    {
      tickJeu2 = currentTaskStartTime;
      Serial.println(F("\n\n************ JEU #2 **********"));
      Serial.println(F("F\tFIN JEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
    
    t_taskID loopJeu2()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu2 >= 5000U) {
        Serial.print(F("\tDANS JEU #2 DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        tickJeu2 += 5000U;
      }
    
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
    }
    
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
    
    
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
    
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
    
      // AUTRES INITIALISATIONS
    
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(MENU);
    }
    
    
    void loop()
    {
      gestionGlobale();
      gestionEtat();
    }
    il vous faudra bien comprendre le premier exemple que j'ai donné ci dessous et comment ça fonctionne car ce code en est une généralisation.

    j'ai enlevé l'affichage du temps qui passe toutes les secondes dans la tâche globale, je garde juste la LED qui clignote à 1Hz

    Le reste fonctionne comme avant. Les tâches ont accès à une variable globale qui est gérée par le système "currentTaskStartTime" qui donne l'heure de départ de notre tâche en cours.

    Une fois que vous avez capté, il suffit de définir les parties du code en vert (et bien sûr vous assurer que votre fonction 'loop' de chaque tâche retourne soit INCHANGE quand on continue dans la tâche, soit un nouveau N° de tâche)

    J'ai mis en vert dans le code ci dessus ce qui est spécifique à votre programme. (définition des fonctions, du tableau des tâches, de petits noms dans l'enum pour simplifier la lecture du code)

    le reste c'est l'architecture générale à ne pas toucher.

    Comme je l'ai dit dans le premier post, ça ne marchera bien que si les loop() ne sont pas bloquantes trop longtemps, sinon la gestion globale n'est pas appelée assez souvent.

  7. #7
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    OK, j'ai regardé votre premier programme et c'est top.
    Je vais me pencher sur votre programme cet après-midi.
    Sinon vous me confirmez bien qu'au tout début, je mets toutes les bibliothèques...?

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Citation Envoyé par hugobeauce Voir le message
    Sinon vous me confirmez bien qu'au tout début, je mets toutes les bibliothèques...?
    Oui bien sûr il faut que le tout compile.. donc que toutes les bibliothèques nécessaires soient intégrées dans le code (pas forcément au début, vous pouvez mettre cela au début de chaque définition des 3 fonctions des tâches). vous pouvez aussi avoir bien sûr d'autres fonctions etc...

    bien noter aussi que la fonction setupXXX() n'est pas tout à fait un vrai setup() appelé qu'une seule fois , mais à chaque fois que vous basculez sur la tâche. Donc si vous avez des trucs à ne faire qu'une seule fois (activer un lecteur de badge, ouvrir la console série à 115200 bauds, etc) il faut le faire dans le vrai setup().

    On aurait pu rajouter une fonction oneTimeSetup() dans la structure de tâche et appeler cela lors du premier déclenchement de cette tâche si on voulait conserver une modularité et ne pas avoir à modifier le setup().

    la structure ressemblerait alors à ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // une tâche va consister en 4 pointeurs de fonctions
    struct t_task {
      t_setupFunc oneTimeSetup;
      t_setupFunc taskSetup;
      t_loopFunc taskLoop;
      t_cleanupFunc taskCleanUp;
    };
    dans notre cas on n'a rien à faire donc on pourrait juste déclarer que ces fonctions n'existent pas avec NULL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // définir le tableau des tâches
    t_task taskList[] = {
      {NULL, setupMenu, loopMenu, finMenu},
      {NULL, setupJeu1, loopJeu1, finJeu1},
      {NULL, setupJeu2, loopJeu2, finJeu2}
    };
    et le setup() appellerait ces fonctions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
    
      // call the one time setpup of all the tasks
      for (t_taskID t = 0; t < taskCount; t++)
        if (taskList[currentTask].oneTimeSetup != NULL)
          taskList[currentTask].oneTimeSetup();
    
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(MENU);
    }
    Attention à la mémoire, plus vous aurez de code et de variables globales, plus vous mangez la mémoire. Soyez économe !

  9. #9
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    Bon, j'ai compilé, mais ça beug ici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void finJeuLeds() {
      etat=JEUTAG;  //lancer le jeu TAG
    }
    cannot convert 't_etatJeu' to '<unnamed enum>' in assignment
    Après, j'ai aussi copié (bêtement) le menu, mais vu que ça doit lancer directement le jeuLed, je pense qu'il n'a pas lieu d'être.
    Voici le code complet, est-ce qu'au niveau de la présentation c'est bon?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
     
    const uint16_t battementCoeur = 1000U;
    uint32_t chronometre = 0;
     
    enum t_etatJeu : byte {INCHANGE = 0, MENU, JEULED, JEUTAG} etatGlobal = MENU;
     
    //*******************************************
    //Parametres de base decompte temps 60 minutes
    //*******************************************
    unsigned long t = 70;     //temps total en secondes
    unsigned long h = (t / 3600);         //nombre d'heure
    unsigned long mn = ((t / 60) - 60 * h); //nombre de minutes de 0 à 59
    unsigned long sec = (t % 60);         //nombre de secondes de 0 à 59
     
    const unsigned long interval = 1000;           // tu dis que tu veux un interval de 1000
    unsigned long previousMillis = 0;            //initialisation de la variable
     
    //initialisation du LCD I2C
    #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
    //Fin decompte 60 minutes
    //**********************************
     
    //**********************************
    //Parametres de base Jeu LEDs
    //**********************************
     
    #define LED_OFF HIGH
    #define LED_ON LOW
     
    // les pins à mettre en correspondance
    const uint8_t pinLEDSource[]  = {30, 31, 32, 33, 34};
    uint8_t pinDestination[] = {35, 36, 37, 38, 39}; // pas const car on va le mélanger
    const size_t nombreDeFils = sizeof(pinLEDSource) / sizeof(pinLEDSource[0]);
     
    enum : uint8_t {NOUVEAU_JEU, JEU_EN_COURS, VICTOIRE, FIN_JEU_LED} etat;
    //Fin jeu Leds
    //********************************
     
     
    //*********************************
    //Parametres de base Jeu TAGs
    //*********************************
    #include <SPI.h>
    #include <MFRC522.h>
    #define RST_PIN 5
    #define SS_PIN 53
    MFRC522 mfrc522(SS_PIN, RST_PIN);
     
    uint8_t carteAleatoire;
     
    //Je déclare 1 tableau qui contient les identifiants des cartes rfid et no associé
    // On définit le type carte
    struct t_carte {
      const char* nom;
      uint32_t UID;
    };
     
    t_carte jeuDeCartes[] = {   // préférer le nom du type sous forme t_xxx car le format xxx_t est réservé par la norme aux types officiels
      {"Colonel", 0x1965669A}, // Attention little Endian -> les octets de poids faibles seront en premier en mémoire
      {"General", 0x1A72690A},
      {"President", 0x196A7AFA},
      {"Secrétaire", 0x195E6C7A},
      {"Soldat", 0x19A94B1A},
      {"Entretien", 0x5FA7BFB7},
      {"Administrateur", 0x2A7A3080}
    };
     
    const uint8_t nombreDeCartes = sizeof(jeuDeCartes) / sizeof(jeuDeCartes[0]);
    //Fin parametres jeu TAGS
    //*****************************
     
     
    // ****************************
    //            MENU
    // ****************************
    uint32_t debutChronoMenu;
    uint32_t tickMenu;
     
    void setupMenu()
    {
      debutChronoMenu = millis();
      tickMenu = debutChronoMenu;
      Serial.println(F("\n\n************ MENU ************"));
      Serial.println(F("1\tJEU #1"));
      Serial.println(F("2\tJEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
     
    t_etatJeu loopMenu()
    {
      // faire une étape de la tâche courante
      if (millis() - tickMenu >= battementCoeur * 5) {
        Serial.print(F("\tDANS MENU DEPUIS: "));
        Serial.println((millis() - debutChronoMenu) /  1000);
        tickMenu += battementCoeur * 5;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == '1') return JEULED;
      if (c == '2') return JEUTAG;
      return INCHANGE;
    }
     
    void finMenu()
    {
      Serial.println(F("\tFIN MENU"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
     
    //**************************************
    //Programmation Setup Loop Fin DECOMPTE
    //**************************************
     
    void setupDecompte()
    {
      Serial.begin(112500);   //Serial monitor
      Serial.println("Temps de jeu");
      Serial.println("60 minutes");
      lcd.init();                      // initialize the lcd
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      lcd.setCursor(0, 0);
      lcd.print("Temps de jeu");
      lcd.setCursor(0, 1);
      lcd.print("60 minutes");
      millis();
    }
     
    void loopDecompte()
    {
      lcd.clear();
      while ( t > 0 ) {     //tant qu'il y a du temps
        h = (t / 3600);
        mn = ((t / 60) - 60 * h);
        sec = (t % 60);
        // digitalWrite(3, LOW);
        //digitalWrite(2, HIGH);
        unsigned long currentMillis = millis();    // à chaque boucle, tu initialise currentMillis
     
        if (h >= 10)        //si le temps est > 10heures
        {
          Serial.print(h);
          Serial.print("h");
          lcd.setCursor(0, 0); lcd.print(h); lcd.setCursor(2, 0); lcd.print("H");
          //lcd.setCursor(0, 1); lcd.print("OUI");
     
        }
        if (h < 10)        //si le temps est < 10heure
        {
          Serial.print("0");
          Serial.print(h);
          Serial.print("h");
          lcd.setCursor(0, 0); lcd.print("0"); lcd.setCursor(1, 0); lcd.print(h); lcd.setCursor(2, 0); lcd.print("H");
        }
     
        if (h == 0) //quand le temps est inférieur à 1heure, on supprime la valeur écrite
        {
          lcd.setCursor(0, 0); lcd.print("   ");
        }
        if (((t / 60) >= 1)) // si le temps est > 1 minute
        {
          if (mn >= 10)     //si il y a pus de 10 minutes
          {
            Serial.print(mn);   //on écrit la caleur de min
            Serial.print("min");
            lcd.setCursor(3, 0); lcd.print(mn); lcd.setCursor(5, 0); lcd.print("min");
     
          }
          else                //sinon
          {
            Serial.print("0");   //on ajoute un 0 pour avoir 2 chiffres
            Serial.print(mn);
            Serial.print("min");
            lcd.setCursor(3, 0); lcd.print("0"); lcd.setCursor(4, 0); lcd.print(mn); lcd.setCursor(5, 0); lcd.print("min");
          }
     
          if (sec >= 10)      //s'il y a plus de 10 sec
          {
            Serial.print(sec);    // on affiche sec
            Serial.println("sec");
            lcd.setCursor(8, 0); lcd.print(sec); lcd.setCursor(10, 0); lcd.print("sec");
          }
          else                //sinon
          {
            Serial.print("0");  //on ajoute un 0 pour avoir 2 chiffres
            Serial.print(sec);
            Serial.println("sec");
            lcd.setCursor(8, 0); lcd.print("0"); lcd.setCursor(9, 0); lcd.print(sec); lcd.setCursor(10, 0); lcd.print("sec");
          }
          if (currentMillis - previousMillis >= interval   ) {    // quand millis-(valeur de millis boucle avant==1000 ; alors action
            previousMillis += interval; // currentMillis ;
            t--;
          }
        }
        else     //quand temps inférieur à 1 minute
        {
          if (sec >= 10)      //s'il y a plus de 10 sec
          {
            Serial.print(sec);    // on affiche sec
            Serial.println("sec");
            lcd.setCursor(0, 0); lcd.print("        ");
            lcd.setCursor(8, 0); lcd.print(sec); lcd.setCursor(10, 0); lcd.print("sec");
            //tone(DIO_Buzzer,500,50);
            if (currentMillis - previousMillis >= interval  ) {    // quand millis-(valeur de millis boucle avant==1000 ; alors action
              previousMillis += interval;//currentMillis ;
              t--;
            }
          }
          else                //sinon
          {
            Serial.print("0");  //on ajoute un 0 pour avoir 2 chiffres
            Serial.print(sec);
            Serial.println("sec");
            lcd.setCursor(0, 0); lcd.print("         ");
            lcd.setCursor(9, 0); lcd.print(sec); lcd.setCursor(10, 0); lcd.print("sec");
            //tone(DIO_Buzzer,500,50);
            if (currentMillis - previousMillis >= interval   ) {    // quand millis-(valeur de millis boucle avant==1000 ; alors action
              previousMillis += interval; // currentMillis ;
              t--;
            }
          }
     
     
        }
      }
     
      finDecompte();
    }
    void finDecompte()
    {
      Serial.println("Partie finie");
      lcd.clear();
      lcd.print("Partie finie");
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
    //***********************
    // Programmation JeuLED
    //***********************
    void imprime()
    {
      for (size_t i = 0; i < nombreDeFils; i++) {
        Serial.print(F("{"));
        Serial.print(pinLEDSource[i]);
        Serial.print(F(" <<->> "));
        Serial.print(pinDestination[i]);
        Serial.print(F("} "));
      }
      Serial.println();
    }
     
    bool cablageCorrect()
    {
      // on fait clignoter la Source et on regarde si on voit ce signal sur la destination
     
      const uint8_t nombreDeClignotements = 3;
      size_t nbFilsCorrects = 0;
     
      for (size_t unFil = 0; unFil < nombreDeFils; unFil++) {
        bool erreur = false;
     
        for (uint8_t n = 0; n < nombreDeClignotements; n++) {
          digitalWrite(pinLEDSource[unFil], LED_ON);
          erreur = (digitalRead(pinDestination[unFil]) != LED_ON);
          if (erreur) break;
          digitalWrite(pinLEDSource[unFil], LED_OFF);
          erreur = (digitalRead(pinDestination[unFil]) != LED_OFF);
          if (erreur) break;
        }
        if (erreur) {
          digitalWrite(pinLEDSource[unFil], LED_OFF);
        } else {
          // le fil est bon on laisse la LED allumée
          digitalWrite(pinLEDSource[unFil], LED_ON);
          nbFilsCorrects++;
        }
      } // fin de pour chaque fil
      return (nbFilsCorrects == nombreDeFils);
    }
     
    void melange()
    {
      for (size_t i = nombreDeFils - 1; i >= 1; --i) {
        size_t j = random(0, i + 1);
        uint8_t echange = pinDestination[i];
        pinDestination[i] = pinDestination[j];
        pinDestination[j] = echange;
      }
    }
     
    // -----------------
     
    void setupLeds() {
      Serial.begin(115200);
      randomSeed(analogRead(A0));
     
      for (size_t i = 0; i < nombreDeFils; i++) {
        pinMode(pinLEDSource[i], OUTPUT);
        digitalWrite(pinLEDSource[i], LED_OFF);
        pinMode(pinDestination[i], INPUT_PULLUP);
      }
     
      etat = NOUVEAU_JEU;
    }
     
    void loopLeds()
    {
      switch (etat) {
     
        case NOUVEAU_JEU:
          melange();
          imprime();
          etat = JEU_EN_COURS;
          break;
     
        case JEU_EN_COURS:
          if (cablageCorrect()) etat = VICTOIRE;
          delay(500);
          break;
     
        case VICTOIRE:
          Serial.println(F("VICTOIRE"));
          for (uint8_t n = 0; n < 20; n++) {
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_OFF);
            delay(50);
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_ON);
            delay(50);
          }
          etat = FIN_JEU_LED;
          break;
     
        case FIN_JEU_LED:
          finJeuLeds();
          break;
      }
    }
     
    void finJeuLeds() {
      etat=JEUTAG;  //lancer le jeu TAG
    }
     
     
    //****************************
    // Programmation jeu TAGS
    //****************************
    void choisirCarteAleatoire()
    {
      carteAleatoire = random(0, nombreDeCartes); // un nombre entier entre 0 et nombreDeCartes-1
      Serial.print(F("Nouvelle Carte Aleatoire: "));
      Serial.print(jeuDeCartes[carteAleatoire].nom);
      Serial.print(F("\t0x"));
      Serial.println(jeuDeCartes[carteAleatoire].UID, HEX);
    }
     
    void setupTags()
    {
      Serial.begin(115200);
      while (!Serial);
     
      SPI.begin();
      mfrc522.PCD_Init();
     
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
      choisirCarteAleatoire();
    }
     
     
    void loopTags()
    {
     
      if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      if ( ! mfrc522.PICC_ReadCardSerial()) return;
      // on a une carte dont le N° est dans le tableau mfrc522.uid.uidByte
     
      if (jeuDeCartes[carteAleatoire].UID == *((uint32_t*) mfrc522.uid.uidByte)) {
        Serial.println("ACCES AUTORISE");
       finTags();   
    } else {
        Serial.println("STOP");
      }
    }
    void finTags(){
       Serial.println("Fin de partie");
    }
     
     
    // ****************************
    //         UTILITAIRES
    // ****************************
    void gestionGlobale()
    {
      // Gestion de l'écran toutes les "battementCoeur"
      if (millis() - chronometre >= battementCoeur) {
        Serial.print(F("TEMPS GLOBAL: "));
        Serial.println(millis() / 1000);
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW); // inverse l'état de la LED, on clignote
        chronometre += battementCoeur;
      }
    }
     
    void etablirNouvelEtat(t_etatJeu nouvelEtat)
    {
      switch (nouvelEtat) {
        case MENU:
          setupMenu();
          etatGlobal = MENU;
          break;
        case JEULED:
          setupLeds();
          etatGlobal = JEULED;
          break;
        case JEUTAG:
          setupTags();
          etatGlobal = JEUTAG;
          break;
        default: break; // on reste dans cet état
      }
    }
     
    void gestionEtat()
    {
      switch (etatGlobal) {
        case MENU:      // attente d'un choix
          {
            t_etatJeu nouvelEtat = loopMenu();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le MENU proprement
              finMenu();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
     
        case JEU1:
          {
            t_etatJeu nouvelEtat = loopJeu1();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le JEU1 proprement
              finJeu1();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
     
        case JEU2:
          {
            t_etatJeu nouvelEtat = loopJeu2();
            if (nouvelEtat != INCHANGE) { // demande de changement
              // on termine le JEU2 proprement
              finJeu2();
              etablirNouvelEtat(nouvelEtat);
            }
          }
          break;
      }
    }
     
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
      decompte();
      jeuLeds();
    }
     
     
    void loop()
    {
      gestionGlobale();
      gestionEtat();
    }

  10. #10
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    vous avez lu ci dessous le point pour ce qu'on met dans le setup ? les trucs à ne faire qu'une fois vont dans le vrai setup, donc il faut virer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      Serial.begin(115200);
      while (!Serial);
     
      SPI.begin();
      mfrc522.PCD_Init();
    de setupTags

    pourquoi appelez vous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      decompte();
      jeuLeds();
    dans le setup ?

    si vous voulez que ce soit géré par la machine a état il faut appeler
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      etablirNouvelEtat(XXX);
    avec XXX le code de la tâche

    Je ne suis pas sûr que vous ayez compris comment ça fonctionne....faut bien lire le code est essayer de le dérouler à la main pour voir ce qu'il se passe.


    PS: passez sur la seconde version du code que j'ai posté, avec les tâches et pointeurs sur fonctions.

  11. #11
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    Citation Envoyé par Jay M Voir le message

    pourquoi appelez vous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      decompte();
      jeuLeds();
    dans le setup ?
    bonjour, déjà, merci pour votre analyse.

    Pour répondre à votre question, je pensais que dans le VRAI setup, il fallait appeler la fonction decompte() et en même temps, la fonction jeuLeds pour qu'elles se déroulent simultanément.

    Sinon, comme la réussite d'un jeu déclenche l'autre jeu, il faut bien que le void finJEU1 appelle le jeu2?

    Bon je vais me pencher sur votre dernier post

  12. #12
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    oui étudiez un peu le principe proposé

    l'idée générale c'est qu'en plus du code qui maintient le temps (celui appelé par gestionGlobale(); dans la loop) il y a UNE SEULE TACHE active à un instant t.
    cette tâche vie et meurt grâce aux appels à gestionEtat(); dans la loop.

    au tout début du démarrage de la tâche on appelle sa fonction setupXXX, puis pendant toute sa vie sa fonction loopXXX qui doit retourner une valeur disant si cette tâche doit continuer à vivre ou s'arrêter et passer la main à une autre tâche.

    Si vous voulez continuer la tâche en cours (le jeu n'est pas fini) vous retournez INCHANGE, sinon un N° de tâche.

    Quand gestionEtat() voit que le code retourné n'est pas INCHANGE, il sait qu'il doit terminer la tâche courante, donc appeler finXXXX puis activer la tâche suivante donc appeler son setupYYY et ensuite boucler sur sa loopYYY jusqu'à ce qu'elle même retourne autre chose que INCHANGE

  13. #13
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    C'est simple à lire.
    Pour la mise en œuvre, je vais me servir de votre exemple avec les jeux 1 et 2.
    En essayant d'automatiser le passage au jeu 2 quand le temps arrive à X secondes (simulation de réussite au jeu 1).
    Histoire de bien comprendre tout ça.

  14. #14
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Oui il suffit que la loop du JEU1 retourne JEU2 au moment où le JEU1 se termine et automatiquement la fonction finJeu1() sera appelée et setupJeu2() puis ensuite la loop() appellera la loopJeu2() toute seule.

  15. #15
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    Bon déjà, la première adaptation fonctionne
    J'ai juste rajouté un affichage Lcd.I2C
    et un lancement automatique du jeu2 quand le temps jeu1=30sec.
    Pas de quoi s'enflammer vous me direz, mais pour niveau d'informatique, c'est déjà pas mal.

    Bon, c'est là où je comprends vite, mais il faut m'expliquer longtemps.

    C'est où placer le décompte de temps?
    Si j'ai bien compris, il faut le mettre dans le "VRAI" setup et l'affichage, dans le vrai "LOOP"; du programme principal?
    (Et pas dans le GLOBAL, où j'ai mis lcd.print("##TIMING##"); ).

    ou faut-il comme pour JEU1, créer un "sous-programme"?

    sinon, j'ai bien compris le système des appels.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    //***************************
    //Bibliotheques, variables...
    //***************************
     
    //initialisation du LCD I2C
    #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
     
     
     
    typedef  int16_t t_taskID;
    const t_taskID INCHANGE = -1;
     
    typedef void (*t_setupFunc)();      // on défint le type t_setupFunc comme pointeur sur fonction retournant rien
    typedef t_taskID (*t_loopFunc)();  // on défint le type t_loopFunc comme pointeur sur fonction retournant un N°de tâche
    typedef void (*t_cleanupFunc)();    // on défint le type t_cleanupFunc comme pointeur sur fonction retournant rien
     
    // une tâche va consister en 3 pointeurs de fonctions
    struct t_task {
      t_setupFunc taskSetup;
      t_loopFunc taskLoop;
      t_cleanupFunc taskCleanUp;
    };
     
    // *********************************************
    // pour pouvoir définir le tableau des tâches
    // On pré-annonce les fonctions de nos tâches. (forward declaration)
    // Leur code viendra plus tard.
     
    // le Menu
    void setupMenu();
    t_taskID loopMenu();
    void finMenu();
     
    // le jeu 1
    void setupJeu1();
    t_taskID loopJeu1();
    void finJeu1();
     
    // le Jeu2
    void setupJeu2();
    t_taskID loopJeu2();
    void finJeu2();
    // *********************************************
     
    // définir le tableau des tâches
    t_task taskList[] = {
      {setupMenu, loopMenu, finMenu},
      {setupJeu1, loopJeu1, finJeu1},
      {setupJeu2, loopJeu2, finJeu2}
    };
     
    // définir les N° de nos tâches avec un nom parlant, ça simplifie la lecture du code.
    enum : t_taskID {MENU, JEU1, JEU2};
     
     
    // ****************************
    //         UTILITAIRES
    // ****************************
     
    // on calcule le nombre de tâches définies
    uint16_t taskCount = sizeof(taskList) / sizeof(taskList[0]);
    t_taskID currentTask;
    uint32_t currentTaskStartTime;
     
    void etablirNouvelleTache(t_taskID nouvelleTache)
    {
      if (nouvelleTache >= taskCount) return;     // nouvelleTache n'existe pas
      currentTaskStartTime = millis();
      currentTask = nouvelleTache;
      taskList[currentTask].taskSetup();
    }
     
     
    void gestionEtat()
    {
      t_taskID nouvelleTache = taskList[currentTask].taskLoop();   // on fait un tour de loop de la tâche
     
      if (nouvelleTache != INCHANGE) {          // demande de changement
        taskList[currentTask].taskCleanUp();   // on termine la tâche en cours  proprement
        etablirNouvelleTache(nouvelleTache);    // on bascule vers la nouvelle tâche
      }
    }
     
     
    // ****************************
    //     TÂCHE GLOBALE
    // ****************************
    const uint16_t pulsation = 500U; // 1Hz
    uint32_t chronometre = 0;
     
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW); // inverse l'état de la LED, on clignote
        chronometre += pulsation;
      }
      //lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("##TIMING##");
     
      // VOUS POUVEZ FAIRE AUTRE CHOSE ICI, C'EST APPELE A CHAQUE TOUR DE LOOP GLOBALE
    }
     
     
    // ****************************
    //            MENU
    // ****************************
    uint32_t tickMenu;
     
    void setupMenu()
    {
      tickMenu = currentTaskStartTime;
      Serial.println(F("\n\n************ MENU ************"));
      Serial.println(F("1\tJEU #1"));
      Serial.println(F("2\tJEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
    }
     
    t_taskID loopMenu()
    {
      // faire une étape de la tâche courante
      if (millis() - tickMenu >= 5000U) {
        Serial.print(F("\tDANS MENU DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        lcd.setCursor(0, 1);
        lcd.print("1=JEU1, 2=JEU2");
        tickMenu += 5000U;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == '1') return JEU1; // index du Jeu 1
      if (c == '2') return JEU2; // index du Jeu 2
      return INCHANGE;
    }
     
    void finMenu()
    {
      Serial.println(F("\tFIN MENU"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 1
    // ****************************
    uint32_t tickJeu1;
     
    void setupJeu1()
    {
      tickJeu1 = currentTaskStartTime;
      Serial.println(F("\n\n************ JEU #1 **********"));
      Serial.println(F("F\tFIN JEU #1"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
      lcd.setCursor(0, 1);
      lcd.print("##### JEU1 #####");
     
    }
     
    t_taskID loopJeu1()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu1 >= 5000U) {
        Serial.print(F("\tDANS JEU #1 DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        lcd.setCursor(0, 1);
        lcd.print("                ");
        lcd.setCursor(0, 1);
        lcd.print("Tps JEU1:"); lcd.setCursor(10, 1); lcd.print((millis() - currentTaskStartTime) /  1000);
        tickJeu1 += 5000U;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      if (((millis() - currentTaskStartTime) /  1000) == 35) return JEU2;
      return INCHANGE;
    }
     
    void finJeu1()
    {
      Serial.println(F("\tFIN JEU #1"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 2
    // ****************************
    uint32_t tickJeu2;
     
    void setupJeu2()
    {
      tickJeu2 = currentTaskStartTime;
      Serial.println(F("\n\n************ JEU #2 **********"));
      Serial.println(F("F\tFIN JEU #2"));
      Serial.println(F("******************************"));
      Serial.println(F("ENTREZ VOTRE CHOIX\n\n"));
      lcd.setCursor(0, 1);
      lcd.print("##### JEU2 #####");
    }
     
    t_taskID loopJeu2()
    {
      // faire une étape de la tâche courante
      if (millis() - tickJeu2 >= 5000U) {
        Serial.print(F("\tDANS JEU #2 DEPUIS: "));
        Serial.println((millis() - currentTaskStartTime) /  1000);
        lcd.setCursor(0, 1);
        lcd.print("                ");
        lcd.setCursor(0, 1);
        lcd.print("Tps JEU2:"); lcd.setCursor(10, 1); lcd.print((millis() - currentTaskStartTime) /  1000);
        tickJeu2 += 5000U;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
    }
     
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
     
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
     
      // AUTRES INITIALISATIONS
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      lcd.setCursor(0, 0);
      lcd.print("Bonjour");
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(MENU);
    }
     
     
    void loop()
    {
      gestionGlobale();
      gestionEtat();
    }

  16. #16
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut


    la gestion globale est effectuée dans ... gestionGlobale();

    Cette fonction est appelée à chaque tour de loop. pour le moment je fais clignoter la LED à 1Hz
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     const uint16_t pulsation = 500U; // 1Hz
    uint32_t chronometre = 0;
     
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == LOW ? HIGH : LOW); // inverse l'état de la LED, on clignote
        chronometre += pulsation;
      }
     
      // VOUS POUVEZ FAIRE AUTRE CHOSE ICI, C'EST APPELE A CHAQUE TOUR DE LOOP GLOBALE
    }
    mais vous pouvez faire autre chose qui dépend de millis() aussi. Par exemple afficher sur la ligne 1 du LCD le temps restant


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const uint16_t pulsation = 1000U; // mise à jour une fois par seconde
    const uint32_t  tempsTotal = 1000UL*60UL*30UL; // 30 minutes = 1 800 000 ms
    uint32_t chronometre = 0;
     
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        if (millis() < tempsTotal) {  // si on considère que le début du jeu est au boot
          uint32_t tempsRestant = (tempsTotal - millis()) / 1000; // en secondes
          // lcd.setCursor(0, 0);  // si on ne l'a jamais effacé pas la peine de le ré-afficher, le faire une fois dans le setup
          // lcd.print(F("TEMPS:"); 
          lcd.setCursor(6, 0);
          lcd.print(tempsRestant); // au max c'est 1800 (30 minutes) donc 4 caractères. quand on passera à 3 faut effacer le 4ème etc
          lcd.print("s "); // ici on met un s pour secondes et un espace qui effacera ce qui dépasse.
        } else {
          // LE TEMPS EST EXPIRE. FAIRE CE QU'IL FAUT !
        } 
        chronometre += pulsation;
      }
    }

  17. #17
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut bidouille et petit problème
    bonjour,

    bon j'ai réussi à incorporer le code des jeux (non sans mal) mais il y a quelques petits beugs ça et là.

    déjà pour lancer automatiquement le jeu1, je suis obliger de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     int c;
      if (c == 0)  return JEU1;
      return INCHANGE;
    ça refuse: return JEU1;

    Pour le JEU1, aucun problème

    Pour le JEU2, sur le serial monitor, ça met en boucle Fin jeu 2, même si je ne rentre pas de carte !!!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
       // nettoyage éventuel, ici rien de particulier à nettoyer
    }
    Enfin,

    J'ai fait comme un jeu "FIN"
    de façon à écrire une merdouille de félicitation.

    J'ai tout déclaré. Lorsque je veux compiler, ça beug…
    exit status 1
    Erreur de compilation pour la carte Arduino Mega or Mega 2560


    voici le code en entier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    //***************************
    //Bibliotheques, variables...
    //***************************
     
    //initialisation du LCD I2C
    #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
     
    //Partie tableau des differents jeux
    typedef  int16_t t_taskID;
    const t_taskID INCHANGE = -1;
     
    typedef void (*t_setupFunc)();      // on défint le type t_setupFunc comme pointeur sur fonction retournant rien
    typedef t_taskID (*t_loopFunc)();  // on défint le type t_loopFunc comme pointeur sur fonction retournant un N°de tâche
    typedef void (*t_cleanupFunc)();    // on défint le type t_cleanupFunc comme pointeur sur fonction retournant rien
     
    // une tâche va consister en 3 pointeurs de fonctions
    struct t_task {
      t_setupFunc taskSetup;
      t_loopFunc taskLoop;
      t_cleanupFunc taskCleanUp;
    };
     
    // *********************************************
    // pour pouvoir définir le tableau des tâches
    // On pré-annonce les fonctions de nos tâches. (forward declaration)
    // Leur code viendra plus tard.
     
    // le Menu
    void setupMenu();
    t_taskID loopMenu();
    void finMenu();
     
    // le jeu 1
    void setupJeu1();
    t_taskID loopJeu1();
    void finJeu1();
     
    // le Jeu2
    void setupJeu2();
    t_taskID loopJeu2();
    void finJeu2();
     
    // la fin
    /*void setupFin();
    t_taskID loopFin();
    void finFin();*/
     
    // *********************************************
     
    // définir le tableau des tâches
    t_task taskList[] = {
      {setupMenu, loopMenu, finMenu},
      {setupJeu1, loopJeu1, finJeu1},
      {setupJeu2, loopJeu2, finJeu2},
      //{setupFin, loopFin, finFin}
    };
     
    // définir les N° de nos tâches avec un nom parlant, ça simplifie la lecture du code.
    enum : t_taskID {MENU, JEU1, JEU2, FIN};
     
     
    // ****************************
    //         UTILITAIRES
    // ****************************
     
    // on calcule le nombre de tâches définies
    uint16_t taskCount = sizeof(taskList) / sizeof(taskList[0]);
    t_taskID currentTask;
    uint32_t currentTaskStartTime;
     
    void etablirNouvelleTache(t_taskID nouvelleTache)
    {
      if (nouvelleTache >= taskCount) return;     // nouvelleTache n'existe pas
      currentTaskStartTime = millis();
      currentTask = nouvelleTache;
      taskList[currentTask].taskSetup();
    }
     
     
    void gestionEtat()
    {
      t_taskID nouvelleTache = taskList[currentTask].taskLoop();   // on fait un tour de loop de la tâche
     
      if (nouvelleTache != INCHANGE) {          // demande de changement
        taskList[currentTask].taskCleanUp();   // on termine la tâche en cours  proprement
        etablirNouvelleTache(nouvelleTache);    // on bascule vers la nouvelle tâche
      }
    }
     
     
    // ****************************
    //     TÂCHE GLOBALE
    // ****************************
    const uint16_t pulsation = 1000U; // mise à jour une fois par seconde
    const uint32_t  tempsTotal = 1000UL * 60UL * 60UL; // 60 minutes = 3 600 000 ms
    uint32_t chronometre = 0;
     
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        if (millis() < tempsTotal) {  // si on considère que le début du jeu est au boot
          uint32_t tempsRestant = (tempsTotal - millis()) / 1000; // en secondes
          lcd.setCursor(0, 0); lcd.print(F("TEMPS:"));
          if (tempsRestant >= 60) {
            lcd.print(tempsRestant / 60);
            lcd.print("min");
          }
          lcd.print(tempsRestant % 60); lcd.print("s    ");
     
        } else {
          // LE TEMPS EST EXPIRE. FAIRE CE QU'IL FAUT !
          lcd.setCursor(0, 0); lcd.print(F("VOUS AVEZ PERDU"));
        }
        chronometre += pulsation;
      }
    }
     
     
     
     
     
    // ****************************
    //            MENU
    // ****************************
    uint32_t tickMenu;
     
    void setupMenu()
    {
      tickMenu = currentTaskStartTime;
     }
     
    t_taskID loopMenu()
    {
      // faire une étape de la tâche courante
      if (millis() - tickMenu >= 5000U) {
        tickMenu += 5000U;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
        int c;
      if (c == 0)  return JEU1;
      return INCHANGE;
    }
     
    void finMenu()
    {
        // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 1
    // ****************************
    uint32_t tickJeu1;
     
    #define LED_OFF HIGH
    #define LED_ON LOW
     
    // les pins à mettre en correspondance
    const uint8_t pinLEDSource[]  = {30, 32, 34};
    uint8_t pinDestination[] = {31, 33, 35}; // pas const car on va le mélanger
    const size_t nombreDeFils = sizeof(pinLEDSource) / sizeof(pinLEDSource[0]);
     
    enum : uint8_t {NOUVEAU_JEU, JEU_EN_COURS, VICTOIRE} etat;
     
    void imprime()
    {
      for (size_t i = 0; i < nombreDeFils; i++) {
        Serial.print(F("{"));
        Serial.print(pinLEDSource[i]);
        Serial.print(F(" <<->> "));
        Serial.print(pinDestination[i]);
        Serial.print(F("} "));
     
        lcd.setCursor(0, 1); lcd.print("Connectez fils");
      }
      Serial.println();
    }
     
    bool cablageCorrect()
    {
      // on fait clignoter la Source et on regarde si on voit ce signal sur la destination
     
      const uint8_t nombreDeClignotements = 3;
      size_t nbFilsCorrects = 0;
     
      for (size_t unFil = 0; unFil < nombreDeFils; unFil++) {
        bool erreur = false;
     
        for (uint8_t n = 0; n < nombreDeClignotements; n++) {
          digitalWrite(pinLEDSource[unFil], LED_ON);
          erreur = (digitalRead(pinDestination[unFil]) != LED_ON);
          if (erreur) break;
          digitalWrite(pinLEDSource[unFil], LED_OFF);
          erreur = (digitalRead(pinDestination[unFil]) != LED_OFF);
          if (erreur) break;
        }
        if (erreur) {
          digitalWrite(pinLEDSource[unFil], LED_OFF);
        } else {
          // le fil est bon on laisse la LED allumée
          digitalWrite(pinLEDSource[unFil], LED_ON);
          nbFilsCorrects++;
     
        }
      } // fin de pour chaque fil
      return (nbFilsCorrects == nombreDeFils);
    }
     
    void melange()
    {
      // algo cf <a href="https://fr.wikipedia.org/wiki/Mélange_de_Fisher-Yates" target="_blank">https://fr.wikipedia.org/wiki/Mélange_de_Fisher-Yates</a>
      for (size_t i = nombreDeFils - 1; i >= 1; --i) {
        size_t j = random(0, i + 1);
        uint8_t echange = pinDestination[i];
        pinDestination[i] = pinDestination[j];
        pinDestination[j] = echange;
      }
    }
     
    // -----------------
     
     
    void setupJeu1()
    {
     
      tickJeu1 = currentTaskStartTime;
      randomSeed(analogRead(A0));
     
      for (size_t i = 0; i < nombreDeFils; i++) {
        pinMode(pinLEDSource[i], OUTPUT);
        digitalWrite(pinLEDSource[i], LED_OFF);
        pinMode(pinDestination[i], INPUT_PULLUP);
      }
      etat = NOUVEAU_JEU;
    }
     
     
     
    t_taskID loopJeu1()
    {
      switch (etat) {
     
        case NOUVEAU_JEU:
          melange();
          imprime();
          etat = JEU_EN_COURS;
          break;
     
        case JEU_EN_COURS:
          if (cablageCorrect()) etat = VICTOIRE;
          delay(500);
          break;
     
        case VICTOIRE:
          Serial.println(F("VICTOIRE"));
          for (uint8_t n = 0; n < 20; n++) {
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_OFF);
            delay(50);
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_ON);
            delay(50);
          }
          return JEU2;
          break;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      if (c == 'F') return MENU;
      return INCHANGE;
     
    }
     
    void finJeu1()
    {
      Serial.println(F("\tFIN JEU #1"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 2
    // ****************************
    uint32_t tickJeu2;
     
    #include <SPI.h>
    #include <MFRC522.h>
    #define RST_PIN 5
    #define SS_PIN 53
    MFRC522 mfrc522(SS_PIN, RST_PIN);
     
    uint8_t carteAleatoire;
     
    //Je déclare deux tableaux qui contient les identifiants des cartes rfid et nol associé
    // On définit le type carte
    struct t_carte {
      const char* nom;
      uint32_t UID;
    };
     
    t_carte jeuDeCartes[] = {   // préférer le nom du type sous forme t_xxx car le format xxx_t est réservé par la norme aux types officiels
      {"Colonel", 0x1965669A}, // Attention little Endian -> les octets de poids faibles seront en premier en mémoire
      {"General", 0x1A72690A},
      {"President", 0x196A7AFA},
      {"Secrétaire", 0x195E6C7A},
      {"Soldat", 0x19A94B1A},
      {"Entretien", 0x5FA7BFB7},
      {"Administrateur", 0x2A7A3080}
    };
     
    const uint8_t nombreDeCartes = sizeof(jeuDeCartes) / sizeof(jeuDeCartes[0]);
     
    void choisirCarteAleatoire()
    {
      carteAleatoire = random(0, nombreDeCartes); // un nombre entier entre 0 et nombreDeCartes-1
      Serial.print(F("Nouvelle Carte Aleatoire: "));
      Serial.print(jeuDeCartes[carteAleatoire].nom);
      Serial.print(F("\t0x"));
      Serial.println(jeuDeCartes[carteAleatoire].UID, HEX);
      lcd.setCursor(0, 1);lcd.print("SCANNER ");lcd.print(jeuDeCartes[carteAleatoire].nom);
    }
     
     
    void setupJeu2()
    {
      tickJeu2 = currentTaskStartTime;
      while (!Serial);
     
      SPI.begin();
      mfrc522.PCD_Init();
     
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
      choisirCarteAleatoire();
    }
     
    t_taskID loopJeu2()
    {
      if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      if ( ! mfrc522.PICC_ReadCardSerial()) return;
      // on a une carte dont le N° est dans le tableau mfrc522.uid.uidByte
     
      if (jeuDeCartes[carteAleatoire].UID == *((uint32_t*) mfrc522.uid.uidByte)) {
        //Serial.println("ACCES AUTORISE");
        lcd.setCursor(0, 1);
        lcd.print("ACCES AUTORISE  ");
        //choisirCarteAleatoire();
        return FIN;
      } else {
        //Serial.println("STOP");
        lcd.setCursor(0, 1);
        lcd.print(" Mauvaise carte  ");
      }
      // faire une étape de la tâche courante
      //if (millis() - tickJeu2 >= 5000U) {
        tickJeu2 += 5000U;
     
     
    // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
    return INCHANGE;
    }
     
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
       // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
    //*****************************
    //        FIN DU JEU
    //*****************************
    /*void setupFin ()
    {
    lcd.clear();
    lcd.setCursor(0, 0); lcd.print(" VOUS AVEZ GAGNE ");
    lcd.setCursor(0, 0); lcd.print("   Bravo à vous  ");
    }*/
     
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
     
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
     
      // AUTRES INITIALISATIONS
     
      //decompte
      // Pour activer l'état HOLD
      unsigned int time_hold = 4;
     
      //Ecran
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(MENU);
    }
     
     
    void loop()
    {
     
      gestionGlobale();
      gestionEtat();
     
    }
    Merci par avance pour votre aide

  18. #18
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Salut

    pour lancer JEU1 par défaut il suffit de mettre à la fin du setup
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(JEU1);
    Vous n'utilisez pas la tâche menu, donc virez là

    pourquoi loopJeu1 retournerai MENU ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      if (c == 'F') return MENU;
    On a dit que tout ce qui concernait le mise en fonction du matériel devait être dans le vrai setup. Donc ne mettez pas ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      while (!Serial);
     
      SPI.begin();
      mfrc522.PCD_Init();
     
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
    dans setupJeu2()


    pourquoi conserver
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      // faire une étape de la tâche courante
      //if (millis() - tickJeu2 >= 5000U) {
      tickJeu2 += 5000U;
    on avait cela dans l'exemple pour montrer comment faire quelque chose de temps en temps... là ça ne sert à rien

  19. #19
    Membre confirmé
    Homme Profil pro
    pompier
    Inscrit en
    Janvier 2020
    Messages
    86
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Eure et Loir (Centre)

    Informations professionnelles :
    Activité : pompier

    Informations forums :
    Inscription : Janvier 2020
    Messages : 86
    Par défaut
    voilà , j'ai fait quelques modifications.
    Je pense que je vais manger mon chapeau à force.

    Quand je lance le jeu tout va bien jusqu'au moment où je passe au jeu2.

    Sur mon écran LCD, pas de problème.
    Sur l'écran virtuel, ça me donne le nom de la personne à scanner, puis en boucle, "fin jeu2". Alors même que je n'ai scanné aucune carte.

    PUIS, quand le jeu2 est terminé:
    Sur mon écran, j'ai toujours le temps qui défile sur la première ligne, et "bravo a vous" sur la seconde.

    faut-il faire un bout de code dans le loopGeneral, si action=END alors stop décompte?

    le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    //***************************
    //Bibliotheques, variables...
    //***************************
     
    //initialisation du LCD I2C
    #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
     
    //Partie tableau des differents jeux
    typedef  int16_t t_taskID;
    const t_taskID INCHANGE = -1;
     
    typedef void (*t_setupFunc)();      // on défint le type t_setupFunc comme pointeur sur fonction retournant rien
    typedef t_taskID (*t_loopFunc)();  // on défint le type t_loopFunc comme pointeur sur fonction retournant un N°de tâche
    typedef void (*t_cleanupFunc)();    // on défint le type t_cleanupFunc comme pointeur sur fonction retournant rien
     
    // une tâche va consister en 3 pointeurs de fonctions
    struct t_task {
      t_setupFunc taskSetup;
      t_loopFunc taskLoop;
      t_cleanupFunc taskCleanUp;
    };
     
    // *********************************************
    // pour pouvoir définir le tableau des tâches
    // On pré-annonce les fonctions de nos tâches. (forward declaration)
    // Leur code viendra plus tard.
     
    // le Menu
    /*void setupMenu();
      t_taskID loopMenu();
      void finMenu();*/
     
    // le jeu 1
    void setupJeu1();
    t_taskID loopJeu1();
    void finJeu1();
     
    // le Jeu2
    void setupJeu2();
    t_taskID loopJeu2();
    void finJeu2();
     
    // la fin
    void setupEnd();
    t_taskID loopEnd();
    void finEnd();
     
    // *********************************************
     
    // définir le tableau des tâches
    t_task taskList[] = {
      //{setupMenu, loopMenu, finMenu},
      {setupJeu1, loopJeu1, finJeu1},
      {setupJeu2, loopJeu2, finJeu2},
      {setupEnd, loopEnd, finEnd}
    };
     
    // définir les N° de nos tâches avec un nom parlant, ça simplifie la lecture du code.
    enum : t_taskID {JEU1, JEU2, END};
     
     
    // ****************************
    //         UTILITAIRES
    // ****************************
     
    // on calcule le nombre de tâches définies
    uint16_t taskCount = sizeof(taskList) / sizeof(taskList[0]);
    t_taskID currentTask;
    uint32_t currentTaskStartTime;
     
    void etablirNouvelleTache(t_taskID nouvelleTache)
    {
      if (nouvelleTache >= taskCount) return;     // nouvelleTache n'existe pas
      currentTaskStartTime = millis();
      currentTask = nouvelleTache;
      taskList[currentTask].taskSetup();
    }
     
     
    void gestionEtat()
    {
      t_taskID nouvelleTache = taskList[currentTask].taskLoop();   // on fait un tour de loop de la tâche
     
      if (nouvelleTache != INCHANGE) {          // demande de changement
        taskList[currentTask].taskCleanUp();   // on termine la tâche en cours  proprement
        etablirNouvelleTache(nouvelleTache);    // on bascule vers la nouvelle tâche
      }
    }
     
     
    // ****************************
    //     TÂCHE GLOBALE
    // ****************************
    const uint16_t pulsation = 1000U; // mise à jour une fois par seconde
    const uint32_t  tempsTotal = 1000UL * 60UL * 60UL; // 60 minutes = 3 600 000 ms
    uint32_t chronometre = 0;
     
    void gestionGlobale()
    {
      // pulsation pour montrer que tout va bien, on fait clignoter la LED
      if (millis() - chronometre >= pulsation) {
        if (millis() < tempsTotal) {  // si on considère que le début du jeu est au boot
          uint32_t tempsRestant = (tempsTotal - millis()) / 1000; // en secondes
          lcd.setCursor(0, 0); lcd.print(F("TEMPS:"));
          if (tempsRestant >= 60) {
            lcd.print(tempsRestant / 60); lcd.print("min");
          }
          lcd.print(tempsRestant % 60); lcd.print("s    ");
     
        } else {
          // LE TEMPS EST EXPIRE. FAIRE CE QU'IL FAUT !
          lcd.setCursor(0, 0); lcd.print(F("VOUS AVEZ PERDU"));
        }
        chronometre += pulsation;
      }
    }
     
     
     
     
     
    // ****************************
    //            MENU
    // ****************************
    /*uint32_t tickMenu;
     
      void setupMenu()
      {
      //tickMenu = currentTaskStartTime;
      }
     
      t_taskID loopMenu()
      {
      // faire une étape de la tâche courante
      //if (millis() - tickMenu >= 5000U) {
      //  tickMenu += 5000U;
      //}
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      //  int c;
      //if (c == 0)  return JEU1;
      //return INCHANGE;
      }
     
      void finMenu()
      {
      // nettoyage éventuel, ici rien de particulier à nettoyer
      }*/
     
     
    // ****************************
    //            JEU 1
    // ****************************
    uint32_t tickJeu1;
     
    #define LED_OFF HIGH
    #define LED_ON LOW
     
    // les pins à mettre en correspondance
    const uint8_t pinLEDSource[]  = {30, 32, 34};
    uint8_t pinDestination[] = {31, 33, 35}; // pas const car on va le mélanger
    const size_t nombreDeFils = sizeof(pinLEDSource) / sizeof(pinLEDSource[0]);
     
    enum : uint8_t {NOUVEAU_JEU, JEU_EN_COURS, VICTOIRE} etat;
     
    void imprime()
    {
      for (size_t i = 0; i < nombreDeFils; i++) {
        Serial.print(F("{"));
        Serial.print(pinLEDSource[i]);
        Serial.print(F(" <<->> "));
        Serial.print(pinDestination[i]);
        Serial.print(F("} "));
     
        lcd.setCursor(0, 1); lcd.print("Connectez fils");
      }
      Serial.println();
    }
     
    bool cablageCorrect()
    {
      // on fait clignoter la Source et on regarde si on voit ce signal sur la destination
     
      const uint8_t nombreDeClignotements = 3;
      size_t nbFilsCorrects = 0;
     
      for (size_t unFil = 0; unFil < nombreDeFils; unFil++) {
        bool erreur = false;
     
        for (uint8_t n = 0; n < nombreDeClignotements; n++) {
          digitalWrite(pinLEDSource[unFil], LED_ON);
          erreur = (digitalRead(pinDestination[unFil]) != LED_ON);
          if (erreur) break;
          digitalWrite(pinLEDSource[unFil], LED_OFF);
          erreur = (digitalRead(pinDestination[unFil]) != LED_OFF);
          if (erreur) break;
        }
        if (erreur) {
          digitalWrite(pinLEDSource[unFil], LED_OFF);
        } else {
          // le fil est bon on laisse la LED allumée
          digitalWrite(pinLEDSource[unFil], LED_ON);
          nbFilsCorrects++;
     
        }
      } // fin de pour chaque fil
      return (nbFilsCorrects == nombreDeFils);
    }
     
    void melange()
    {
      // algo cf <a href="https://fr.wikipedia.org/wiki/Mélange_de_Fisher-Yates" target="_blank">https://fr.wikipedia.org/wiki/Mélange_de_Fisher-Yates</a>
      for (size_t i = nombreDeFils - 1; i >= 1; --i) {
        size_t j = random(0, i + 1);
        uint8_t echange = pinDestination[i];
        pinDestination[i] = pinDestination[j];
        pinDestination[j] = echange;
      }
    }
     
    // -----------------
     
     
    void setupJeu1()
    {
     
      tickJeu1 = currentTaskStartTime;
      randomSeed(analogRead(A0));
     
      for (size_t i = 0; i < nombreDeFils; i++) {
        pinMode(pinLEDSource[i], OUTPUT);
        digitalWrite(pinLEDSource[i], LED_OFF);
        pinMode(pinDestination[i], INPUT_PULLUP);
      }
      etat = NOUVEAU_JEU;
    }
     
     
     
    t_taskID loopJeu1()
    {
      switch (etat) {
     
        case NOUVEAU_JEU:
          melange();
          imprime();
          etat = JEU_EN_COURS;
          break;
     
        case JEU_EN_COURS:
          if (cablageCorrect()) etat = VICTOIRE;
          delay(500);
          break;
     
        case VICTOIRE:
          Serial.println(F("VICTOIRE"));
          for (uint8_t n = 0; n < 20; n++) {
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_OFF);
            delay(50);
            for (size_t i = 0; i < nombreDeFils; i++)
              digitalWrite(pinLEDSource[i], LED_ON);
            delay(50);
          }
          return JEU2;
          break;
      }
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      //int c = Serial.read(); // retourne -1 s'il n'y a rien à lire
      //if (c == 'F') return MENU;
      return INCHANGE;
     
    }
     
    void finJeu1()
    {
      Serial.println(F("\tFIN JEU #1"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
     
    // ****************************
    //            JEU 2
    // ****************************
    uint32_t tickJeu2;
     
    #include <SPI.h>
    #include <MFRC522.h>
    #define RST_PIN 5
    #define SS_PIN 53
    MFRC522 mfrc522(SS_PIN, RST_PIN);
     
    uint8_t carteAleatoire;
     
    //Je déclare deux tableaux qui contient les identifiants des cartes rfid et nol associé
    // On définit le type carte
    struct t_carte {
      const char* nom;
      uint32_t UID;
    };
     
    t_carte jeuDeCartes[] = {   // préférer le nom du type sous forme t_xxx car le format xxx_t est réservé par la norme aux types officiels
      {"Colonel", 0x1965669A}, // Attention little Endian -> les octets de poids faibles seront en premier en mémoire
      {"General", 0x1A72690A},
      {"President", 0x196A7AFA},
      {"Secrétaire", 0x195E6C7A},
      {"Soldat", 0x19A94B1A},
      {"Entretien", 0x5FA7BFB7},
      //{"Administrateur", 0x2A7A3080}
    };
     
    const int nombreDeCartes = sizeof(jeuDeCartes) / sizeof(jeuDeCartes[0]);
     
    void choisirCarteAleatoire()
    {
      carteAleatoire = random(0, nombreDeCartes); // un nombre entier entre 0 et nombreDeCartes-1
      Serial.print(F("Nouvelle Carte Aleatoire: "));
      Serial.print(jeuDeCartes[carteAleatoire].nom);
      Serial.print(F("\t0x"));
      Serial.println(jeuDeCartes[carteAleatoire].UID, HEX);
      lcd.setCursor(0, 1); lcd.print("SCANNER "); lcd.print(jeuDeCartes[carteAleatoire].nom);
    }
     
     
    void setupJeu2()
    {
      tickJeu2 = currentTaskStartTime;
      while (!Serial);
     
     
      choisirCarteAleatoire();
    }
     
    t_taskID loopJeu2()
    {
      if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      if ( ! mfrc522.PICC_ReadCardSerial()) return;
      // on a une carte dont le N° est dans le tableau mfrc522.uid.uidByte
     
      if (jeuDeCartes[carteAleatoire].UID == *((uint32_t*) mfrc522.uid.uidByte)) {
        //Serial.println("ACCES AUTORISE");
        lcd.setCursor(0, 1);
        lcd.print("ACCES AUTORISE  ");
        //choisirCarteAleatoire();
        return END;
      } else {
        //Serial.println("STOP");
        lcd.setCursor(0, 1);
        lcd.print(" Mauvaise carte  ");
      }
      // faire une étape de la tâche courante
      //if (millis() - tickJeu2 >= 5000U) {
      // tickJeu2 += 5000U;
     
     
      // ici retourner INCHANGE si l'état suivant reste identique, sinon le nouvel état
      return INCHANGE;
    }
     
    void finJeu2()
    {
      Serial.println(F("\tFIN JEU #2"));
      // nettoyage éventuel, ici rien de particulier à nettoyer
    }
     
    //*****************************
    //        FIN DU JEU
    //*****************************
    uint32_t tickEnd;
     
    void setupEnd ()
    {
      Serial.println(F("Partie terminée"));
      lcd.clear();
      lcd.setCursor(0, 0); lcd.print(" VOUS AVEZ GAGNE ");
      lcd.setCursor(0, 1); lcd.print("   Bravo a vous  ");
    }
    t_taskID loopEnd() {return INCHANGE;}
    void finEnd() {}
    // ****************************
    //     PROGRAMME PRINCIPAL
    // ****************************
     
    void setup()
    {
      Serial.begin(115200);
      pinMode(LED_BUILTIN, OUTPUT);
     
      // AUTRES INITIALISATIONS
     
      //decompte
      // Pour activer l'état HOLD
      unsigned int time_hold = 4;
     
      //Ecran
      lcd.init();
      // Print a message to the LCD.
      lcd.backlight();
      // On donne le point d'entrée de notre programme général
      etablirNouvelleTache(JEU1);
     
      //RFID
      SPI.begin();
      mfrc522.PCD_Init();
     
      randomSeed(analogRead(A0)); // génération d'un peu d'aléatoire
    }
     
     
    void loop()
    {
     
      gestionGlobale();
      gestionEtat();
     
    }

  20. #20
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 921
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 921
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      if ( ! mfrc522.PICC_ReadCardSerial()) return;
    -> il faut faire un return INCHANGE; (le compilateur doit vous mettre un warning à mon avis vu que vous ne respectez pas le type pour le return... faut en tenir compte!)

    faut-il faire un bout de code dans le loopGeneral, si action=END alors stop décompte?
    ben oui

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [Temps réél] Jeux web mmo
    Par anthyme dans le forum Développement 2D, 3D et Jeux
    Réponses: 8
    Dernier message: 21/02/2008, 21h36
  2. Programme de recherche temps d'execution trop long
    Par lucas67 dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 21/11/2007, 15h15
  3. lancer 16 programmes en même temps
    Par piotr dans le forum Langage
    Réponses: 9
    Dernier message: 23/03/2007, 16h31
  4. suspendre le déroulement du programme pendant un temps déterminé
    Par yvanovitch dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 11/12/2006, 13h00
  5. Comment sont programmés les plug-ins de jeux
    Par Marneus dans le forum Développement 2D, 3D et Jeux
    Réponses: 2
    Dernier message: 25/11/2005, 18h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo