Factorisation du code logiciel
Pour factoriser le code logiciel précédent, vous allez créer la fonction “JouerNote” qui va prendre pour argument la fréquence de la note et le nombre de temps:
void JouerNote(unsigned int Note_P, unsigned int NombreTemps_P) { tone(8, Note_P, NombreTemps_P * DUREE_TEMPS); delay(NombreTemps_P * DUREE_TEMPS); }
Vous pouvez alors remplacer les instruction logicielle localisée dans la fonction “loop” par les suivantes:
// Jeu des 11 premières notes de "Au clair de la lune" JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_MI, 2); JouerNote(OCTAVE_4_RE, 2); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_MI, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_DO, 4);
Voici à quoi devrait ressembler votre programme maintenant:
// Définition des fréquences des notes de musiques de la 4ème octave #define OCTAVE_4_DO 523 #define OCTAVE_4_RE 587 #define OCTAVE_4_MI 659 #define OCTAVE_4_FA 698 #define OCTAVE_4_SOL 784 #define OCTAVE_4_LA 880 #define OCTAVE_4_SI 988 // Définition de la durée d'un temps en millisecondes #define DUREE_TEMPS 300 // Fonction de démarrage, s'exécute une seule fois: void setup() { } // Fonction principale du programme, s'exécute en boucle: void loop() { // Jeu des 11 premières notes de "Au clair de la lune" JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_MI, 2); JouerNote(OCTAVE_4_RE, 2); JouerNote(OCTAVE_4_DO, 1); JouerNote(OCTAVE_4_MI, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_RE, 1); JouerNote(OCTAVE_4_DO, 4); } void JouerNote(unsigned int Note_P, unsigned int NombreTemps_P) { // Lance l'émission de la note tone(8, Note_P, NombreTemps_P * DUREE_TEMPS); // Attend que la note soit terminée de jouée delay(NombreTemps_P * DUREE_TEMPS); }
Afin de le vérifier, vous pouvez maintenant compiler ce programme puis le transférer dans l’Arduino. Vous devez obtenir le résultat suivant:
Et là vous sentez que quelque-chose cloche dans la mélodie !? En effet Arduino enchaine les notes d’ “Au clair de la lune” les unes à la suite des autre sans qu’aucun silence ne permette de les découper. Nous allons donc modifier notre programme pour laisser un petit temps de silence entre chaque note.
Amélioration de la mélodie:
A l’aide de la directive “#define” utilisée précédemment, nous commençons par définir la durée de cette pause (90 ms par exemple) :
// Définition de la pause de fin de note en millisecondes #define PAUSE_FIN_NOTE 90
Puis nous modifions la fonction “JouerNote” pour y ajouter ce petit silence:
void JouerNote(unsigned int Note_P, unsigned int NombreTemps_P) { // Lance l'émission de la note tone(8, Note_P, NombreTemps_P * DUREE_TEMPS); // Attend que la note soit terminée de jouer delay(NombreTemps_P * DUREE_TEMPS); // Petit silence avant la note suivante delay(PAUSE_FIN_NOTE); }
Et voilà le résultat:
Pour continuer:
J’espère que ce projet vous a plu. Si vous souhaitez aller plus loin avec la carte Arduino Uno, voici deux projets qui pourrait vous intéresser:
Bonjour,
Merci pour cette explication fort bien documentée et détaillée d’ utilisation d’une mélodie d’attente.
Par ailleurs, la plus gracieuse à l’oreille parmi d’autres. Chapeau, pour une personne ne pratiquant pas la musique.
J’aimerais en faire usage sur un répondeur piloté par une carte nano, toutefois delay gênerait le bon déroulement d’autres fonctions simultanées synchronisées en millis.
Auriez-vous SVP l’amabilité de m’indiquer comment vous procéderiez en remplaçant delay par millis dans l’ensemble de votre code. Merci d’avance et encore bravo pour ce joli travail.
Pierre.
Bonsoir Pierre,
Pour dérouler d’autres fonctions simultanées synchronisées par l’utilisation de l’instruction « millis() », je remplacerais la fonction « JouerNote » par une fonction non-bloquant qui retournerait le temps à attendre avant de jouer la note suivante :
long DemarrerNote(unsigned int Octave_P, unsigned int NombreTemps_P)
{
// Lance l’émission de la note
tone(8, Octave_P, NombreTemps_P * DUREE_TEMPS);
// Retourne le délai à attendre avant de jouer la note suivante
return(NombreTemps_P * DUREE_TEMPS + PAUSE_FIN_NOTE);
}
Également, je stockerais les notes dans un tableau global afin de pouvoir les jouer successivement à l’aide d’un index parcourant ce tableau :
typedef struct
{
unsigned int Octave;
unsigned int NombreTemps;
} StrNote;
// Melodie à jouer
StrNote Melodie_G[] = {
{OCTAVE_4_DO, 1},
{OCTAVE_4_DO, 1},
{OCTAVE_4_DO, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_MI, 2},
{OCTAVE_4_RE, 2},
{OCTAVE_4_DO, 1},
{OCTAVE_4_MI, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_DO, 4},
{0, 0}
};
Si par exemple on prend comme fonction simultanée l’envoi d’un maximum de caractère « . » sur l’interface série, le programme devient :
// Définition des fréquences des notes de musiques de la 4ème octave
#define OCTAVE_4_DO 523
#define OCTAVE_4_RE 587
#define OCTAVE_4_MI 659
#define OCTAVE_4_FA 698
#define OCTAVE_4_SOL 784
#define OCTAVE_4_LA 880
#define OCTAVE_4_SI 988
// Définition de la durée d’un temps en millisecondes
#define DUREE_TEMPS 300
// Définition de la pause de fin de note en millisecondes
#define PAUSE_FIN_NOTE 90
typedef struct
{
unsigned int Octave;
unsigned int NombreTemps;
} StrNote;
// Melodie à jouer
StrNote Melodie_G[] = {
{OCTAVE_4_DO, 1},
{OCTAVE_4_DO, 1},
{OCTAVE_4_DO, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_MI, 2},
{OCTAVE_4_RE, 2},
{OCTAVE_4_DO, 1},
{OCTAVE_4_MI, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_RE, 1},
{OCTAVE_4_DO, 4},
{0, 0}
};
unsigned int NoteCourante_G = 0;
unsigned long HeurePrecedente_L = 0;
unsigned long IntervalEntre2Note_L = 0;
// Fonction de démarrage, s’exécute une seule fois:
void setup()
{
Serial.begin(57600); // Ouverture du port série à 57600 bauds
}
// Fonction principale du programme, s’exécute en boucle:
void loop()
{
unsigned long HeureCourante_L = millis();
if(HeureCourante_L – HeurePrecedente_L > IntervalEntre2Note_L)
{
// Sauvegarde de l’heure du dernier démarrage de jeu de note
HeurePrecedente_L = HeureCourante_L;
// C’est le moment de lancer le jeu d’une note
IntervalEntre2Note_L = DemarrerNote(Melodie_G[NoteCourante_G].Octave,Melodie_G[NoteCourante_G].NombreTemps);
if(Melodie_G[NoteCourante_G+1].Octave!=0)
{
NoteCourante_G++; // On passe à la note suivante
}
else
{
NoteCourante_G=0; // C’était la dernière note de la mélodie, on recommence depuis le début
}
}
else
{
// On a le temps de faire autre chose comme d’envoyer plein de caractères sur le port série.
Serial.print(“.”);
delay(10);
}
}
long DemarrerNote(unsigned int Octave_P, unsigned int NombreTemps_P)
{
// Lance l’émission de la note
tone(8, Octave_P, NombreTemps_P * DUREE_TEMPS);
// Retourne le délai à attendre avant de jouer la note suivante
return(NombreTemps_P * DUREE_TEMPS + PAUSE_FIN_NOTE);
}
Voilà, j’espère que cette solution vous a aidé dans votre projet. 🙂
Merci Nico pour votre réponse si rapide et avec autant de détail.
j’apprécie énormément votre aide; notamment d’avoir composer un code complet.
Il me reste à le transcrire sur l’IDE Arduino et le tester , ce dont je ne doute pas.
Encore mille mercis Nico.
komen on brenche svépé ?
Bonjour orto … graphe ?
Le câblage du montage est décrit au chapitre suivant:
https://tropratik.fr/au-clair-de-la-lune-avec-arduino#Cablage-du-haut-parleur-avec-votre-carte-Arduino
Salut je voudrais savoir si il est possible d’ajouter un bouton pour jouer la mélodie quand on le souhaite, si possible veut tu bien me dire comment le brancher et introduire le bouton dans le code.
Merci,
Cordialement
On est en TP de physique et on y arrive pas, on pourrait avoir de l’aide svp ?
HELP
Je suis la pour t’aider si tu veux
bon courage au groupe 2 de la classe 2GT1
BISOU
merci