Partie pratique : Générer un signal PWM avec Arduino
Notation : /10
10 questions notées sur 10 points soit 1 point par question + 2 questions bonus
Matériels nécessaires :
1 platine Arduino
1 oscilloscope numérique
1 led
1 buzzer
1 potentiomètre
Pré-requis :
Prendre connaissance de la partie théorique sur le PWM (cliquez ici).
Activités pratiques : PWM Arduino
PWM arduino : explications (broches de sortie, rapport cyclique, fréquences, modes)

Intro : qu’est-ce qu’un signal PWM ?
« PWM » est un sigle anglais, signifiant « Pulse Width Modulation ». En français, on le traduit par « Modulation de Largeur d’Impulsion » (MLI).
En fait, un signal PWM est un signal électrique de fréquence donnée, et dont le rapport cyclique peut varier dans le temps. Le rapport cyclique étant le rapport entre le temps où le signal sera à « l’état haut », et le temps d’une période complète de ce signal (la somme du temps passé « à l’état haut » + le temps passé à « l’état bas », en fait).

Avec un arduino, on peut facilement générer un signal PWM en sortie. À noter que celui-ci sera :
- Uniquement « diffusable » sur certaines broches de sorties spécifiques (nativement, j’entends)
- De fréquence fixe (modifiable dans le code, dans une certaine limite, en changeant la valeur de certains registres du microcontrôleur)
- D’amplitude 3,3 ou 5 volts (selon si votre microcontrôleur fonctionne en 3V3 ou 5V)
- De fréquence parfois différente, d’une broche à une autre (suivant l’architecture interne de votre µC, et du mode de génération PWM sélectionné)
- Et de rapport cyclique modifiable logiciellement, avec la fonction « analogWrite » ou via les registres du µC
Broches de sortie PWM (output pins Arduino)
Toutes les broches d’un arduino ne permettent pas d’émettre nativement de signal PWM.
Sur certaines cartes arduino, vous trouverez le sigle « ~ » présent devant certains numéros de broche. En fait, ce sigle (« tilde ») vous indique quelles sorties peuvent générer des signaux PWM !
Sorties PWM sur Arduino Uno ou Nano (microcontrôleur ATmega328P)
Si vous travaillez avec un Arduino Uno ou Nano c’est-à-dire un modèle équipé d’un microcontrôleur ATmega328P, voici les broches qui permettent d’émettre un signal PWM :
- La pin D3
- La pin D5
- La pin D6
- La pin D9
- La pin D10
- La pin D11

Comment générer un signal PWM, et régler le rapport cyclique de 0 à 100 % ?
- Déclarer « en sortie » une des broches pouvant émettre un signal PWM, ce qui se fait avec un pinMode(numero_de_la_broche_souhaitée, OUTPUT);
- Et lui envoyer la valeur de rapport cyclique souhaité, avec la commande analogWrite(numero_de_la_broche_souhaitée, valeur_de_rapport_cyclique_souhaité);
À noter que le rapport cyclique, au niveau du code arduino, est exprimé au travers d’un nombre compris entre 0 et 255. Du coup, en théorie :
- Un rapport cyclique égal à 0 équivaut à aucun signal PWM en sortie (soit un état bas permanent, égal à 0 volt)
- Et un rapport cyclique égal à 255 équivaut à un signal PWM à 100% (soit un état haut permanent, par exemple égal à +5V si votre microcontrôleur fonctionne sous 5 volts)
En pratique, voici un exemple permettant de générer un signal PWM sur un Arduino Uno, via la sortie D5, avec un rapport cyclique de 50% :
#define brochePwmChoisie 5 // On choisit d’émettre sur la broche D5
#define brochePwmChoisieEnPlus 3 // On choisit d’émettre sur la broche D5
#define pourcentageRapportCycliqueChoisi 30 // avec un rapport cyclique égal à 30%
void setup() {
// Conversion du « pourcentage » de rapport cyclique en une valeur comprise entre 0 et 255
int rapportCycliqueEntre0et255 = map(pourcentageRapportCycliqueChoisi, 0, 100, 0, 255);
// Génération du signal PWM
pinMode(brochePwmChoisie, OUTPUT); // Définition de la broche D5 en tant que « SORTIE »
pinMode(brochePwmChoisieEnPlus, OUTPUT); // Définition de la broche D3 en tant que « SORTIE »
analogWrite(brochePwmChoisie, rapportCycliqueEntre0et255); // Génération du signal PWM, avec le rapport cyclique voulu
analogWrite(brochePwmChoisieEnPlus, rapportCycliqueEntre0et255); // Génération du signal PWM, avec le rapport cyclique voulu
}
void loop() {
// Pas de code ici, car tout se passe dans la partie setup !
}
Q1 : Proposez un schéma de câblage pour voir le signal sur l'oscilloscope. Utilisez obligatoirement Fritzing pour le réaliser. Vous mettrez une capture d'écran dans votre compte-rendu à chaque étape de l'activité.
Câbler (faites valider par le professeur) puis téléverser le programme sur la carte arduino.
- La fonction analogWrite appelée, le signal PWM se répétera à l’infini. Bien sûr, vous pourrez à tout moment :
- modifier le rapport cyclique de ce signal, en rappelant la fonction analogWrite
- ou bien arrêter la génération du signal PWM, en envoyant la valeur « 0 » via la fonction analogWrite
Q2 : Pourquoi le fonction loop est-elle vide ? Expliquez en vous aidant du code ci-dessus. Comment faire pour arrêter le signal ?
Fréquences par défaut des signaux PWM Arduino (Uno, Nano, Mega)
Nous venons de voir comment générer un signal PWM Arduino, et comment ajuster son rapport cyclique, à nos besoins. Par contre, à aucun moment, nous avons précisé la fréquence de ce signal PWM. Pourtant, il y a bien une fréquence d’émission « par défaut ».
Cette fréquence change :
- les fréquences d’émission des signaux PWM peuvent varier d’une broche à l’autre
- et celles-ci dépendent de la valeur de certains registres (zone de données pouvant être changer dans la mémoire) du microcontrôleur (intégré à votre Arduino), et notamment, des « timers » de ce dernier.
De base, si vous ne touchez à aucun registre du microcontrôleur et créez un programme qui génère un signal PWM sur une broche de sortie de votre Arduino, vous aurez, par défaut, pour un Arduino Uno et Nano :
- Un signal PWM de 976,56 Hz sur les broches de sortie D5 ou D6
- Un signal PWM de 490,20 Hz sur les broches de sortie D3, D9, D10, ou D11
Q3 : A l'aide de l'aide Arduino via ce lien situez et indiquez la valeur du quartz présent sur l'arduino ? Quelles sont les sorties de l'Arduino qui permettent de générer un signal PWM ?
Q4 : Vérifier que la fréquence présente sur l'oscilloscope est bien de 976,56 Hz pour la sortie D5 et de 490,20 Hz pour la sortie D3, en effectuant un relevé avec l'oscilloscope et en vous aidant des calibres. Les boutons Cursor et Measure doit aussi être utilisés. Vous pouvez utiliser des traits verticaux qui permettront de prendre des mesures très facilement avec l'oscilloscope. Effectuez une capture d'écran de votre vérification pour chacune des sorties.
Ces fréquences PWM proviennent de la fréquence d’horloge du microcontrôleur (16 MHz, pour les Arduino cités ci-dessus), sur laquelle on applique une division particulière, en fonction de certains modes et valeur de registre. En effet :
- 16 MHz / 64 / 256 = 976,5625 Hz (64 étant la valeur du prédiviseur par défaut, interne au µC, et 256 le nombre de pas du signal PWM généré ici, dans un mode particulier, par défaut)
- 16 MHz / 64 / 510 = 490,196 Hz (64 étant la valeur du prédiviseur par défaut, interne au µC, et 510 le nombre de pas du signal PWM généré ici, dans un autre mode de fonctionnement, par défaut)
Remarque : les fréquences de 976 et 490 Hz sont dans le « spectre » des fréquences audibles de l’être humain. En clair : on peut donc entendre ces fréquences, sous certaines conditions.
Q5 : Branchez un buzzer sur la sortie PWM sur D3, écoutez le son puis branchez celui-ci sur la sortie D5, entendez-vous la différence ? Quelle son est le plus aigu ? Le plus grave ? Donner leur fréquence.
Quelles sont toutes les fréquences arduino PWM possible ?
Dans la partie précédente, je vous ai dit que la fréquence PWM d’un Arduino était fonction :
- De la fréquence d’horloge principale du microcontrôleur (généralement 16 MHz, généré à partir d’un quartz externe)
- De la valeur des prédiviseurs d’horloge de chaque timer (qui sont réglés pour une division par 64, par défaut)
- Et du mode de génération de signaux PWM choisi (à 256 pas, à 510 pas, ou autre, que nous détaillerons dans les exemples)
Nota : la fréquence PWM est également fonction de la valeur du prescaler (diviseur « général » de fréquence de votre µC). Mais celui-ci étant toujours, sauf cas particulier, réglé sur un « rapport de division par 1 », le prescaler peut donc être ignoré ici. Par contre, il est important se savoir qu’il peut jouer un rôle au niveaux des signaux PWM, si modifié !
Concernant les prédiviseurs de fréquence d’horloge de chaque timer, ceux-ci peuvent prendre différentes valeurs, prédéfinies à l’avance (interne au µC). Généralement, ces prédiviseurs permettent :
- De diviser la fréquence par 1, 8, 64, 256, et 1024 (pour la plupart)
- Ou par 1, 8, 32, 64, 128, 256, et 1024 (pour d’autres)
En fait, suivant le modèle de microcontrôleur et la broche de sortie PWM que vous choisirez, vous aurez le choix entre l’un ou l’autre de ces rapports de division de fréquence (car chaque sortie PWM dépend d’un timer en particulier, et chaque timer a son prédiviseur associé).
Parallèlement à ça, et comme je vous le disais un peu plus haut, les fréquences des signaux PWM Arduino sont également fonctions du « mode de génération » utilisé. Ici, il en existe de 2 types :
- Le modèle « Fast PWM Mode » : il permet la génération de signaux PWM « découpés » en 256 morceaux, ou multiples de 256. C’est un mode rapide, mais « peu » précis.
- Le modèle « Phase Correct PWM Mode » : il permet la génération de signaux PWM « découpés » en 510 morceaux, ou multiples de 510. C’est un mode plus précis que le précédent, mais plus « lent ».
À noter qu’il existe bien d’autres modes de génération de signaux PWM encore (notamment à 8 bits, 9 bits, 10 bits), permettant au final d’avoir une grande variété de signaux PWM possibles, en sortie. Mais bien sûr, aussi riche que tout cela puisse être, tout ceci reste limité du fait qu’on ne peut travailler qu’à certaines fréquences, « imposées » par l’horloge et les différents diviseurs de fréquences.
Plus concrètement, voici des exemples de fréquences que l’on peut obtenir avec un ATmega328P, équipant les Arduino Uno, Nano, et Pro Mini, selon si on touche aux prédiviseurs de fréquence, ou au mode de génération PWM :

En pratique, pour changer de fréquence PWM, on peut :
- Changer le rapport de division de fréquence d’horloge (de 1 à 1024, au niveau des prédiviseurs d’horloge)
- Et/ou changer de mode de génération de signal PWM (Fast Mode, Phase Correct Mode, 8-bit, 9-bit, 10-bit, …)
Mais autant vous le dire de suite : pour dompter le PWM Arduino, il vous faudra tôt ou tard toucher aux registres internes du microcontrôleur.
Q6 : Quel est la valeur en Hz si on utilise le mode FAST PWM-10-bit avec un prédiviseur de 1024 sur la broche 9 ?
Q7 : Quel est la valeur en Hz si on utilise le mode Phase Correct PWM avec un prédiviseur de 8 sur la broche 11 ?
Exemple de code #1 : faire varier la luminosité d’une LED grâce à un signal PWM, piloté par potentiomètre
Au niveau fonctionnement, c’est hyper simple : plus vous tournerez le potentiomètre, et plus la LED s’éclairera (ou plus elle s’éteindra, suivant dans quel sens vous tournez !).
Au niveau du montage électrique, voici ce que je vous propose de réaliser, pour ce faire :

Pour rappel : la sortie D3, fait partie de l’une des 6 sorties possibles d’un arduino UNO, pouvant générer un signal PWM (comme vu un peu plus haut, dans cet article). En fait, les sorties D5, D6, D9, D10, ou D11 auraient pu également convenir. Mais dans tous les cas, pas les autres, ici !
Au niveau du programme arduino en lui-même, vous verrez qu’il n’y a que très peu de lignes de code. C’est pourquoi j’en ai profité pour mettre un maximum de commentaires :
#define pinOuEstBrancheLePotentiometre 3 // Le potentiomètre servant à faire varier la luminosité de la LED sera branché sur l'entrée A3 de l'Arduino Uno
#define pinOuEstBrancheLaLED 3 // La LED sera quant à elle branchée sur la sortie D3 de l'Arduino Uno (attention : toutes les sorties ne permettent pas de générer un signal PWM)
int valeurTensionEntreeAnalogique; // Variable qui contiendra la valeur de la tension mesurée sur l'entrée analogique (valeur comprise entre 0 et 1023, car lecture sur 10 bits)
int valeurRaccordCycliqueSignalPwm; // Variable qui contiendra la valeur du rapport cyclique du signal PWM à générer
// ========================
// Initialisation programme
// ========================
void setup()
{
// Définition de la broche où sera branché la LED en sortie
pinMode(pinOuEstBrancheLePotentiometre, OUTPUT);
// Nota : pas besoin de déclarer l'entrée analogique en entrée, car c'est sous entendu, par défaut
}
// =================
// Boucle principale
// =================
void loop()
{
// *****************************************************************************************************************************
// Lecture de la tension présente sur l'entrée analogique, où est branché le potentiomètre (son "point milieu", plus exactement)
// *****************************************************************************************************************************
// Pour rappel : la valeur retournée sera comprise entre 0 et 1023, car il s'agit là d'une lecture sur 10 bits (0 correspondant à 0V, et 1023 à +5V)
valeurTensionEntreeAnalogique = analogRead(pinOuEstBrancheLePotentiometre);
// *****************************************************************************************************************************
// Conversion tension -> rapport cyclique
// *****************************************************************************************************************************
// Comme la valeur mesurée sur l'entrée analogique sera exprimée sous la forme d'un nombre compris entre 0 et 1023,
// et que la valeur du rapport cyclique à renseigner dans le code arduino devra être comprise entre 0 et 255,
// alors il faut convertir les mesures 0-1023 en valeur 0-255
valeurRaccordCycliqueSignalPwm = ????????????????????????????;
// *****************************************************************************************************************************
// Génération du signal PWM
// *****************************************************************************************************************************
analogWrite(pinOuEstBrancheLaLED, valeurRaccordCycliqueSignalPwm);
}
Une fois ce programme uploadé dans votre Arduino, et votre montage alimenté, vous devriez être en mesure de faire varier l’intensité lumineuse de la LED, en tournant le potentiomètre vers la droite, ou vers la gauche.
Ah oui… pour ceux qui se demandent comment fonctionne ce montage, en fait, c’est tout simple :
- Le potentiomètre permet de faire varier la tension entre 0 et +5V sur l’entrée A0.
- Le programme arduino mesure cette tension, et génère un signal PWM en conséquence, sur la sortie D3. À noter que :
- le rapport cyclique de ce signal sera proportionnel à cette tension lue (0% si 0 volt, jusqu’à 100% si 5 volts)
- dans le codage arduino, le rapport cyclique ne pourra pas être renseigné en pourcentage (0 à 100%), mais plutôt au travers d’une valeur décimale, comprise entre 0 et 255
- Enfin, la LED éclairera plus ou moins fortement, selon la valeur du rapport cyclique qui lui est appliqué. À noter qu’ici la fréquence de ce signal PWM est fixe (à sa valeur par défaut), et qu’elle est bien alimentée en 0/+5V via sa résistance. En clair : ce n’est pas la tension de sortie en D3 qui varie, mais seulement le rapport cyclique d’un signal 0/5V.

Q8 : Complétez le code pour que la LED soit contrôler par le signal PWM.
valeurRaccordCycliqueSignalPwm = ????????????????????????????;
Q9 : Visualisez le signal PWM à l'aide de l'oscilloscope.
Q10 : On ne veut plus utiliser de potentiomètre, proposer une solution pour gérer cela ? Expliquez comment vous allez faire ?
Implémenter le code et tester cela.
Q11 : Ajouter un bouton qui va remettre à zéro le cycle.
Q12 : Brancher le buzzer avec la solution sans potentiomètre, que constatez-vous ?
Créé avec HelpNDoc Personal Edition: Passez au CHM avec l'outil de conversion WinHelp HLP vers CHM de HelpNDoc