Utiliser un buzzer avec Arduino en langage C

Francesco Balducci

Traducteur

f-leb

Ce tutoriel montre un exemple de programmation de carte Arduino en langage C, sans passer par le « langage Arduino » proposé dans l'EDI standard. Le compilateur utilisé sera avr-gcc, sous Debian.

Commentez

- Titre : Utiliser un buzzer avec Arduino en langage C

- Auteur : Francesco Balducci

- Traducteur : f-leb

- Parution : 14 novembre 2016

- Public visé :

- Licence : Le contenu de cet article est rédigé par Francesco Balducci et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Voir également :

- Programmer l'Arduino en langage C

Sommaire

- I. Ressources matérielles

- II. Utilisation d'un Timer

- III. Téléversement du code et tests

- IV. Notes de la Rédaction Developpez.com

I - Ressources matérielles

Arduino UNO connectée à un buzzer KEPO

Cette fois, j'utilise un buzzer acheté chez un revendeur de matériel électronique. La première chose que j'avais à faire était de trouver la documentation du constructeur (datasheet), car il n'y avait aucune indication sur la capsule du buzzer excepté le nom de la marque, KEPO. Après quelques recherches, j'ai découvert la référence KPR-2310. Il s'agit d'un buzzer piézoélectrique conçu pour fonctionner avec des signaux périodiques rectangulaires 12 V crête à crête. La bonne nouvelle est que le courant maximal consommé par ce composant n'excède pas 3 mA, ce qui est largement en deçà des 40 mA tolérés par broche d'entrée-sortie de l'ATmega328P. Cela signifie que je peux alimenter le buzzer sans résistance de protection. J'étais par contre inquiet du fait que ce buzzer était conçu pour du 12 V, et qu'il risquait de ne pas fonctionner avec le niveau de tension 5 V d'une entrée-sortie de la carte Arduino. Il s'avère malgré tout que le niveau sonore produit est tout à fait convenable.

II - Utilisation d'un Timer

Afin de produire un son, il fallait configurer une entrée-sortie pour générer un signal rectangulaire périodique à une certaine fréquence. Il y a au moins deux manières pour cela : soit en faisant basculer directement l'état du port, soit en utilisant un timer. J'ai décidé d'utiliser la sortie OC0A du Timer0, qui correspond à la broche 6 du port D de l'ATmega328P, soit le connecteur 6 de la carte Arduino UNO. Ces informations sont contenues dans la documentation de l'ATmega328P et les schémas de l'Arduino UNO.

Le Timer0 a plusieurs modes de fonctionnement, et celui qui correspond le mieux à mon besoin est le mode Clear Timer on Compare Match (CTC). Avec ce mode de fonctionnement, je peux faire basculer la sortie OC0A à une fréquence que je peux régler, et ainsi générer un signal périodique rectangulaire de rapport cyclique 50 % pour piloter le buzzer. La fréquence peut être réglée en utilisant la formule suivante provenant de la documentation :

Où est la fréquence du signal, vaut 16 MHz pour l'Arduino UNO, est la valeur du prescaler, et est la sortie Output Compare Register voulue, dans mon cas la sortie OCR0A correspondant à la broche OC0A. Par exemple, si on veut une note correspondant à la fréquence standard 440 Hz (NDLR : la fréquence du la du diapason standard), on fixe le prescaler à 256 et le registre OCR0A à 70 (NDLR : 16.10^6 / (2 x 256 x (1 + 70)) ≈ 440, CQFD). Avec cette information, j'ai écrit le code buzzer.c suivant qui joue deux notes, une à 440 Hz et l'autre à 880 Hz (NDLR : c'est-à-dire la fréquence du la de l'octave supérieure) :

buzzer.c

#include <avr/io.h>
#include <util/delay.h>

enum t0_prescaler
{
T0_PRESCALER_1 = _BV(CS00),
T0_PRESCALER_8 = _BV(CS01),
T0_PRESCALER_64 = _BV(CS00) | _BV(CS01),
T0_PRESCALER_256 = _BV(CS02),
T0_PRESCALER_1024 = _BV(CS02) | _BV(CS00),
};

static void t0_set_prescaler(enum t0_prescaler ps)
{
TCCR0B = ps;
}

static unsigned short t0_get_prescaler_rate(enum t0_prescaler ps)
{
unsigned short rate;
switch(ps)
{
case T0_PRESCALER_1:
rate = 1;
break;
case T0_PRESCALER_8:
rate = 8;
break;
case T0_PRESCALER_64:
rate = 64;
break;
case T0_PRESCALER_256:
rate = 256;
break;
case T0_PRESCALER_1024:
rate = 1024;
break;
default:
rate = 0;
break;
}
return rate;
}

static unsigned long div_round(unsigned long d, unsigned long q)
{
return (d + (q/2)) / q;
}

static void t0_set_ctc_a(unsigned long hz, unsigned long timer_freq)
{
OCR0A = div_round(timer_freq, hz*2) - 1;
TCCR0A =
_BV(COM0A0) // toggle
| _BV(WGM01); // CTC
}

int main(void)
{
unsigned long timer_freq;
enum t0_prescaler ps = T0_PRESCALER_256;

DDRD |= _BV(DDD6);
t0_set_prescaler(ps);
timer_freq = div_round(F_CPU, t0_get_prescaler_rate(ps));

while(1)
{
t0_set_ctc_a(440, timer_freq);
_delay_ms(200);
t0_set_ctc_a(880, timer_freq);
_delay_ms(200);
}
return 0;
}

Soyez conscient que le code ne vérifie pas la validité des valeurs renseignées, et que les valeurs de fréquence possibles sont peut-être limitées.

III - Téléversement du code et tests

Pour téléverser le programme dans l'Arduino UNO, j'ai lancé les commandes suivantes :

$ avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -o buzzer buzzer.c
$ avr-objcopy -O ihex -R .eeprom buzzer buzzer.hex
$ avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:buzzer.hex

J'ai relié le buzzer aux connecteurs GND et 6 de l'Arduino UNO, et le buzzer s'est mis à jouer les deux notes l'une après l'autre dans une boucle sans fin.

À partir de là, il est possible de trouver d'autres solutions, d'autres broches et différentes manières pour gérer les notes, par exemple en utilisant des interruptions au lieu de pauses pour contrôler la durée des notes. On pourrait aussi gérer deux buzzers connectés à deux broches et jouer une mélodie polyphonique.

IV - Notes de la Rédaction Developpez.com

Cet article est la traduction du billet écrit par Francesco Balducci (alias Balau). Retrouvez la version originale de cet article ainsi que les autres chapitres consacrés à Arduino sur son blog.

Nous remercions les membres de la Rédaction de Developpez.com pour le travail de traduction et de relecture qu'ils ont effectué, en particulier : f-leb, lolo78 et Malick SECK.