Jouer des notes de musiques avec une carte Arduino / Genuino

Faites du bruit !

Image d'entête

par skywodd | | Licence (voir pied de page)

Catégories : Tutoriels Arduino | Mots clefs : Arduino Genuino Musique Chiptune Buzzer

Cet article a été modifié pour la dernière fois le


Dans ce tutoriel, nous allons apprendre à faire du bruit avec une carte Arduino / Genuino ! En bonus, nous retournerons dans le passé avec un lecteur de musique rétro. Quoi de mieux qu'un air de Tetris pour égayer sa journée !

Sommaire

Bonjour à toutes et à tous !

Si vous demandez à un maker ce qu'il aime faire, il vous répondra à coup sûr qu'il aime bricoler, faire des montages qui clignotent et/ou faire de la musique (ou du bruit, en fonction du point de vue).

On aime tous les trucs qui brillent, clignotent et encore plus ceux qui font de la musique (sauf quand il s'agit du jouet du petit frère / neveu / fils du voisin, dans ce cas c'est juste très énervant).

Dans mes précédents articles, on a vu ensemble beaucoup de choses, mais rien permettant d'ajouter une dimension sonore à un projet. Il est grand temps de réparer cette injustice.

Faire de la musique avec tone()

Dans ce chapitre, nous allons étudier les bases de la génération de sons avec une carte Arduino / Genuino. Pour ce faire, nous allons réaliser un montage de test qui nous servira tout au long de ce tutoriel.

N.B. Nous allons uniquement générer des sons dans ce tutoriel, mais il est tout à fait envisageable d'utiliser les informations ci-dessous pour générer des signaux pour un tout autre usage.

Le montage de test

Matériel pour le tutoriel Arduino tone

Matériel nécessaire

Pour réaliser ce montage, il va nous falloir :

  • Une carte Arduino UNO (et son câble USB),

  • Un haut-parleur de 8 ohms (haut-parleur de casque par exemple),

  • Une résistance de 100 ohms (marron / noir / marron),

  • Une plaque d'essai et des fils pour câbler notre montage.

Vue schématique du tutoriel Arduino tone

Vue schématique du montage

Vue prototypage du tutoriel Arduino tone

Vue prototypage du montage

Pour faire ce circuit, il faut commencer par relier une des broches du haut-parleur à la broche D9 de la carte Arduino. L'autre broche du haut-parleur devra quant à elle être reliée à une extrémité de la résistance de 100 ohms.

N.B. Il est possible d'utiliser n'importe quelle broche numérique ou analogique. Le choix de la broche D9 pour ce tutoriel est parfaitement arbitraire, libre à vous de choisir une autre broche si vous le souhaitez.

Photographie du montage du tutoriel Arduino tone

Le montage fini

On achève ensuite le circuit en reliant l'autre extrémité de la résistance de 100 ohms à la broche GND de la carte Arduino avec un fil.

Le code

Générer un son avec une carte Arduino / Genuino est aussi simple que d'appeler la fonction tone() dans un morceau de code.

Le code ci-dessous permet par exemple de générer un La3 à 440Hz, comme un diapason, mais avec une carte Arduino :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
 * Exemple Arduino tone().
 */
 
const byte PIN_BUZZER = 9;

void setup() {
  pinMode(PIN_BUZZER, OUTPUT);

  // Note "La3" 440Hz
  tone(PIN_BUZZER, 440); 
}

void loop() {
  
}

L'extrait de code ci-dessus est disponible en téléchargement sur cette page (le lien de téléchargement en .zip contient le projet Arduino prêt à l'emploi).

La fonction tone() permet de générer un signal carré (50% du temps à 5 volts, 50% du temps à 0 volt) d'une durée et d'une fréquence donnée.

1
2
tone(int broche, unsigned int fréquence);
tone(int broche, unsigned int fréquence, unsigned long durée);

La fonction tone() prend en arguments deux paramètres obligatoires et un paramètre optionnel. Cette fonction ne retourne aucune valeur.

Les paramètres obligatoires sont le numéro de broche sur lequel générer le signal et la fréquence du signal en Hertz (entre 31Hz et 65535Hz pour toutes les cartes Arduino classiques basées sur un microcontrôleur AVR).

Une durée (optionnelle) peut être précisée pour arrêter la génération du signal après un certain nombre de millisecondes. Si la durée n'est pas précisée, le signal est généré indéfiniment jusqu'à un appel à la fonction noTone(), présentée dans le chapitre suivant.

N.B. La fonction tone() est non bloquante, cela signifie qu'elle ne bloque pas le programme durant la durée spécifiée. Si vous souhaitez faire un lecteur de musique rétro par exemple (dont un exemple de code est présenté en bonus, comme par hasard ;) ), il faudra ajouter un delay() après l'appel à tone() pour avoir le bon tempo.

Limitations connues de tone()

La fonction tone() a plusieurs limitations connues à ce jour :

  • un seul signal peut être généré à la fois, sur une seule broche,

  • un appel à tone() sur une broche quand un signal est généré sur une autre broche n'a pas d'effet,

  • un appel à tone() sur une broche quand un signal est généré sur la même broche change immédiatement la fréquence du signal,

  • sur une carte Arduino UNO, l'utilisation de tone() rend impossible l'utilisation des broches D3 et D11 en PWM avec analogWrite().

Annexe : signal carré, tone() et analogWrite()

Illustration square wave

Illustration d'un signal carré

La fonction tone() permet de générer un signal carré d'une fréquence précise et d'un rapport cyclique de 50%. Cela signifie que les temps hauts et bas du signal sont de mêmes durées.

Il ne faut pas confondre la fonction tone() avec la fonction analogWrite() qui semble avoir un comportement semblable aux premiers abords.

La fonction tone() permet de générer un signal de fréquence variable et de rapport cyclique fixe. La fonction analogWrite() permet de générer un signal de fréquence fixe et de rapport cyclique variable. La différence est subtile, mais elle change tout.

Avoir le silence avec noTone()

Comme on a pu le voir dans le chapitre précédent, il est possible d'appeler la fonction tone() avec ou sans durée de génération du signal.

Quand on appelle la fonction tone() sans durée, elle génère un signal indéfiniment, ce qui peut vite devenir très énervant, un peu comme un moustique qu'on n’arriverait pas à attraper.

Heureusement, il existe une fonction, nommée noTone() permettant de retrouver un peu de silence.

1
void noTone(int broche);

Il suffit de donner en paramètre le numéro de broche à la fonction noTone() et celle-ci arrêtera immédiatement la génération de signal sur cette broche, jusqu'au prochain appel à la fonction tone().

PS Vous remarquerez que les fonctions Arduino ci-dessus ont été conçues avec une possible évolution future permettant de générer plusieurs signaux en même temps sur plusieurs broches. Ce n'est pas le cas pour le moment, mais tout a été prévu pour plus tard.

Bonus : un petit air de musique rétro

C'est l'heure du d-d-d-d-du duel chapitre bonus !

Et quoi de mieux qu'un lecteur de musique rétro (chiptune) pour faire un chapitre bonus !

Le code

Le montage est identique à celui du chapitre précédent, je passe donc directement au code ;)

Pour faire de la musique avec tone(), il suffit d'enchainer des appels à tone() et à delay().

Par exemple, pour avoir un petit air de Tetris dans votre bureau :

 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
/**
 * Théme musicale de Tetris en Arduino avec tone()
 */

const byte PIN_BUZZER = 9;

void setup() {
  pinMode(PIN_BUZZER, OUTPUT);
}

void loop() {
  tone(PIN_BUZZER, 2637, 200);
  delay(400);
  tone(PIN_BUZZER, 1975, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 2349, 200);
  delay(400);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 1975, 200);
  delay(200);
  tone(PIN_BUZZER, 1760, 200);
  delay(400);
  tone(PIN_BUZZER, 1760, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 2637, 200);
  delay(400);
  tone(PIN_BUZZER, 2349, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 1975, 200);
  delay(400);
  tone(PIN_BUZZER, 1975, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 2349, 200);
  delay(400);
  tone(PIN_BUZZER, 2637, 200);
  delay(400);
  tone(PIN_BUZZER, 2093, 200);
  delay(400);
  tone(PIN_BUZZER, 1760, 200);
  delay(400);
  tone(PIN_BUZZER, 1760, 200);
  delay(800);
  tone(PIN_BUZZER, 1760, 200);
  delay(400);
  tone(PIN_BUZZER, 2349, 200);
  delay(200);
  tone(PIN_BUZZER, 2794, 200);
  delay(200);
  tone(PIN_BUZZER, 3520, 200);
  delay(400);
  tone(PIN_BUZZER, 3136, 200);
  delay(200);
  tone(PIN_BUZZER, 2794, 200);
  delay(200);
  tone(PIN_BUZZER, 2637, 200);
  delay(600);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 2637, 200);
  delay(400);
  tone(PIN_BUZZER, 2349, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 1975, 200);
  delay(400);
  tone(PIN_BUZZER, 1975, 200);
  delay(200);
  tone(PIN_BUZZER, 2093, 200);
  delay(200);
  tone(PIN_BUZZER, 2349, 200);
  delay(400);
  tone(PIN_BUZZER, 2637, 200);
  delay(400);
  tone(PIN_BUZZER, 2093, 200);
  delay(400);
  tone(PIN_BUZZER, 1760, 200);
  delay(400);
  tone(PIN_BUZZER, 1760, 200);
  delay(800);
}

L'extrait de code ci-dessus est disponible en téléchargement sur cette page (le lien de téléchargement en .zip contient le projet Arduino prêt à l'emploi).

Quelques exemples

J'ai fait un script Python 3 permettant de convertir les partitions disponibles sur cet ancien topic du site du zéro forum open classrooms en fichiers de code Arduino.

Une archive avec le code Python, une copie des partitions et les fichiers Arduino est disponible ici.

N.B. Tous les crédits pour les partitions reviennent à leurs auteurs respectifs du forum SdZ. J'ai inclus une copie des partitions dans l'archive au cas où le topic du forum viendrait à disparaitre.

Conclusion

Ce tutoriel est désormais terminé.

Si ce tutoriel vous a plu, n'hésitez pas à le commenter sur le forum, à le diffuser sur les réseaux sociaux et à soutenir le site si cela vous fait plaisir.