Bonjour,
Je travaille sur un projet de jeu musical pour les enfants, le principe est le suivant : une musique est joué au hasard, l'enfant doit reconnaitre l'instrument entendu, et pose la carte correspondante, si c'est gagné, une led verte s'allume et on entend un jingle et une voix qui donne le nom de l'instrument, puis le jeu recommence, si c'est perdu, on entend un autre jingle, la led rouge s'allume, et on entend à nouveau le même morceau.
pour ce projet j'utilise : 1 arduino nano, 1 module rfid rc522, 2 led, 1 interrupteur (pour sélectionner un mode facile ou difficile), et un bouton suivant.
Mon code fonctionne 95% du temps, mais de temps en temps, j'ai un bug.
Soit le morceau suivant s'arrête avant même d'avoir commencé et du coup le programme se bloque en mode écoute, je pense que le problème vient du DFplayer qui envoie 2 fois de suite le message play finished.
J'ai parfois un autre bug, j'ai 2 musiques qui sont jouées en même temps... étrange
Est-ce que mon code est en cause ?
[code]
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <SPI.h>
#include <MFRC522.h>
#include <Bounce2.h>
#include <Chrono.h>
#define SS_PIN 10
#define RST_PIN 9
// Jeu de reconnaissance d'instruments avec cartes RFID, 2 modes :
// mode facile : 1 instrument seul est entendu
// mode difficile : reconnaitre l'instrument dans un duo ou trio.
// 11 instruments à trouver, possibilité d'en rajouter en rajoutant d'autres cartes
// sdcard : chaque dossier correspond à 1 instrument,
// dans chaque dossier 1er mp3 : instrument solo,
// les autres fichiers : Duos ou trios contenant 1 seul instrument à trouver
const byte redLedPin = 6;
const byte greenLedPin = 5;
const byte interPin = 4;
const byte buttonPin = 3;
//const byte busyPin = 7;
Chrono timer;
Bounce interMode = Bounce();
Bounce nextButton = Bounce();
SoftwareSerial mySoftwareSerial(2, 8); // RX, TX
DFRobotDFPlayerMini MP3Player;
// sometime ACK messages sent on software serial seems to create bugs when trying to access to number of files in folders... strange but observed.
// if you get "no file found" too often, then try to set the flag to false.
const bool useMP3Ack = true;
// sometime you should try to disable reset flag, if your SD card isn't recognized at boot... strange but observed.
// if the MP3 does not start properly at boot, then try to set the flag to false.
const bool resetMP3OnBoot = true;
// Set volume value (0~30). /!\ 5 is clearly enough if you don't want to damage your ears !
const byte MP3Volume = 20;
// 90 : bonne réponse, 91 : mauvaise réponse
const byte jingle[2] = { 90, 91 };
enum state { initial, lecture, ecoute, attente, rejouer };
state jeuState = initial;
// mode facile = false (ne joue que le 1er morceau de chaque dossier)
// mode difficile = true (joue tous les morceaux sauf le 1er)
bool mode = false;
bool mp3End = false;
int jeuFlag = -1;
int songIndex = -1;
byte songNb = 0;
int folderNb = -1;
byte lastSongNb;
byte lastFolderNb;
const byte nbCard = 11;
byte playlist[nbCard] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
byte playlistSong[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
int numCarte = -1;
int reponse;
MFRC522 rfid(SS_PIN, RST_PIN);
// UID des cartes
int cartes[nbCard][4] = {
{ 170, 104, 79, 25 },
{ 58, 13, 146, 25 },
{ 26, 254, 81, 25 },
{ 58, 99, 82, 25 },
{ 10, 120, 151, 25 },
{ 234, 49, 76, 25 },
{ 58, 13, 74, 25 },
{ 154, 177, 135, 25 },
{ 26, 112, 77, 25 },
{ 186, 99, 137, 25 },
{ 212, 141, 149, 42 }
};
int newCard[4] = { 0, 0, 0, 0 };
// mélange aléatoire sans répétition de la liste des dossiers de la sdcard
void shuffle() {
for (int i = 0; i < nbCard; ++i) {
int index = random(i, nbCard);
int temp = playlist[i];
playlist[i] = playlist[index];
playlist[index] = temp;
}
}
// mélange aléatoire sans répétition des mp3 contenus dans 1 dossier, 20 fichiers max par dossier
void shuffleSong() {
for (int i = 0; i < 20; ++i) {
int index = random(i, 20);
int temp = playlistSong[i];
playlistSong[i] = playlistSong[index];
playlistSong[index] = temp;
}
}
// vérifie si l'UID fait partie de la liste des cartes référencées rfid
int verifCarte(int carteTest[]) {
byte verif = 0;
for (int n = 0; n < nbCard; n++) {
for (int c = 0; c < 4; ++c ) {
if (carteTest[c] == cartes[n][c]) {
++verif;
}
}
if (verif == 4) {
// Serial.println("Gagné ");
Serial.print("carte n° ");
Serial.println(n);
return n;
}
else {
verif = 0;
}
}
Serial.println("Erreur aucune carte valide");
return -1;
}
// choix dossier suivant dans la playlist, si mode difficile, choix d'un fichier dans le dossier
// si mode facile, 1er mp3 du dossier choisi.
// mélange aléatoire de la playlist lorsque tous les dossiers ont été parcouru 1 fois.
void getRandomFile() {
++folderNb;
++songIndex;
if (folderNb == nbCard) {
folderNb = 0;
songIndex = 0;
shuffle();
shuffleSong();
}
if (mode) {
int nbFilesInFolder = MP3Player.readFileCountsInFolder(playlist[folderNb]);
// sometime, the sd card seems to be lazy. Strange. But fixed by a second try.
if (nbFilesInFolder <= 0)
{
Serial.println("Got no file from the folder. Let's try another time, just in case of a lazy sd card");
delay(100);
nbFilesInFolder = MP3Player.readFileCountsInFolder(playlist[folderNb]);
}
songNb = map(playlistSong[songIndex], 1, 20, 2, nbFilesInFolder);
//Serial.println(songNb);
}
else {
songNb = 1;
}
Serial.print(" dossier n° ");
Serial.println(playlist[folderNb]);
Serial.print(" mp3 n° ");
Serial.println(songNb);
lastFolderNb = folderNb;
lastSongNb = songNb;
}
// led verte allumée si reponse juste, led rouge si réponse fausse
void allumeLed(bool rep) {
if (rep) {
digitalWrite(greenLedPin, HIGH);
digitalWrite(redLedPin, LOW);
}
else {
digitalWrite(redLedPin, HIGH);
digitalWrite(greenLedPin, LOW);
}
}
// extinction des leds
void stopLed() {
digitalWrite(greenLedPin, LOW);
digitalWrite(redLedPin, LOW);
}
// Vérifie si la carte correspond au dossier de la playlist, et donc à l'instrument entendu.
int jeu(int carte) {
mp3End = false;
if (carte + 1 == playlist[lastFolderNb]) {
Serial.println("Bravo, Gagné ");
allumeLed(1);
MP3Player.playMp3Folder(jingle[0]);
delay(2000);
MP3Player.playMp3Folder(playlist[lastFolderNb]);
delay(200);
jeuState = ecoute;
jeuFlag = 1;
}
else {
mp3End = false;
Serial.println("perdu");
allumeLed(0);
MP3Player.playMp3Folder(jingle[1]);
delay(2000);
jeuState = ecoute;
jeuFlag = 0;
}
}
// récupère l'UID de la carte posée, et renvoie le n° de carte correspondant
int readRfid() {
byte verif = 0;
if (rfid.PICC_IsNewCardPresent()) { // new tag is available
if (rfid.PICC_ReadCardSerial()) { // NUID has been readed
MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
//byte card = rfid.uid.uidByte;
//Serial.println(card);
for (int i = 0; i < rfid.uid.size; i++) {
newCard[i] = rfid.uid.uidByte[i];
//Serial.print(rfid.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print("uid carte : ");
Serial.println(rfid.uid.uidByte[i]);
}
for ( int n = 0; n < nbCard; n++) {
for (int c = 0; c < rfid.uid.size; ++c ) {
if (newCard[c] == cartes[n][c]) {
++verif;
}
}
if (verif == 4) {
// Serial.println("Gagné ");
Serial.print("carte n° ");
Serial.println(n);
numCarte = n;
verif = 0;
rfid.PICC_HaltA(); // halt PICC
rfid.PCD_StopCrypto1(); // stop encryption on PCD
reponse = numCarte;
return numCarte;
}
else {
//Serial.println(" carte non trouvée ");
verif = 0;
//numCarte = -1;
}
}
rfid.PICC_HaltA(); // halt PICC
rfid.PCD_StopCrypto1(); // stop encryption on PCD
}
}
for (int i = 0; i < 4; ++i) {
newCard[i] = 0;
}
numCarte = -1;
// if (numCarte == -1) {
// Serial.println("pas de carte posée ou carte invalide");
// }
return numCarte;
}
// gestion de l'interrupteur de mode difficile ou facile
void boutonMode() {
if (interMode.changed()) {
int valeurInter = interMode.read();
if ( valeurInter == LOW) {
mode = true;
Serial.println("mode difficile");
}
else {
mode = false;
Serial.println("mode facile");
}
}
}
// bouton suivant attaché à une interruption
void boutonSuivant() {
MP3Player.pause();
mp3End = false;
Serial.println("suivant");
jeuState = initial;
}
// pour savoir si le mp3 est fini ou non,
void printDetail(uint8_t type, int value) {
switch (type) {
case DFPlayerPlayFinished:
// Serial.print(F("Number:"));
// Serial.print(value);
Serial.println(F(" Play Finished!"));
mp3End = true;
break;
default:
mp3End = false;
break;
}
}
// pour savoir si le mp3 est fini ou non.
void mp3State() {
while (MP3Player.available()) {
printDetail(MP3Player.readType(), MP3Player.read()); //Print the detail message from DFPlayer to handle different errors and states.
}
}
void setup() {
mySoftwareSerial.begin(9600);
Serial.begin(115200);
randomSeed(analogRead(A0));
SPI.begin(); // init SPI bus
rfid.PCD_Init(); // init MFRC522
pinMode(redLedPin, OUTPUT);
pinMode(greenLedPin, OUTPUT);
//pinMode(busyPin, INPUT);
// Use softwareSerial to communicate with mp3,
if ( !MP3Player.begin(mySoftwareSerial, useMP3Ack, resetMP3OnBoot) )
{
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
Serial.println(F("3.If it still fail : try to change MP3 flags in configuration"));
while (true) {
delay(0);
}
}
Serial.println(F("MP3 player ready"));
MP3Player.setTimeOut(800);
MP3Player.pause();
MP3Player.volume(MP3Volume);
MP3Player.EQ(DFPLAYER_EQ_NORMAL); // Set EQ
MP3Player.outputDevice(DFPLAYER_DEVICE_SD); // Set device we use : SD card
delay(2000);
interMode.attach(interPin, INPUT_PULLUP);
nextButton.attach(buttonPin, INPUT);
// interruption sur le bouton suivant, pour permettre de passer au mp3 suivant
// quelque soit l'état du système
attachInterrupt(digitalPinToInterrupt(buttonPin), boutonSuivant, RISING);
interMode.interval(5);
nextButton.interval(5);
// vérifie 1 première fois le mode avant de démarrer la loop
if (interMode.read() == LOW) {
mode = true;
Serial.println("mode difficile");
}
else {
mode = false;
Serial.println("mode facile");
}
// mélange 1 fois avant la loop
shuffle();
}
void loop() {
interMode.update();
nextButton.update();
boutonMode();
int answer = readRfid();
mp3State();
switch (jeuState) {
case initial:
// initialise les variables
stopLed();
jeuFlag = -1;
mp3End = false;
reponse = -1;
MP3Player.pause();
getRandomFile();
jeuState = lecture;
break;
case lecture:
// lance la lecture du Mp3 et se met en attente de réponse à la fin du mp3
//Serial.println("lecture");
MP3Player.playFolder(playlist[folderNb], songNb);
delay(200);
jeuState = ecoute;
break;
case ecoute:
// en cours d'écoute
//Serial.println("ecoute");
if (mp3End) {
Serial.println("mp3 fini");
//Serial.println(MP3Player.readState());
if (jeuFlag == 1) {
jeuState = initial;
}
if (jeuFlag == 0) {
jeuState = rejouer;
}
if (jeuFlag == -1) {
jeuState = attente;
}
}
break;
case rejouer:
// si une mauvaise réponse est donnée, on a droit à un autre essai
// rejoue le dernier mp3 joué
//Serial.println("rejouer");
stopLed();
mp3End = false;
jeuFlag = -1;
reponse = -1;
MP3Player.playFolder(playlist[lastFolderNb], lastSongNb);
delay(200);
jeuState = ecoute;
break;
case attente:
// attente de réponse, et vérifie si la réponse est bonne ou pas
MP3Player.pause();
//Serial.println(mp3End);
// if (answer == -1 && reponse == -1) {
// Serial.println("attente de réponse");
// }
if (reponse != -1) {
jeu(reponse);
}
break;
}
}
[/code]```