Le titre est quelque peu provocateur, car le dicton est connu pour avoir un double sens. Mais ce n'est explicitement pas le cas ici. Nous voulons vous montrer comment extraire des sons de votre micro-contrôleur (AVR). L'idée du blog est née parce qu'après avoir passé de nombreuses années à m'occuper de Raspberry Pis et de microcontrôleurs, j'ai appris qu'il existe des buzzers (avertisseurs sonores) actifs et passifs. Jusqu'à présent, je ne me suis apparemment trompé que par accident lorsque mes élèves ont programmé et essayé de petits programmes, comme un jeu de réaction, au seuil de douleur de mes oreilles.
Matériel utilisé
Tout |
microcontrôleur compatible avec Arduino (AVR) |
1 |
|
1 |
|
ou encore |
Dans ce jeu de réaction pour deux joueurs, le but est d'appuyer sur votre bouton le plus rapidement possible lorsque le buzzer se met à sonner après un temps choisi au hasard. Maintenant je sais : pour cela, il faut un buzzer actif, comme ceux installés dans notre machine à laver ou notre sèche-linge. Le buzzer actif possède un oscillateur intégré, qui produit le son du buzzer lorsque la tension de 3,3V ou 5V est appliquée. En raison de sa conception, vous devez faire attention à la polarité du buzzer. A la livraison, ces buzzers sont généralement munis d'un petit autocollant avec le signe plus et la mention "REMOVE SEAL AFTER WASHING". Il y a également un + sur le composant lui-même. Il faut regarder deux fois pour voir la jambe la plus longue. Vous pouvez aussi utiliser un petit circuit imprimé comme celui qui se trouve dans le kit de capteurs 35 en 1. Ici, les contacts sont marqués par S (=signal) et - (moins). Le troisième connecteur (du milieu) n'est pas connecté. Vous pouvez essayer le buzzer avec un simple sketch comme Blink, où la broche (presque) quelconque est commutée à HIGH pendant une seconde et à LOW pendant une seconde avec digitalWrite().
Le buzzer passif n'a pas d'oscillateur intégré, le micro contrôleur doit donc prendre en charge cette fonction. Si vous essayez le sketch ci-dessus sur un buzzer passif, vous entendrez un léger clic toutes les secondes, rien de plus. Cependant, si l'on raccourcit extrêmement le temps de pause (delay(1) ou delay(2)), on peut entendre un son dont on peut facilement calculer la fréquence : une milliseconde par HIGH ou LOW signifie (en négligeant le temps d'exécution des autres commandes) environ 500 cycles on/off par seconde, c'est-à-dire 500Hz.
Avec le petit bout de code suivant, vous pouvez générer une courte tonalité d'avertissement sur la broche (précédemment définie) pour le buzzer :
int var = 0;
while (var < 100) {
// do something repetitive 100 times
digitalWrite(Buzzer, HIGH);
delay(1);
digitalWrite(Buzzer, LOW);
delay(1);
var++;
}
Mieux encore, la génération de tonalités fonctionne avec la fonction tone(), qui ne peut toutefois générer qu'un seul signal sonore (une seule fréquence) sur une seule broche. Les explications suivantes s'appliquent au buzzer passif ou également à un petit haut-parleur, qui est connecté à la broche correspondante via une résistance de 100 Ohms.
La syntaxe est la suivante :Tonalité (épingle, fréquence) ou alors
Tonalité (broche, fréquence, durée)
Les paramètres utilisés sont :
pin : La broche Arduino sur laquelle le son doit être généré.
frequency : La fréquence du son en Hertz. Types de données autorisés : unsigned int.
duration : La durée du son en millisecondes (facultatif). Types de données autorisés : unsigned long.
A moins qu'un troisième paramètre ne soit spécifié pour la durée, la fréquence est émise sur le buzzer passif (ou alternativement un petit haut-parleur) jusqu'à ce qu'une nouvelle assignation de fréquence soit faite ou que la fonction noTone(pin) soit appelée.
Cependant, le fait de spécifier le paramètre de durée ne signifie pas (!) que vous pouvez jouer une gamme de cette manière. Les notes suivantes "descendent", sauf si vous ajoutez une pause avec delay() dans le sketch. Mais vous pouvez alors omettre la durée lorsque vous jouez une mélodie. Donc : n'utilisez la durée que si vous voulez jouer un seul son (d'avertissement) pendant une courte durée.
En ce qui concerne les fréquences, nous ne sommes pas épargnés par un voyage dans la musique ou la physique. Les quelques éléments dont je me souviens sont le diapason de concert A = 440 Hz et la division par deux ou par deux de la fréquence par octave. Il est recommandé d'utiliser la notation américaine pour les noms de variables, c'est-à-dire A4=440Hz, A3=220Hz, A5=880Hz. Avec les chiffres, on nomme les octaves respectives, par exemple au piano. Pour les autres notes, malheureusement, il n'y a pas toujours de fréquences entières (rappel : type de données requis = unsigned int) ; la cacophonie est donc inévitable à cause du système, mais comme une seule fréquence est jouée à la fois, elle reste supportable et la mélodie reste reconnaissable.
Il est préférable de définir les notes au début de l'esquisse, par exemple pour la quatrième octave avec le diapason de concert La :
Vous pouvez également prendre le fichier pitches.h de l'exemple de sketch toneKeyboard, dans lequel toutes les notes de 31 Hz à 4,978 KHz sont définies.
Les fichiers de l'exemple sont situés dans le dossier du programme de l'IDE Arduino dans le sous-répertoire "examples" :
Copiez ce fichier et enregistrez-le dans votre dossier Sketch ; incluez-le ensuite dans le Sketch avec #include "pitches.h".
Sur internet, j'avais vu un sketch avec "Tous mes canetons ...", qui sonnait terriblement mal, car aucune pause n'était insérée entre les notes individuelles ; cela dérange surtout si une note est répétée. Ainsi, si vous voulez entendre les notes individuelles d'une mélodie comme sur un piano, vous devez arrêter la sortie du son avec noTone() et une autre pause après le premier delay(). Les deux pauses déterminent ensemble la longueur d'une note ; il faut donc définir ces valeurs avec une variable, par exemple pour le nombre de millisecondes d'une note noire.
Dans le sketch suivant, j'ai aggravé le cas de "Tous mes canetons ...", en fixant la durée du son audible avec int DELAY = 400 ; et la pause avec int PAUSE = 100 ;. La durée d'une noire est donc de 500 ms. Comme décrit ci-dessus, j'ai placé le fichier pitches.h dans le dossier sketch.
/* Alle meine Entchen ... einmal abgespielt
* Die Datei pitches.h muss sich im gleichen Dateiordner befinden
*/
int DELAY = 400;
int PAUSE = 100;
void setup() {
tone(7, NOTE_C5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_D5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_E5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_F5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_G5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_A5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_F5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_F5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_F5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_F5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_E5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_E5);
delay(2*DELAY);
noTone(7);
delay(2*PAUSE);
tone(7, NOTE_G5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_G5);
delay(DELAY);
noTone(7);
delay(PAUSE);
tone(7, NOTE_C5);
delay(2*DELAY);
noTone(7);
}
void loop() {
//keine zu wiederholende Aktion
}
Comme vous pouvez le constater, ce n'est pas un chef-d'œuvre de l'art de la programmation. Mais certainement bon à utiliser si vous voulez simuler une sirène à deux tons comme dans un véhicule de secours.Pour les mélodies plus longues, l'approche à deux tableaux est plus adaptée, comme décrit dans notre eBook. Ici, la mélodie de Pirates des Caraïbes publiée sur Internet est liée :
https://github.com/xitangg/-Pirates-of-the-Caribbean-Theme-Song
Dans le premier tableau int notes[] sont listées les notes, dans le second int durations[] la durée respective du ton. Comme dans les autres exemples, la mélodie n'est jouée qu'une seule fois, le code du programme à exécuter se trouve donc dans le void setup() ; le void loop() reste vide.
Voici les explications du sketch :
Afin de répéter correctement la boucle for pour toutes les notes, le nombre de notes totalNotes est d'abord déterminé à l'aide de la fonction sizeof(). Comme cette fonction renvoie le nombre d'octets dans le tableau, il faut encore le diviser par le nombre d'octets par entier, c'est-à-dire par 2.
Les valeurs respectives des tableaux sont stockées temporairement dans les variables currentNote et wait. Pour les pauses marquées par 0 dans le tableau, la fonction noTone() est appelée.
Voici juste la section void setup() de l'esquisse :
void setup()
{
const int totalNotes = sizeof(notes) / sizeof(int);
// Loop through each note
for (int i = 0; i < totalNotes; i++)
{
const int currentNote = notes[i];
float wait = durations[i] / songSpeed;
// Play tone if currentNote is not 0 frequency, otherwise pause (noTone)
if (currentNote != 0)
{
tone(buzzer, notes[i], wait); // tone(pin, frequency, duration)
}
else
{
noTone(buzzer);
}
// delay is used to wait for tone to finish playing before moving to next loop
delay(wait);
}
}
Il existe d'autres bibliothèques de programmes pour les cartes microcontrôleurs ATmega328P/ATmega16U2 (AVR) pour émettre des tonalités, par exemple pour émettre deux tonalités en même temps sur des broches différentes. Mais celles-ci sont parfois très complexes et le résultat donne autant à réfléchir que la simple sortie de tons avec tone(). Notre microcontrôleur polyvalent convient à de nombreuses applications, mais certainement pas à la synthèse.
GPIO Zero Reaction Game für Raspberry Pi
Ici je vous lie un petit jeu pour le Raspberry Pi, pour lequel en plus du buzzer des boutons et des LEDs (ainsi que des résistances) sont utilisés. Vous pouvez trouver une description plus détaillée dans le code source.
Download : gpiozero_reactentgame_nochenating.py
Conclusion
Si vous souhaitez émettre un bref signal d'avertissement, vous devez utiliser un buzzer actif qui s'allume et s'éteint comme une LED (ou en parallèle). Il faut faire attention à la polarité.
Si vous voulez programmer une sirène à deux tons (qui s'entend plus clairement) ou une courte mélodie de reconnaissance (jingle), vous devez utiliser un buzzer passif ou un petit haut-parleur.