Logiciels > Programmation PIC > Bases > MP > Production sonore

Dernière mise à jour : 03/10/2009

Présentation

Les exemples décrits ici montrent comment produire un son continu, un son bref de type "bip", une petite mélodie ou un son de sirène, avec un PIC.

Comment produire un son ?

Un son est produit par un signal électrique oscillant à une fréquence située dans le domaine audio, c'est à dire entre 20 Hz et 20 KHz. Le signal électrique doit attaquer un transducteur de type haut-parleur ou piezo-électrique pour être transformé en vibrations mécaniques transmises dans l'air et ainsi être entendu. La forme du signal peut être quelconque, de cette forme dépend le timbre du son. Produire un son avec un PIC est très simple, si on se contente d'un signal carré. Le PIC est en effet un composant "logique", qui aime travailler avec des informations de type "tout ou rien", en général des niveaux logiques bas (par exemple 0 V) ou des états logiques hauts (par exemple +5 V). Si on envoie à un petit haut-parleur une succession d'états logiques alternant entre niveaux hauts et niveaux bas à une vitesse convenable (comprise dans la fourchette 20 Hz et 20 KHz), le haut-parleur va produire un son audible, à condition bien sûr que ses caractéristiques techniques (mécaniques) lui permettent de le faire, et que nos oreilles fonctionnent encore bien. Finalement, produire un son n'est pas plus compliqué que de faire clignoter une led., il faut juste que le "clignotement" soit assez rapide pour être perçu comme un son continu et non comme une suite de "clacs" (comme celui que produirait un métronome).

Production d'un son continu

Le shéma qui suit, associé au code logiciel complet qui fait suite juste après, permet de produire un son ininterrompu avec pour seul composant externe, un buzzer piezo-électrique !

pic_tuto_base_son_001a

Vous avez l'idée d'un générateur sonore encore plus simple ? Je suis preneur ! Attention, je n'accepte pas le buzzer électronique avec son oscillateur intégré...

program electronique_pic_tuto_base_son_001a;

procedure Init;
begin
CMCON := %00000111; // comparators OFF
TRISIO.0 := 0; // GPIO configuré en sortie
ANSEL.ANS0 := 0; // GPIO configuré en sortie numérique
end;

// main program
begin
Init;
while true do
begin
GPIO.0 := GPIO.0 xor 1; // changement d'état logique
Delay_us(500); // delai avant de changer d'état logique
end;
end.


Ce circuit ultra-simple produit un signal sonore dont la fréquence est voisine de 1 KHz. L'explication en est fort simple : la sortie GP0, configurée en tant que sortie logique, change d'état sans arrêt (passe de 0 V à +5 V, puis repasse à 0 V, puis repasse à +5 V, etc), à une cadence qui est liée à la durée du délai introduit dans la boucle principale, ici de 0,5 ms (500 us). On revient donc régulièrement au même état logique toutes les ms, ce qui correspond à une fréquence de 1 KHz. En réalité, la fréquence de sortie est un peu inférieure à 1 KHz car cette façon de procéder n'est pas extrêmement précise d'un point de vue timing. Pour obtenir une fréquence de 1 KHz, il faudrait diminuer un poil la durée d'attente imposée par la ligne de code Delay_us(500), un délai de 495 us devrait convenir. Mais l'idée n'est pas ici de faire dans la précision, nous verrons plus tard que pour obtenir une grande précision il faut faire autrement. Mais le code est simple, tout de même, on ne peut pas le nier et on peut bien le ranger dans une petite case de sa mémoire à soi.

Production d'un son bref (bip)

Gardons le même schéma électronique, et modifions légèrement le code logiciel précédent, de telle sorte que le son produit ne soit plus continu, mais dure seulement un bref instant.

program electronique_pic_tuto_base_son_001b;

var
i: byte;

procedure Init;
begin
CMCON := %00000111; // comparators OFF
TRISIO.0 := 0; // GPIO configuré en sortie
ANSEL.ANS0 := 0; // GPIO configuré en sortie numérique
end;

// main program
begin
Init;
i := 0;
while true do
begin
if i < 200 then
begin
inc(i);
GPIO.0 := GPIO.0 xor 1;
delay_us(500);
end;
end;
end.


Avec ce code logiciel, le son généré à la mise sous tension du montage ne dure plus qu'un dizième de secondes, ce qui se traduit par un bref bip sonore. Pour obtenir cet effet, il suffit en effet d'autoriser les changements d'état de la sortie pendant un temps bien défini, ce temps est ici conditionné par la valeur d'une variable qui a été ajoutée pour l'occasion (variable i de type byte). Au départ, cette variable est à zéro, et elle s'incrémente de 1 à chaque changement d'état de la sortie. Au bout de 200 changements consécutifs, les changements d'états n'ont plus lieu. C'est une façon de faire, il en existe d'autres. Et si maintenant, nous utilisions une routine toute faite et proposée par MikroPascal ? On aime bien économiser ses énergies (surtout intellectuelles), et il serait dommage de ne pas profiter du travail que d'autres ont fait pour nous simplifier la vie. Je vous laisse méditer sur le code suivant.

program electronique_pic_tuto_base_son_001c;

procedure Init;
begin
CMCON := %00000111; // comparators OFF
TRISIO.0 := 0; // GPIO configuré en sortie
ANSEL.ANS0 := 0; // GPIO configuré en sortie numérique
Sound_Init(GPIO, 0);
// Preparation du port GPIO.0 pour sortie sonore
end;

// main program
begin
Init;
Sound_Play(1000, 100); // production du bip
end.


Plus simple, non ? En fait, la procédure Sound_Play, obligatoirement précédée de la procédure Sound_Init pour un fonctionnement correct, ne fait que cacher quelques lignes de codes similaires à celle que nous avons vues précédement. Elle attend de nous qu'on lui précise la fréquence (première valeur, en Hz) et la durée du signal sonore (seconde valeur, en ms). D'un point de vue précision de la fréquence générée, ce n'est pas le top là non plus, le signal de sortie est voisin de 960 Hz quand on demande un signal de 1000 Hz et que l'horloge de base du PIC est de 4 MHz. Mais dans bien des cas, ce manque de précision n'est guère bloquant, sauf si bien sûr on envisage de réaliser un générateur BF super précis...

Production d'une petite mélodie

Le paragraphe précédent a permis de poser les premières pierres. Générer une mélodie n'est finalement guère plus compliqué que de générer un bip sonore bref. Il suffit d'en produire plusieurs à la suite, avec des durées et fréquences différentes, avec éventuellement des pauses de silence pour donner vie au morceau. Le code exemple qui suit génère les premières notes de la chanson "Au clair de la lune".

program electronique_pic_tuto_base_son_001c;

procedure Init;
begin
CMCON := %00000111; // comparators OFF
TRISIO.0 := 0; // GPIO configuré en sortie
ANSEL.ANS0 := 0; // GPIO configuré en sortie numérique
Sound_Init(GPIO, 0);
// Preparation du port GPIO.0 pour sortie sonore
end;

// main program
begin
Init;
//
// Do = 239; DoD = 253; Re = 268; ReD = 284; Mi = 301; Fa = 319;
// FaD = 338; Sol = 358; SolD = 379; La = 402; LaD = 426; Si = 451;
//
Sound_Play(239, 200);
Delay_ms(10);
Sound_Play(239, 200);
Delay_ms(10);
Sound_Play(239, 200);
Delay_ms(10);
Sound_Play(268, 200);
Delay_ms(10);
Sound_Play(301, 400);
Delay_ms(10);
Sound_Play(268, 400);
Delay_ms(10);
Sound_Play(239, 200);
Delay_ms(10);
Sound_Play(301, 200);
Delay_ms(10);
Sound_Play(268, 200);
Delay_ms(10);
Sound_Play(268, 200);
Delay_ms(10);
Sound_Play(239, 400);
Delay_ms(10);
end.


Le code précédent fonctionne bien, mais sa relative gourmandise en ressources ne permet pas de jouer des mélodies très longues, surtout avec un "petit" PIC comme le 12F675. Mais comme vous êtes tous aussi curieux, je ne doute pas un instant que vous allez trouver comment faire rentrer la "Marche turque" dans un petit pavé noir à quelques pattes.

Utilisation pour orgue musical

La procédure Sound_Play proposée dans l'environnement MikroPascal peut être mise à profit pour générer des notes sur commande. Je ne me suis pas gêné pour le faire dans les deux projets suivants :
Orgue 006 - Mini orgue monodique / polyphonique Audio et MIDI à base de PIC 18F2520
Orgue 008 - Mini orgue à base de clavier informatique PS2 et PIC 16F628A

Production d'un son modulé type "sirène"

Plutôt que de produire un certain nombre de sons fixes avec des intervalles de temps plus ou moins longs entre chaque, on peut aussi envisager de produire des sons de fréquences différentes tellement rapprochés en fréquence et dans le temps, qu'on entend à peine (voire pas du tout) le passage de l'un à l'autre. Dans ce cas, l'effet obtenu peut être celui d'un glissement de fréquence, tel que celui que l'on peut observer avec les sirènes modulées en fréquence (il existe aussi des sirènes modulées en amplitude, mais elles sont moins répendues car moins percutantes). Imaginez simplement qu'un son de fréquence 250 Hz soit produit pendant quelques "périodes" de temps, puis que l'on passe à la fréquence de 260 Hz, laquelle dure un même nombre de périodes (par exemple 3 ou 6), et ainsi de suite. Le son semble alors monter, assez progressivement. Un exemple de code mettant ce principe en service, est proposé ci-après.

program electronique_pic_tuto_base_son_001d;

var
i, j, iDelay, iPeriod: integer;

procedure Init;
begin
CMCON := %00000111; // comparators OFF
TRISIO.0 := 0; // GPIO configuré en sortie
ANSEL.ANS0 := 0; // set as analog input
end;

// main program
begin
Init;
while true do
begin
for iDelay := 1 to 100 do
begin
for iPeriod := 0 to 5 do
begin
GPIO.0 := GPIO.0 xor 1;
for j := 0 to iDelay do
delay_us(1);
end;
end;
end;
end.


Ce code permet la production d'un son dont la fréquence décroit progressivement, puis remonte d'un coup pour redescendre à nouveau. En le modifiant légèrement, on peut obtenir quelques variations sur le thème, voir en exemple le projet Sirène 007.