Bonsoir lec3pu
Je dois dire que je me suis laissé "emballer" pas le sujet, à tel point que j'ai terminée le programme, ou presque. En même temps il est difficile de répondre aux questions, qui, souvent, s'imbriquent. Le programme, tu le prends si tu veux ou tu piques des bouts. Pour la commutation de tes paramètres et des miens, pour éviter des "incidents" il y a cette ligne au tout début:
#define lec3pu
Si non commentée c'est tes paramètres
Si commentée, c'est les miens
Er, ensuite, c'est aiguillé par #ifdef lec3pu
Ca doit se faire en faisant clignoter ta LED en utilisant les millis()(exemple BlinkWithoutDelay.ino). Actuellement, ta loop()
est bloquée par des return tant que les 2 conditions if(!mfrc522
. ne sont pas remplies, c'est gênant et surtout, pas très "élégant" (à mon avis)
Une chose à faire est de supprimer ces return
en écrivant les tests conditionnels différemment:
void loop()
{
if(mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
{
... Actions à la lecture d'une carte
}
}
Le compteur de temps est à déclencher au début d'une partie, à la lecture du premier badge.
if (ordre.luNombre == 1) // Si premier badge
{
ordreBlinkMillis = millis(); // Démarrage clognotement de la LED
digitalWrite(LED_BLEU, HIGH);
}
et le clignotement se fait dans loop()
//--------------------------------- Clignotement
if (ordreBlinkMillis != 0 && (millis()-ordreBlinkMillis >= ordreBlinkTempo))
{
digitalWrite(LED_BLEU, !digitalRead(LED_BLEU)); // Inverser la LED
ordreBlinkMillis = millis();
}
Pour ce faire, j'ai créé une structure ordre:
//------------------------------------- Ordre de lecture des badges
struct OrdreDef
{
String voulu;
int vouluNombre;
String lu;
int luNombre;
};
et initialisé dans partieDemarrage():
ordre.voulu = "0-3-2-1-";
ordre.lu = "";
Les chiffres correspondent à la position de l'UID dans le tableau uidListe[]
Une partie débute à la lecture du premier badge.
Ainsi quand ordre.lu à la même longueur que ordre.voulu
la partie se termine et le résultat évalué dans partieFin()
Le même badge peut être passé plusieurs fois mais est enregistré qu'une fois dans ordre.lu.
//------------------------------------- Ordre ajouter ok si nombre atteint
void ordreAjouterUid(int uidIndex)
{
String ordreAjout = String(uidIndex) + "-"; // Ce qui sera ajouté à uidLu
if (ordre.lu.indexOf(ordreAjout, 0) == -1) // Si pas encore
{
ordre.lu += ordreAjout;
}
}
C'est sa première lecture qui définit son emplacement dans ordre.lu
Pendant une partie, à chaque passage de badge, l'affichage indique:
et, à la fin:
La durée de la partie est définie par la variable partieDuree
et est gérée ici, dans loop():
//--------------------------------- Partie chrono
if (partieDureeMillis != 0 && ((millis()-partieDureeMillis >= 1000))) // Toutes les secondes
{
Il y a un badge Manager qui permet d'arrêter une partie en cours, il est défini ici:
const String uidManager = "uid du manager";
Il y a aussi des indications sur le fonctionnement, dans le moniteur (115200).
Le programme (attention, c'est une toute première version!!!):
/*
Name: ARDFR_EscapeGameRFID.ino
Created: 27.09.2022
Author: https://forum.arduino.cc/t/carre-blanc-lcd-16x2/1035238
*/
//------------------------------------- Définit les paramètres personnels
#define lec3pu
#include<MFRC522.h>
#include<SPI.h>
#include <Wire.h>
#include<Servo.h>
#include <LiquidCrystal_I2C.h>
//------------------------------------- Tableau des UID et pseudo
struct uidListDef
{
const String uid;
const String uidPseudo;
};
const int uidNombre = 4; // A ajuster en fonction de la taille du tableau
#ifdef lec3pu
uidListDef uidListe[] =
{
{"0415915AC03221", "La tortue"},
{"0415916AB36621", "Ours"},
{"6B42EB66", "Serpent"},
{"15AE1CC3", "Chat"},
};
const String uidManager = "A48F951A";
#else
uidListDef uidListe[] =
{
{"076CDAEE", "La vache"},
{"64562705", "Canard"},
{"D780B7BF", "Le Chien"},
{"D30812AB", "Chatton"},
};
const String uidManager = "A48F951A";
#endif
//------------------------------------- Partie
int partieDuree = 0; // Durée de la partie en secondes
int partieDureeDecompte = 0; // Durée de la partie en secondes décompte
unsigned long partieDureeMillis = 0; // Durée de la partie, chrono
//------------------------------------- Ordre de lecture des badges
struct OrdreDef
{
String voulu;
int vouluNombre;
String lu;
int luNombre;
};
OrdreDef ordre;
unsigned long ordreBlinkTempo = 250; // Toutes les 500 milliSecondes
unsigned long ordreBlinkMillis = 0; // Chrono
//------------------------------------- LED et servo
int LED_BLEU = 4;
int LED_ROUGE = 3;
int LED_VERT = 2;
Servo myservo;
MFRC522 mfrc522(10,9);
#ifdef lec3pu
LiquidCrystal_I2C lcd(0x3F,16,2);
#else
LiquidCrystal_I2C lcd(0x27,16,2);
#endif
unsigned long compteur;
boolean uidOrdre(String uidLue) // Retourne true si ordreVoulu est complet
{
//String uidLue = uidLire();
int uidIndex = uidRecherche(uidLue); // Recherche de l'UID dans le tableau
if (uidIndex > -1) // Si uid trouvé
{
ordreAjouterUid(uidIndex);
Serial.println("Ordre voulu\t" + ordre.voulu);
Serial.println("Ordre lu\t" + ordre.lu);
ordre.luNombre = ordreNombreCalcul(ordre.lu);
if (ordre.luNombre == 1) // Si premier badge
{
partieDureeDecompte = partieDuree;
partieDureeMillis = millis(); // Pour chronométrer la partie
ordreBlinkMillis = millis(); // Démarrage clognotement de la LED
digitalWrite(LED_BLEU, HIGH);
}
uidOkDisplay(uidIndex);
digitalWrite(LED_VERT, HIGH);
delay(2000);
digitalWrite(LED_VERT, LOW);
if (ordre.luNombre == ordre.vouluNombre) // Si les ordreVouluNombre basdges lus, partie terminé
{
return true;
}
}
else
{
Serial.print(F(" ACCESS DENIED"));
digitalWrite(LED_ROUGE, HIGH);
lcd.clear();
lcd.print(F(" ACCESS DENIED"));
delay(2000);
digitalWrite(LED_ROUGE, LOW);
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Scannez Tag"));
}
return false; // Partie pas terminé
}
//------------------------------------- Lire la carte
String uidLire()
{
String uid="";
Serial.println();
Serial.print(F("UID : "));
// pour la taille de uid.size écrire uid.uidByte à readCard
for(int i=0;i<mfrc522.uid.size;i++)
{
Serial.print(mfrc522.uid.uidByte[i]<0x10 ? "0" : "");
Serial.print(mfrc522.uid.uidByte[i],HEX);
uid.concat(String(mfrc522.uid.uidByte[i]<0x10 ? "0" : ""));
uid.concat(String(mfrc522.uid.uidByte[i],HEX));
}
uid.toUpperCase();
Serial.println("");
return uid;
}
//------------------------------------- Recherche d'un UID dans la table, -1 si pas trouvé
int uidRecherche(String uidRecu)
{
int uidIndex = -1;
for (int u = 0; u < uidNombre; u ++)
{
if (uidListe[u].uid == uidRecu) // Si uid dans la liste
{
return u; // Retourne l'index de l'UID lu
}
}
return uidIndex;
}
void uidOkDisplay(int uidIndex)
{
Serial.println(uidListe[uidIndex].uid + ":" + uidListe[uidIndex].uidPseudo);
lcd.clear();
lcd.print(F("ACCES OK"));
int lcdCol = ((14/2) - (uidListe[uidIndex].uidPseudo.length()/2))-1; // Pour centrer le texte
lcd.setCursor(lcdCol,1);
lcd.print(uidListe[uidIndex].uidPseudo);
lcd.print(" " + String(ordre.luNombre) + "/" + String(ordre.vouluNombre));
}
//------------------------------------- Ordre ajouter ok si nombre atteint
void ordreAjouterUid(int uidIndex)
{
String ordreAjout = String(uidIndex) + "-"; // Ce qui sera ajouté à uidLu
if (ordre.lu.indexOf(ordreAjout, 0) == -1) // Si pas encore
{
ordre.lu += ordreAjout;
}
}
//------------------------------------- Retourne la longueur de l'ordre
int ordreNombreCalcul(String ordreCalc)
{
String ordreTempo = ordreCalc;
ordreTempo.replace("-", ""); // Supprimer les - pour les compter
return ordreCalc.length() - ordreTempo.length();
}
void managerAction()
{
lcd.clear();
lcd.print(F("Manager action"));
lcd.setCursor(0, 1);
lcd.print(F(" RESTART"));
delay(3000);
partieDemarrage();
}
void setup()
{
Serial.begin(9600);
SPI.begin();
pinMode(LED_ROUGE, OUTPUT);
pinMode(LED_VERT, OUTPUT);
pinMode(LED_BLEU, OUTPUT);
digitalWrite(LED_ROUGE, LOW);
digitalWrite(LED_VERT, LOW);
digitalWrite(LED_BLEU, LOW);
myservo.attach(8);
myservo.write(180);
lcd.init();
lcd.clear();
lcd.backlight();
lcd.print(F("ACCES CONTROL"));
lcd.setCursor(4,1);
lcd.print(F("ESCAPE"));
mfrc522.PCD_Init();
delay(2000); // 10000
partieDemarrage();
}
//------------------------------------- Partie
void partieDemarrage()
{
Serial.println(F("\nScannez Tag Nouvelle partie"));
lcd.clear();
lcd.setCursor(3,0);
lcd.print(F("Scannez Tag"));
ordre.voulu = "0-3-2-1-";
//ordre.voulu = "0-3-";
ordre.lu = "";
partieDuree = 10; // En secondes
partieDureeMillis = 0;
ordreBlinkMillis = 0; // Pour clognotement de la LED (arrêt)
digitalWrite(LED_BLEU, LOW);
ordre.vouluNombre = ordreNombreCalcul(ordre.voulu);
}
void partieFin()
{
Serial.println(F("Fin de partie"));
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Voulu: " + ordre.voulu);
lcd.setCursor(0,1);
lcd.print("Lu: " + ordre.lu);
ordreBlinkMillis = 0; // Pour clognotement de la LED
digitalWrite(LED_BLEU, LOW);
if (ordre.lu == ordre.voulu)
{
digitalWrite(LED_VERT, HIGH);
myservo.write(10);
}
else
{
digitalWrite(LED_ROUGE, HIGH);
}
//--------------------------------- Ouverture porte
delay(5000);
myservo.write(180);
digitalWrite(LED_ROUGE, LOW);
digitalWrite(LED_VERT, LOW);
lcd.clear();
lcd.setCursor(3,0);
lcd.print(F("Scannez Tag"));
lcd.print(ordre.lu);
ordre.lu = "";
}
void loop()
{
//--------------------------------- Clignotement
if (ordreBlinkMillis != 0 && (millis()-ordreBlinkMillis >= ordreBlinkTempo))
{
digitalWrite(LED_BLEU, !digitalRead(LED_BLEU)); // Inverser la LED
ordreBlinkMillis = millis();
}
//--------------------------------- Partie chrono
if (partieDureeMillis != 0 && ((millis()-partieDureeMillis >= 1000))) // Toutes les secondes
{
partieDureeDecompte --; // Décompter les secondes
Serial.println("Duree partie: " + String(partieDureeDecompte) + " sec.");
if (partieDureeDecompte <= 0) // Si temps échu
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Temps imparti"));
lcd.setCursor(0,1);
lcd.print(F("echu"));
partieDureeMillis = 0; // Désactiver le chrono
delay(5000);
partieDemarrage();
}
else
{
lcd.setCursor(12, 0); // Affichage temps restant
lcd.print(String(partieDureeDecompte) + " ");
partieDureeMillis = millis();
}
}
//--------------------------------- Lecture du badge
if(mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
{
String uid = uidLire();
if (uid == uidManager) // Si badge du manager
{
managerAction();
}
else
{
if (uidOrdre(uid)) // Si ordre complet, fin de partie
{
partieFin();
partieDemarrage();
}
}
}
}
On pourrai, à l'avenir, imaginer, pour le fun, commander ce programme depuis un smartphone
A ton entière disposition pour toutes questions.
Bonne lecture et bonne soirée.
Cordialement
jpbbricole