Petit haut-parleur + clavier |
Les perles du Net |
Maj : 23/08/19
Abstract :
Résumé : |
Dans ce texte, par facilité, je parlerai de « buzzer » mais le terme exact serait « petit haut-parleur », car au sens strict, un buzzer vibre à fréquence fixe quand il est alimenté en continu, alors que dans notre application nous fournirons un signal carré variable pour tenter de produire des sons variés bien que peu mélodieux.
Vous trouverez sur le Net pléthore de montages du buzzer (lire : petit haut-parleur), chacun ayant recopié sans le comprendre un montage trouvé n’importe où.
Les plus simplistes attaquent directement le buzzer sur un GPIO ce qui écroule complètement la sortie, d’autres rajoutent une résistance en protection, certains une diode de roue libre, d’autres un transistor…
Nous allons voir qu’un montage propre est un peu plus compliqué mais donne de meilleurs résultats.
De plus, avec un seul fil commun, il permet aussi de gérer 3 à 9 boutons poussoirs, ce qui économise les rares GPIOs disponibles sur une carte à ESP32.
La loterie ! |
Disques acceptables |
Dans tous les cas un vrai petit haut-parleur |
Traditionnellement, nous utiliserons les modèles chinois à bas prix, rond de 14 mm de diamètre sur 8 mm de haut. Il sont constitués de disques piezzoélectriques avec une résistance parallèle interne de moins de 15 Ohms. Mais la sélection est très difficile sur les sites chinois, les descriptions sont totalement farfelues ! Remarque : Petits haut-parleurs originaux
|
Une première solution utilisait un mosFet N, avec filtre de grille et RC d’isolation, mais cette solution amenait trop de distorsions et a été abandonnée. Un seul fil GPIO est utilisé, en écriture il produit des sons, et en lecture, il lit les touches. La nouvelle version est plus simple, en utilisant un mosFet P simple (SI2305 ou BS 250 ou autre), sans filtre, afin d’être en consommation nulle au repos. |
|
Une résistance, ou un potentiomètre de 47 Ohms (l’autre extrémité à la masse en <1>) ou un strap en <2><3> activent le haut-parleur interne.
Rôle d'une diode de roue libre (à la place de CBD1) La résistance en parallèle ainsi que la diode de roue libre sont inutiles avec un vrai haut-parleur. La prise strap en série permet de tester divers haut-parleurs et buzzers en avec les composants nécessaires à la demande.
Pour produire les sons, les signaux carrés seront émis pour attaquer la Gate du mosFet , dont l’impédance d’entrée est très élevée (à la différence d’un transistor qui demande un courant de base). |
Rôle du condensateur CDB1
Le condensateur en parallèle (0.1µF au moins) casse les pics de suroscillations, plus la valeur sera grande, plus les pics seront rabotés au prix d’une baisse de niveau. On ne peut pas aussi simplement extraire la fondamentale d’un signal carré de fréquence variable, il y aura toujours les raies impaires dans le spectre, mais à la différence d’un filtre d’entrée qui dissymétrise le signal, il n’y aura qu’une seule fondamentale.
Résultats avec un vrai haut-parleur :
Autres approches, toujours en signal digital
Approche PWM ou modulation Delta
L’ESP32 possède 16 PWM, mais il y en a peu d’utilisables à cause de limitations.
Les fréquences utilisables sont : 1,5,8 et 10 kHz.
La résolution est entre 1 et 16 bits.
En pratique cela n’est pas assez rapide pour produire une gamme de sons
Cela est parfait pour piloter la vitesse de moteurs, les variations lentes d’éclairage d’une led, mais pas pour faire de la musique.
Un gros problème apparait quand on doit gérer simultanément des routines qui prennent du temps machine, par exemple : Pour résoudre ce problème, je rajoute sur ma nouvelle carte de développement (publication à venir) un ATTiny 85 qui va gérer seul avec ses petites 8 pattes, clavier, son, détection de présence (radar et ultrasons) et leds. |
L’approche convertisseur Digital vers Analogique
Dans les exemples précédents, nous attaquions via un mosFet, le haut-parleur en signaux carrés générant plein d’harmoniques désagréables. L’ESP32 possède deux broches spéciales utilisables en convertisseur Digital vers Analogique, ce n’est que du 8 bits, mais suffisant pour des applications basses fréquences. DAC1 utilise GPIO25, et DAC2 utilise GPIO26. Considérons ce début de programme : Il ne fait que créer un tableau de de 256 bytes représentant une période de sinus, entre 0 et 255. |
#define stepResol 8
|
|||||||||||||||||||||||||||||
Nous savons faire une fréquence unique avec une table unique, mais on peut faire bien mieux !
|
256 points -> 731 Hz 16 points -> 11.7 kHz |
Décrémentation de fréquence Si dans la boucle « for » nous ajoutons un delayMicrodeconds (tempo), nos rallongeons la boucle donc baissons la fréquence. Pour la table de 256, avec une tempo de 160 µS, la fréquence est de 23.4 Hz, la période est de 42.74 mS, il y a 256 boucles, donc le traitement de la condition for + dacWrite +160 µS prend à peu près 42.74/255 = 167 µS, donc <condition for> + dacWrite = 7 µS En rajoutant notre délai, la nouvelle fréquence sera environ de 1/(256* (7+tempo)), car il y a l’arrondi, le délai ne prenant que des entiers. Par exemple pour s’approcher du La 3 à 440 Hz, l’appel avec shift=1 et tempo= 3µS, nous donnera 421 Hz plus proche du Sol# ou La bémol à 415 Hz. |
|
En passant à cette petite boucle « for » les entiers shift et tempo, nous pouvons obtenir toute la gamme audible. Les fréquences se calculent par de simples tables Excel.
Cela a toutefois un défaut, les fréquences obtenues sont serrées, mais ne tombent pas juste sur les notes de la gamme.
Pour des bruitages, aucun problème, mais pour jouer un son parfait sur un bon haut-parleur, les écarts aux vraies notes seront sensibles pour un musicien.
Amélioration de la résolution
Dans ce chapitre nous prendrons un shift de 2, donc 128 points par période. Le delayMicrosecond est trop long pour faire un réglage fin. Nous remarquons que delayMicrosecond(255), qui nous donnait une fréquence de 14.95 Hz prend exactement le même temps que : |
|
Donc <la boucle for> + <l’instruction nop> prennent exactement 255µS/20540, soit environ 12.41 nanoSecondes, soit 3 coups d'horloge (2 pour la boucle, 1 pour le nop) à 240 MHz. Cela donne un delai 80 fois plus fin que delayMicrosecond() Nous pouvons maintenant ajuster plus finement les notes de la gamme, par exemple : Octave 1 : La 110 Hz avec 2616 boucles (exactement) Octave 2 : La 220 Hz avec 1207 boucles (exactement) Octave 3 : La 440 Hz avec 501 boucles (exactement) en descendant les octaves le nombre de boucles augmente ainsi que la résolution, mais en montant les octaves la précision diminue de plus en plus : |
Octave 4 : La 880 Hz, avec 149 -> 886 Hz et avec 150 -> 874.4 Hz
Octave 5 : La 1760 Hz, impossible, trop rapide, avec 1 boucle -> 1464 Hz seulement
La synthèse ne sera juste que dans les graves ce qui pose problème…Avec un shift de 2, donc 128 points on obtient un nouveau jeu de fréquences mais le problème se pose toujours.
Si l'on prend un shift de 1, on descend encore d'une octave sur les valeurs précedentes.
Oublier le DAC 8 bits de l’ESP32 ?
Faut-il oublier le DAC 8 bits de l’ESP32 pour rajouter un meilleur, comme le DAC 12 bits MCP4725 utilisant une commande I2C pour un coût très modique ?
L’avantage de l’approche I2C est que cela ne consomme aucun GPIO supplémentaire, car de toute manière, SDA et SCL de l’I2C sont déjà utilisés par d’autres périphériques.
Pour cette application <son>, cela est inutile, car la limitation n’est pas du tout dans la finesse de la courbe, mais dans la vitesse pour passer les octets de commande.
Plus la résolution est grande, plus la fréquence du signal sera faible.
La bibliothèque d’utilitaires « sons »
La classe < C_utils_Sons> utilise seulement la sortie numérique et le mosFet comme décrit en début de page.
Elle n’utilise pas la synthèse sinusoïdale du chapitre précèdent.
La classe < C_utils_Sons> contient les outils nécessaires pour produire divers bruitages, sans utiliser le fonction « tone » qui ne fonctionne pas sur ESP332.
Elle est remplacée par la méthode « ton ». Cette méthode accepte plusieurs formats :
void ton (float note, uint8_t octave, int duration, int pause);
void ton (float note, uint8_t octave, int duration);
void ton (float frequency, int duration);
Dans cette classe, les notes (et dièses) sont écrites en clair et leur interprétation est très précise.
En utilisant le terminal série de la démo, on peut lancer la collection de tous les sons ou lancer chaque son séparément en tapant son numéro au clavier.
La démo incluse montre les nombreux exemples à tester pour agrémenter les programmes :
Des petits sons gadgets pour agrémenter les actions courantes.
Les classiques sirènes (samu, pompiers, ambulance, police) qui sont fidèles, car le ministère de l’intérieur publie les normes très rigoureuses.
Quelques thèmes musicaux médiocres, identifiables en 8 mesures.
J’avais espéré créer de sons d’explosion, de chocs métalliques, des chants d’oiseau, etc.., mais cela est impossible sans utiliser de lourdes listes de centaines d’octets, il faut passer au MP3. Je tenais à ce que ma bibliothèque soit le plus compacte possible. J’ai renoncé à tout ce que je ne peux pas jouer au piano, avec un seul doigt de la main droite.
Cela limite considérablement les possibilités, ce qui explique les rendus pauvres, car une partition comporte les deux mains et plusieurs doigts par main pour chaque temps.
De nombreux circuits synthétiseurs audio existent, en solution « clefs en main », fournissant une sortie audio parfaite, bien meilleure que ce qui fait l’objet de cette page consacrée à l’approche par le firmware seul.
C'est une excellente approche pour des oreilles sensibles. Une recherche sur Internet <synthétiseur audio arduino> vous donnera de nombreuses pistes. Il y a beaucoup moins de choix en synthétiseurs BF qu’en HF.
Pensez aussi au très riche format Midi très bien documenté.
Autre alternative performante, la carte annexe jouant des MP3 contenus dans sa mémoire SD. Vous pouvez échantillonner toute musique, voix parlées ou chantées, des bruits…
Il existe de multiples applications spécialisées, pour traiter les sons.
Mais cela nous éloigne évidemment du cahier des charges original pour cette page, qui était de faire du son en utilisant simplement une sortie GPIO et quelques lignes de code…
Amplification du signal vers le haut-parleur
Si l’on veut plus de puissance (?) , il faut rajouter un petit circuit intégré amplificateur. Voir par exemple le LM4890MX.
Il existe des modules chinois qui comportent l’ampli et le haut-parleur sur la même plaquette comme le SC8002B, mais vous pouvez utiliser un quelconque ampli de récupération qui traîne dans une de vos boîtes.
Avantages et inconvénients de l’amplificateur SC8002B (ou LM4871)
+ Coût dérisoire
+ Fonctionne à 3.3 V (c’est rare)
+ Surpuissant pour notre application, mais le niveau est simple à contrôler avec une résistance
+ Meilleur son possible sur un petit haut-parleur
- Consommation permanente de quelques milliampères incompatible avec des montages « low power », mais une coupure automatique de l’alimentation en rajoutant un MosFet est simple
- S’il n’est pas en stock, délai pour commande en Chine
N’hésitez pas à m’envoyer vos remarques sur le fond (parties à compléter ou modifier), et sur la forme (fautes de frappe…).
L’expérimentation sur Arduino est très enrichissante, mais se contenter de pomper des pages douteuses sans comprendre ce que l’on fait n’est pas une bonne idée.
Il faut essayer d’aller plus profondément si l’on veut en tirer une satisfaction intellectuelle…
Ne vous attendez pas à faire du son haute-fidélité aussi simplement avec un Arduino, pensez à l’alternative des circuits spécialisés évoqués.
Pour de simples petits sons ponctuant un programme, le montage décrit dans cette page suffit.
De plus, les fréquences sont calculées exactement, mais l’horloge de l’ESP32 n’est pas très stable.
Pour s’en convaincre, il suffit de réaliser une pendule élémentaire qui se base sur millis(), sans autre code parasite et la laisser tourner pour regarder la dérive importante, variable d’un chip à l’autre.
Donc quand vous lisez « le La 3 est callé exactement à 440 Hz », il faut comprendre « pour autant que millis() batte exactement la milliSeconde », ce qui n’est jamais exact.
Vous trouverez joint un petit programme qui envoie le temps toutes les minutes, calez vous sur un top à l’heure entière et laissez tourner pour voir les dérives, entre autres liés à la température (testez dans le frigo sur batterie).