XIV. Sortie « analogique » via des signaux PWM▲
Dans cet exercice, on examinera les « sorties analogiques » à travers l'utilisation des signaux PWM ou Pulse Width Modulation (NDLR en français, MLI pour Modulation en Largeur d'Impulsion). Les signaux PWM permettent de générer des signaux analogiques à l'aide de sorties numériques, à défaut de disposer de véritables sorties variables en continu. Certains microcontrôleurs et cartes à microcontrôleur intègrent en effet des DAC (NDLR Digital-Analogic Converter ou Convertisseur Numérique-Analogique) comme l'Arduino Due, mais comme la plupart n'en disposent pas, un signal numérique impulsionnel modulé en largeur d'impulsion avec un rapport cyclique variable peut être utilisé à la place.
Note de la rédaction
Un signal PWM est un signal logique, rectangulaire et périodique, dont on peut faire varier le rapport cyclique (le pourcentage de temps où le signal est à l'état haut sur une période du signal).
Le signal n’est nullement analogique, mais on peut l'adapter en lui faisant subir un filtrage de type passe-bas.
Filtrer ce signal carré permet d’obtenir la tension moyenne VMOY (et parfois, la charge se comporte avantageusement comme un filtre passe-bas). Si la fréquence porteuse est significativement supérieure à la fréquence de coupure du filtre, l'ondulation résiduelle reste faible.
Rapport cyclique : kitxmlcodeinlinelatexdvp\alpha=\frac{t_{on}}{T}finkitxmlcodeinlinelatexdvp
Tension moyenne : kitxmlcodeinlinelatexdvpV_{MOY}=\frac{1}{T}\int_{0}^{T}v(t)\,\mathrm{d}t=\frac{1}{T}\times \left ( V_{MAX}\cdot \alpha T \right )=\alpha\cdot V_{MAX}finkitxmlcodeinlinelatexdvp
Mathématiquement, la tension « analogique » utile produite en sortie du filtre passe-bas est proportionnelle à l'aire sous la courbe du train d'impulsions modulé. Si vous avez pensé à moyenner le signal du train d'impulsions avec un filtre passe-bas, un rapport cyclique petit (proche de 0 %) produira une tension moyenne basse, et inversement un rapport cyclique grand (proche de 100 %) produira une tension moyenne élevée. Certains composants vont naturellement filtrer les hautes fréquences alors que d'autres non. Dans cet exercice, on commencera par étudier le comportement d'une simple LED.
Il est facile d'allumer ou éteindre une LED. Considérez le code suivant :
/* PWM V1 Test luminosité LED, version manuelle */
#define LEDBIT 0x40
// on/off temporisation en millisecondes
#define LEDONTIME 300
#define LEDOFFTIME 300
void
setup
(
)
{
// Configuration connecteur 6 en sortie vers la LED
DDRD |=
LEDBIT;
}
void
loop
(
)
{
PORTD |=
LEDBIT; // allumer la LED
delay
(
LEDONTIME);
PORTD &=
(~
LEDBIT); // éteindre la LED
delay
(
LEDOFFTIME);
}
Dans cet exemple, on allume la LED pendant 300 millisecondes, on l'éteint pendant 300 millisecondes, puis on perpétue le cycle périodiquement, toutes les 600 millisecondes. Pour contrôler la LED, réalisez un circuit à base de transistor NPN piloté par la sortie 6 de l'Arduino. Saisissez le code, compilez-le et transférez-le afin de tester le programme. Réduisez les temporisations on/off des LED à 30 millisecondes chacune et répétez l'opération. La LED devrait clignoter plus rapidement. Réduisez à nouveau les temporisations on/off des LED, cette fois à 5 millisecondes chacune et répétez l'opération. Une chose curieuse arrive, la LED ne semble plus clignoter, mais sa luminosité est plus faible. Tandis que les temporisations descendent en dessous de 20 millisecondes, l’œil humain ne distingue plus ces flashs lumineux et les assimile en niveau d'intensité lumineuse continue(1), comme s'il moyennait le signal lumineux. Comme sur une période du signal, la LED est allumée la moitié du temps, elle apparaîtra allumée en continu, mais avec sa luminosité atténuée de moitié par rapport à sa luminosité maximum. Vous pouvez vérifier le phénomène en changeant la temporisation on de la LED à 1 milliseconde, et la temporisation off à 9 millisecondes, perpétuant ainsi un cycle périodique de période 10 millisecondes. La luminosité de la LED sera davantage atténuée puisque celle-ci ne sera allumée que 10 % du temps.
Plutôt que de régler les temporisations manuellement, on peut utiliser la fonction analogWrite() sur une des sorties capables de générer des signaux PWM (les sorties dédiées de la carte sont repérées avec un symbole « ~ » (tilde) sérigraphié au niveau du connecteur). Il se trouve que le connecteur 6 offre cette possibilité, et donc nous n'avons qu'un léger changement à effectuer au niveau du code :
/* PWM V2 Test luminosité LED, version avec analogWrite */
#define LEDPIN 6
// luminosité entre 0 et 255
#define LEDBRIGHTNESS 230
void
setup
(
)
{
}
void
loop
(
)
{
analogWrite
(
LEDPIN, LEDBRIGHTNESS);
}
Remarquez que le connecteur 6 n'a pas besoin d'être configuré en sortie puisque la fonction analogWrite() s'en charge automatiquement (voir analogWrite()). Si vous relevez le signal du connecteur 6 à l'oscilloscope, vous verrez un signal carré à 490 Hz environ, avec un rapport cyclique de 90 % (NDLR car 230/255 ≈ 0,90). Notez que le paramètre LEDBRIGHTNESS pourrait être remplacé par une variable résultant d'une lecture d'entrée analogique avec analogRead(). On peut donc connecter un potentiomètre à une entrée analogique et récupérer la valeur issue de la conversion analogique-numérique comprise entre 0 et 1023. Il reste alors à rééchelonner la plage de valeurs vers une autre plage de valeurs entre 0 et 255 (unsigned char), compatible avec le paramètre en entrée de la fonction analogWrite(), et jouer ainsi sur la luminosité de la LED. Ce changement d'échelle peut être effectué avec la fonction map() de la bibliothèque Arduino :
result =
map
(
value, fromLow, fromHigh, toLow, toHigh);
Dans notre cas, on utilisera :
result =
map
(
value, 0
, 1023
, 0
, 255
);
Par la suite, connectez un potentiomètre 10 kΩ entre l'alimentation et la masse. Connectez son curseur au connecteur A0 de l'Arduino. Saisissez le code suivant, compilez-le et transférez-le :
/* PWM V3 Gradateur LED utilisant analogWrite et un potentiomètre */
#define ANALOG_IN_PIN 0
#define LEDPIN 6
void
setup
(
)
{
analogReference
(
DEFAULT );
}
void
loop
(
)
{
int
a;
a =
analogRead
(
ANALOG_IN_PIN );
a =
map
(
a, 0
, 1023
, 0
, 255
);
analogWrite
(
LEDPIN, a);
}
Jouer avec des LED est bien beau, mais on pourrait souhaiter piloter des choses un peu plus intéressantes, par exemple un moteur. Bien entendu, notre circuit de pilotage de LED sera sous-dimensionné pour la plupart des moteurs, mais il sera suffisant moyennant quelques modifications mineures avec un petit moteur à courant continu pour hobbyiste à faible consommation (10 à 15 mA en fonctionnement à vide). Un exemple de circuit de pilotage d'un tel moteur est montré dans la figure ci-dessous :
Notez tout d'abord qu'une alimentation externe plus puissante est nécessaire. Dans ce cas, une alimentation 15 V à courant continu serait appropriée (NDLR une alimentation réglable à CC régulée de laboratoire 0-15 V et 0-2 A par exemple, soit 30 W au maximum). R1 est choisi aux alentours de 6,8 kΩ pour garantir la saturation du transistor, et C1 aux alentours de 100 nF. D1 est une diode de type 1N4002. Son rôle est d'éviter, ou d'amortir les pics de tension dus à l'inductance du moteur lorsque le transistor bascule de l'état saturé à l'état bloqué(2).
Note de la rédaction
Une première remarque sur la présence du condensateur C1 dans le schéma précédent. On retrouve le même montage avec ce condensateur C1 dans un autre ouvrage du même auteur, avec la seule mention : « The resistor and capacitor at the base are used to shape the incoming pulse to improve performance. » Si la présence de la résistance R1 est nécessaire pour contrôler le courant à la base du transistor, la justification de la présence du condensateur C1 pour « améliorer les performances » ne nous paraît pas évidente a priori. Assurément, vous ne risquez rien à omettre ce condensateur dans un premier temps.
La valeur de la résistance de base R1 doit être calculée, mais l'avantage d'utiliser le transistor en « tout ou rien » (état bloqué ou saturé pour faire de la commutation), c'est qu'elle se calcule très facilement grâce à la datasheet du transistor.
Si on prend les caractéristiques du transistor BC547 :
Le constructeur ne garantit plus le fonctionnement du transistor si :
- la tension entre le collecteur et l'émetteur dépasse 45 V ;
- le courant demandé au niveau du collecteur dépasse 100 mA ;
- la puissance dissipée, sans dissipateur et à la température ambiante 25 °C, dépasse 0,625 W.
D’après le constructeur du transistor, celui-ci est complètement saturé si le courant de base IB est 20 fois inférieur au courant du collecteur IC. Ensuite, le constructeur donne au moins deux exemples concrets : si IC = 100 mA (IC = IC maxi) et IB = 5 mA (vingt fois inférieur) alors le transistor sera saturé, sa tension collecteur-émetteur ne sera évidemment pas de 0 V comme un interrupteur fermé, mais elle s'en approchera, 0,2 V typiquement et jusqu'à 0,6 V maxi garanti dans les conditions de courant données juste avant.
Calcul de la résistance de base
Il faut que le courant de base IB soit 20 fois inférieur au courant de collecteur IC.
Imaginons une charge qui consomme 30 mA, donc IC = 30 mA, il faut que IB soit égal ou très proche de 1,5 mA (idéalement, il faut même être un peu au-dessus des 1,5 mA pour « sursaturer »).
Résistance de base = (Tension de sortie de l'Arduino - VBE(SAT)) / IB (application de la loi des mailles et de la loi d’Ohm)
Résistance de base = (5 – 0,7) / 1,5 mA = 2,8 kΩ, et on mettra une résistance normalisée de 2,7 kΩ.
Pour des charges requérant plus de puissance, un transistor à effet de champ (FET pour Field Effect Transistor) peut être utilisé comme montré dans la figure ci-dessous, par exemple avec un ventilateur de PC dans un boîtier standard. Typiquement, ce genre de moteur s'alimente en 12 V et peut dissiper 1 ou 2 watts. Le transistor EMOSFET ZVN4206A pourrait convenir avec une telle charge puisqu''il peut conduire un courant jusqu'à 600 mA en continu et 8 A en pointe (avec Vdd = 12 V CC).
Préparez un circuit de pilotage de moteur en prototype en lieu et place du circuit de pilotage de LED précédent, le connecteur 6 de l'Arduino est conservé pour le pilotage (en mettant de côté provisoirement le circuit de pilotage de LED afin d'y revenir dessus plus tard). Aucune modification du code n'est nécessaire. Une fois le circuit connecté, la vitesse du moteur devrait maintenant varier selon la position du potentiomètre. (NDLR Un tel moteur filtre les hautes fréquences et se comporte comme s'il était alimenté en continu à la tension moyenne déterminée par la position du curseur du potentiomètre.)
Défi
Parfois, on a besoin d'un retour visuel sur la valeur d'une variable, de réaliser un afficheur en quelque sorte. Dans ce cas, on peut réaliser un simple bargraphe à LED pour indiquer la vitesse du moteur, plus la vitesse est élevée et plus il y a de barres allumées. Inutile de réinventer la roue puisqu'un tel dispositif a déjà été réalisé précédemment. Il suffit d'adapter la fonction lightLEDsBar() de l'exercice sur les entrées analogiquesAffichage à LED de l'Arduino. Vous aurez besoin d'un circuit relié au port B de l'Arduino pour piloter les quatre LED.
Finalement, vous pouvez fixer la vitesse du moteur en fonction d'une variable environnementale comme la température ou la luminosité ambiante plutôt qu'utiliser un potentiomètre actionné manuellement. Le potentiomètre peut être remplacé par un simple capteur, tel un LM34 pour acquérir la température, ou bien par une photorésistance avec une résistance pour former un diviseur de tension et acquérir le niveau de luminosité.
Il sera relativement simple et sans danger de faire varier aux extrêmes le niveau de luminosité en utilisant une lampe ou votre doigt pour éclairer ou obscurcir une photorésistance. En comparaison, la plage de variation de la tension d'un capteur de température analogique est plus restreinte et il faudra probablement adapter la plage de tension en conséquence. Vous pouvez aussi souhaiter éloigner le capteur de température des autres composants du circuit afin de les protéger des très hautes ou très basses températures. Par sécurité, n'utilisez pas de flamme en laboratoire pour créer de la chaleur !
Inclure votre code et un schéma de montage approprié, comme d'habitude, et joindre une description des tests réalisés.