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 !
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.