Au chapitre C2‑VIII , on a vu comment utiliser le port numérique d'une carte Arduino pour lire et écrire des entrées‑sorties booléennes, c'est‑à‑dire à niveaux de tension tout‑ou‑rien.
Mais il est aussi parfois nécessaire de piloter des systèmes faisant intervenir composants dont la tension analogique – c'est‑à‑dire pouvant varier dans un intervalle de valeurs déterminées – porte une information quantifiable. C'est pourquoi les cartes Arduino comportent d'autres dispositifs entrées‑sorties, comme le montre la figure ci‑contre de la carte Uno.
Typiquement, on peut avoir des entrées câblées sur :
- des boutons tournants de type potentiomètre (cf. la photo ci‑contre) pour permettre à l'utilisateur de régler des paramètres sur une échelle continue de valeurs ;
- des capteurs divers pour mesurer des grandeurs physiques de l'environnement d'un système ; par exemple, la température avec une thermistance, la luminosité avec une photorésistance (cf. la photo ci‑contre), etc.
Et on peut avoir des sorties câblées sur des dispositifs lumineux, sonores, mécaniques (moteurs), etc. dont on souhaite faire varier l'amplitude du phénomène mis en jeu : l'intensité lumineuse d'une lampe, le volume sonore d'un haut‑parleur, la fréquence de rotation d'un moteur, etc.
Sans exception, toutes les cartes Arduino ou compatibles disposent d'entrées analogiques, c'est‑à‑dire des broches reliées à un convertisseur analogique numérique W ou CAN intégré au microcontrôleur – en anglais, ADC pour analog‑to‑digital converter. La figure ci‑contre représente à titre d'exemple le port analogique du modèle de carte Arduino Uno.
En revanche, peu de cartes disposent de véritables sorties analogiques, c'est‑à‑dire d'un microcontrôleur doté d'un convertisseur numérique analogique W ou CNA – en anglais, DAC pour digital‑to‑analog converter. C'est par exemple le cas du modèle Arduino Due (cf. chap. C1‑III ) dont les broches sont détaillées en figure ci‑contre ou encore des modules ESP32 du fabricant Espressif (cf. chap. C1‑III ).
Néanmoins, il existe néanmoins une alternative pour mettre en œuvre des sorties à tension variable sans DAC : la modulation de largeur d'impulsion W ou MLI – en anglais, PWM pour pulse width modulation. Appliquée à une sortie numérique disposant de cette fonctionnalité (cf. celles représentées avec le symbole ∼ sur la figure ci‑contre du port numérique d'une carte Arduino Uno), cette technologie logicielle permet de générer des variations de la valeur moyenne du signal numérique de tension tout‑ou‑rien dans l'intervalle des valeurs possibles sur la carte, typiquement 0 ‑ 5 V ou 0 ‑ 3,3 V.
En application des chapitres précédents sur les types numériques entiers et flottants, ce chapitre a pour objectif d'apporter toutes les connaissances pour la mise en œuvre d'entrées‑sorties analogiques sur carte Arduino ou compatible. En se limitant à l'emploi des fonctions de haut niveau du framework Arduino, il aborde dans l'ordre :
- la lecture d'entrées analogiques, avec notamment la possibilité d'ajuster la tension de pleine échelle du CAN ;
- l'écriture de sorties analogiques, avec la possibilité de modifier la résolution du CNA ;
- l'écriture de sorties digitales modulées, avec éventuellement la possibilité de modifier la fréquence de MLI.
En revanche, hormis quelques rappels, ce chapitre n'a pas vocation à détailler toutes les bases du conditionnement et de la conversion des signaux, qui est un domaine très complexe de la physique appliquée. En cas de lacunes, on pourra dans un premier temps se reporter à ce cours de Sciences de l'ingénieur .
Et pour une connaissance approfondie des mécanismes de bas niveaux mis en œuvre par les fonctions analogRead et analogWrite, il est recommandé de consulter leur code source, qui est placé dans le fichier wiring_analog.c G du framework Arduino.
Lecture d'entrées analogiques
Principe et caractéristiques générales du CAN
Sur les cartes Arduino, on dispose d'au moins un convertisseur analogique numérique intégré au microcontrôleur. Il s'agit toujours d'un CAN à approximations successives W (en anglais, successive approximation register, abrégée SAR) qui offre un excellent compromis en termes de rapidité et précision de conversion.
La conversion analogique numérique consiste :
- à partir d'une tension d'entrée ve entre une broche du port analogique Ax (x = 0, 1, 2 …) et la broche GND de la carte ;
- à établir un nombre en sortie Ns de type entier positif autant que possible proportionnel à ve.
Quel que soit le modèle de carte (Uno, Nano, Mega, Due…), le CAN intégré au microcontrôleur présente les caractéristiques générales suivantes.
- Il opère une conversion unipolaire, avec une pleine échelle de ve entre 0 et Vmax ;
- Il encode la numérisation sur n bits (n = 10, 12, voire plus selon le modèle de carte), procurant une excursion de Ns comprise entre 0 et Nmax = 2n − 1 ;
- De plus, la tension de pleine échelle Vmax est ajustable par une référence de tension :
- soit interne à la carte, parmi une gamme de valeurs possibles ;
- soit externe, établie à la valeur voulue par un montage potentiométrique spécifique (typiquement, un pont diviseur de tension) entre les broches AREF et GND de la carte.
Sur les cartes Arduino, le CAN intégré peut être mis en œuvre selon deux modes de fonctionnement :
- en mode ponctuel (one shot), à l'aide des fonctions de haut niveau usuelles comme
analogRead(cf. infra ) ; - en mode continu, exécuté en tâche de fond en parallèle du programme utilisateur, pour numériser des signaux analogiques ; il faut pour utiliser des drivers logiciels fournis sous forme de fichiers de bibliothèque, ou encore opérer directement au niveau des registres du microcontrôleur.
Dans ce chapitre, le mode continu n'est pas abordé en raison de sa complexité de mise en œuvre. À titre d'exemple, pour une carte Arduino Due, on pourra se rapporter au lien suivant .
Remarque. Les cartes à module ESP32 disposent de deux CAN. On peut ainsi numériser en mode continu deux signaux en parallèle.
Cas des cartes à modules ESP
Les cartes à module ESP8266 ou ESP32 (cf. chap. C1‑III ) disposent de fonctionnalités similaires :
- CAN unipolaire avec une tension de pleine échelle Vmax = 3,3 V
- technologie SAR avec une résolution maximale sur 10 bits (ESP8266) ou 12 bits (ESP32).
En revanche, sur ces cartes, la tension de pleine échelle n'est pas ajustable.
Les cartes à module ESP8266 ne disposent que d'une seule broche d'entrée analogique, repérée explicitement A0 car elle est dédiée à ce seul usage (cf. chap. C2‑VIII ).
Plus évoluées, les cartes à module ESP32 disposent 2 convertisseurs indépendants, ce qui permet de numériser deux signaux en parallèle en mode continu. Sur ce point, on pourra se rapporter au lien suivant .
Par ailleurs, chacun de ces convertisseurs est multiplexé sur plusieurs broches GPIO, ce qui permet de gérer en principe jusqu'à 16 entrées analogiques. Faute de place sur la carte, ces fonctionnalités ne sont pas inscrites à côté des broches ; il faut donc se reporter au diagramme de brochage où elles sont typiquement repérées par le sigle ADCx_y où x est le numéro du convertisseur et y le numéro de broche (cf. chap. C2‑VIII ou ce lien ).
Toutefois, il faut savoir que le deuxième convertisseur (ADC2) n'est pas exploitable en même temps que les fonctionnalités Wi‑Fi et Bluetooth.
La notion de quantum
De façon générale, le quantum q d'une conversion analogique numérique représente l'accroissement en volt de la tension d'entrée ve pour obtenir un accroissement d'exactement une unité (autrement dit, +1) du nombre en sortie Ns.
Pour un CAN unipolaire comme celui intégré dans le microcontrôleur d'une carte Arduino, le quantum de la conversion s'exprime par la formule :
Parmi les cartes Arduino et compatibles les plus usuelles, on a les cas de figure suivants :
- Les cartes Arduino dont le microcontrôleur est à cœur AVR (Uno, Nano, Mega…) ont un CAN à 10 bits avec une tension de pleine échelle nominale Vmax = 5 V (c'est la valeur du potentiel VDD de la carte).
- Les modules ESP8266 ont un CAN à 10 bits avec une tension de pleine échelle Vmax = 1,1 V. Toutefois, la plupart des cartes de développement qui embarquent ce module (notamment la SBC‑NodeMCU de Joy‑It – cf. chap. C1‑III ) intègrent un pont diviseur de tension pour porter la pleine échelle de la tension d'entrée à 3,3 V (le potentiel VDD de la carte).
- Les cartes Arduino dont le microcontrôleur est à cœur ARM (Due, Zero…), ou encore les carte à module ESP32 (comme la NodeMCU‑ESP32 de Joy‑It – cf. chap. C1‑III ), ont typiquement un CAN à 12 bits avec une tension de pleine échelle Vmax = 3,3 V (c'est la valeur du potentiel VDD de la carte).
La valeur du quantum est une caractéristique théorique qui fixe une limite à la précision d'un CAN. Par exemple, on ne peut pas espérer une numérisation au millivolt près avec une carte Arduino Uno.
Toutefois, la donnée du quantum ne suffit pas à caractériser cette précision. On verra notamment infra que le CAN d'une carte Arduino Uno est plus précis que celui d'une carte à module ESP32, bien que ce dernier bénéficie d'un quantum nettement plus petit.
Fonction de transfert théorique du CAN
La fonction de transfert d'un CAN est la fonction mathématique qui à chaque valeur de la tension d'entrée ve fait correspondre une valeur du nombre en sortie Ns.
En théorie, le CAN intégré au microcontrôleur d'une carte Arduino ou compatible opère en conversion linéaire centrée. Sa fonction de transfert est représentée sur la figure ci‑dessous :
Cette courbe représentative – dite en escalier – admet des marches centrées sur la droite d'équation Ns = ve / q. Les marches ont une longueur constante de la valeur du quantum q, à l'exception de :
- la première marche, dont la longueur vaut q/2 ;
- la dernière marche, dont la longueur vaut 3q/2.
Définition algébrique de la fonction de transfert du CAN
Algébriquement, la fonction de transfert d'un CAN à conversion unipolaire centrée est définie par les formules ci‑dessous :
- si ve ∊ [0, Vmax − ½ q[, alors Ns = ℛ(ve / q) où ℛ est la fonction arrondi entier ;
- si ve ∊ [Vmax − ½ q, Vmax], alors Ns = Nmax (expression constante).
Autrement dit, cette fonction peut s'écrire : Ns = min{ℛ(ve / q), Nmax}.
Dans un programme informatique en langage C ou C++, si l'on souhaite simuler la fonction de transfert ci‑dessus (cf. ex. C3‑5 ), on peut :
- pour la fonction mathématique d'arrondi ℛ, employer la fonction
rounddéclarée dans le fichier d'en‑têtemath.hde la bibliothèque standard du langage C – directement utilisable dans un programme Arduino (cf. chap. C2‑IV ) ; - pour la fonction mathématique min, employer :
#define min(a,b) ((a)<(b)?(a):(b))
Fonction de transfert réelle du CAN
Dans la pratique, par rapport à la définition mathématique présentée supra , la fonction de transfert réelle du CAN d'un microcontrôleur présente des défauts qui peuvent être significatifs.
Certains de ces défauts peuvent néanmoins être compensés lors de l'interprétation des valeurs numériques brutes issue du CAN.
Typiquement, les défauts que l'on constate relèvent des catégories suivantes :
- unicité – on obtient plusieurs valeurs de Ns pour une même valeur de ve ;
- linéarité – la ligne moyenne des marches n'est pas droite ;
- gain – la droite moyenne n'a pas la pente attendue ;
- décalage d'origine – la droite moyenne ne passe pas par l'origine (en anglais, on parle d'offset) ;
- régularité – une valeur intermédiaire de Ns n'apparaît jamais (on parle de code manquant) ;
- monotonie – la valeur de Ns diminue alors que la tension ve augmente.
Dans la pratique, on constate les qualités et défauts suivants de CAN intégrés aux microcontrôleurs des cartes de développement usuelles.
- Sur les cartes Arduino, on a aucun défaut macroscopique : l'unicité, la linéarité et le gain sont très satisfaisants. L'erreur relative entre les mesures et les valeurs théoriques est presque toujours inférieure à 0,5 % – cf. le graphique ci‑contre pour une carte Arduino Uno où les mesures sont quasiment confondus les valeurs théoriques (voir le sujet de TP P2‑1 pour le protocole d'expérimentation).
- Sur une carte à module ESP8266, l'unicité et la linéarité sont satisfaisants. En revanche, on a deux défauts macroscopiques (cf. le graphique ci‑contre pour une carte SBC‑NodeMCU de Joy‑It) :
- un gain excessif qui s'accompagne d'une troncature en haut de l'échelle (avec la particularité que la valeur Nmax vaut 1024 et non pas 1023) ;
- un décalage d'origine négatif d'environ −0,05 V qui se traduit en bas de l'échelle par une valeur minimale de Ns environ égale à 15 et non pas 0.
- Sur une carte à module ESP32, l'unicité, la linéarité ne sont pas satisfaisants et on observe également une troncature en haut de l'échelle. Avec de tels défauts macroscopiques importants, il est difficile d'évaluer l'erreur de gain (cf. le graphique ci‑contre pour une carte NodeMCU‑ESP32 de Joy‑It).
- Le défaut d'unicité étant stochastique, il ne peut être compensé que par la répétition d'une série de conversion et un calcul de moyenne, ce qui se fait au détriment du temps de cycle du programme utilisateur. Il est toutefois possible de diminuer significativement l'étendue des variations de Ns en ajoutant un condensateur de capacité 100 nF entre la broche GND et celle de l'entrée analogique utilisée.
- Quant au défaut de linéarité, il ne correspond à aucune fonction remarquable, aussi est‑il très difficile à compenser (cf. la complexité de la solution proposée par le constructeur Espressif ). Toutefois, ce défaut diminue fortement si on accepte de réduire la tension de pleine échelle en recourant à un facteur d'atténuation (cf. la documentation suivante et ce fil de discussion ).
analogReadMilliVolts (cf. infra ) peut donner des résultats étonnamment stables et précis (avec une erreur relative d'environ 1 % entre 0,6 et 3 V). Néanmoins, pour une mise en œuvre nécessitant une précision élevée, il est préférable de recourir à un module CAN externe, comme par exemple un ADS1115 (16 bits, technologie sigma‑delta, liaison I²C), disponible sur le marché en une grande variété de modules prêt à l'emploi, par exemple celui‑ci . Fonction de lecture d'une entrée analogique
Sur une carte Arduino, contrairement à une broche du port numérique (cf. chap. C2‑VIII ), une broche Ax du port analogique n'a a priori pas besoin d'être configurée comme une entrée non référencée (INPUT) avant d'être employée pour lire des tensions analogiques, car :
C'est donc cette pratique – ne pas configurer – qui prévaut, comme on peut le constater dans les exemples académiques A.
Toutefois, on peut formuler deux exceptions à cette règle.
- Imaginons le cas où, dans le programme utilisateur, la broche aurait été auparavant configurée comme sortie (
OUTPUT) ou comme entrée référencée par l'activation d'un résistor interne (INPUT_PULLUP). Il serait alors indispensable de la reconfigurer en entrée non référencée A. - Sur les cartes à module ESP32 (cf. supra ), on a des broches polyvalentes donc, pour une meilleure lisibilité du code, il est préférable de coder une instruction de configuration de la broche avec la fonction
pinMode.
Pour lire sur une entrée analogique Ax une tension d'entrée ve par rapport à la broche GND, on code une expression d'appel de la fonction de haut niveau analogRead de la forme :
analogRead(pin)
A
et où l'argument pin est une expression qui code le numéro de la broche du port analogique.
La valeur retournée par cette fonction est le nombre en sortie Ns qui est encodé dans le type int et qui numérise la tension d'entrée ve.
On a vu supra que pour interpréter la valeur de Ns il est essentiel de tenir compte de son excursion, définie par l'intervalle 0 ‑ Nmax – laquelle dépend directement du nombre de bits d'encodage du CAN intégré au microcontrôleur de la carte.
De plus, si l'on souhaite retrouver à partir de Ns la valeur de la tension d'entrée ve il faut préalablement effectuer une mesure précise (avec un voltmètre) de la valeur réelle de la tension de référence Vmax. En effet, selon la technologie d'alimentation de la carte (cordon USB ou alimentation externe), la valeur de Vmax peut être légèrement différente de la valeur théorique du potentiel VDD.
Il faut utiliser cette valeur mesurée et non pas la valeur théorique pour calculer la valeur du quantum q de la conversion – et donc pour interpréter la valeur de Ns dans la formule algébrique donnée supra .
Le codage de l'argument pin par un numéro de broche de la forme Ax est possible parce qu'il s'agit d'identificateurs de constantes qui sont déclarées dans un fichier d'en‑tête, typiquement pin_arduino.h (cf. chap. C2‑VIII ).
Pour une meilleure lisibilité du programme, il est néanmoins recommandé de déclarer une constante dont le nom explicite le dispositif auquel est reliée la broche d'entrée analogique. Par exemple, on peut coder :
const int POTENTIOMETER_PIN = A0;
puis utiliser l'identificateur POTENTIOMETER_PIN à la place de A0 partout dans le programme, notamment comme argument de la fonction analogRead.
Par ailleurs, on a les spécificités suivantes pour les cartes à module ESP.
- Dans le framework ESP8266, un seul identificateur
A0est bien défini, mais dans le fichier d'en‑têtecommon.hG - Dans le framework ESP32, au sein du fichier
pin_Arduino.hG, on a seize identificateursAxqui sont numérotés deA0àA19mais où, attention,A1A2A8A9sont omis. Leurs valeurs respectives sont celles des numéros de broche GPIO correspondants.
Fonction de lecture en millivolts (ESP32)
La bibliothèque standard des modules ESP32 met à la disposition du codeur la fonction de lecture analogique calibrée analogReadMilliVolts dont une expression d'appel se code de la forme :
analogReadMilliVolts(pin)
Comme son nom l'indique, cette fonction retourne la valeur numérisée, exprimée en millivolts, de la tension entre la broche dont le numéro pin est passé en argument et la broche GND. Elle est de type uint32_t.
Pour obtenir une valeur exprimée en volts, il suffit de diviser cette valeur par 1000.0 (pas 1000 sinon on met en œuvre une division euclidienne).
La fonction analogReadMilliVolts trouve son intérêt dans les applications où il est nécessaire de calculer la valeur de la tension d'entrée.
Elle présente aussi une excellente alternative à la fonction analogRead pour s'affranchir en grande partie de ses défauts macroscopiques d'unicité, de linéarité et de gain, grâce à la calibration qu'elle met en œuvre (cf. supra).
En effet, à titre d'exemple, on peut constater sur le graphique ci‑contre des mesures effectuées sur une carte NodeMCU‑ESP32 la bonne coïncidence des valeurs numérisées (en rouge) avec les valeurs théoriques attendues (en vert) dans l'intervalle compris entre 0,3 et 3,1 V.
Enfin, le défaut d'origine peut être compensé par le programme utilisateur. On peut notamment le faire en codant des instructions spécifiques pour :
- d'abord, effectuer une série d'appels de la fonction
analogReadMilliVoltspour une tension nulle et mémoriser la valeur retournée la plus haute ; - ensuite, écraser les valeurs retournées par la fonction
analogReadMilliVoltssi elles sont inférieures où égales à cette valeur mémorisée.
Un exemple est donnée dans le programme du sujet de travaux pratiques P3‑4 P consacré aux capteurs de lumière (cf. les lignes nº 86 à 98).
La fonction analogReadMilliVolts retourne des valeurs fortement erronées si la résolution du CAN est ajustée à une valeur inférieure 10 bits (cf. la section suivante).
Ajustement de la résolution du CAN
Sur les cartes Arduino à cœur ARM – Due, Zero, etc. – et les modules ESP32, il est possible d'ajuster la résolution du CAN, en codant (typiquement, dans la fonction setup) un appel de la fonction analogReadResolution de la forme :
analogReadResolution(bits)
A
et où l'argument bits est une expression qui code le nombre de bits sur lequel s'expriment les valeurs retournées par la fonction analogRead.
La fonction analogReadResolution est de type void. Son code source pour les cartes Arduino Due est consultable ici .
La valeur par défaut de la résolution du CAN dépend du type de carte. Elle vaut :
-
10sur les cartes Arduino (Due, Zero…) ; -
12sur les modules ESP32.
Elle peut être ajustée à n'importe quelle valeur comprise entre 1 et 32, sachant qu'un ajustement à une valeur supérieure à la résolution maximale ne présente évidemment aucun intérêt. Cette possibilité n'est offerte que dans la perspective d'évolution de la technologie matérielle – les cartes Uno R4 (cf. chap. C1‑III ) disposent déjà d'un CAN à 14 bits.
Expérimentation sur Tinkercad
Considérons le montage académique en figure ci‑contre où le curseur d'un potentiomètre est relié à la broche A0 du port d'entrée analogique d'une carte Arduino Uno.
- Dans le cadre d'une simulation sur Tinkercad, on peut considérer que la tension de référence à laquelle le potentiomètre est alimenté vaut bien Vmax = 5 V.
- On rappelle par ailleurs qu'avec le CAN 10 bits du microcontrôleur Atmel 328P embarqué sur la carte, on a Nmax = 1023.
À partir de la valeur du nombre Ns retournée par l'appel de la fonction analogRead(A0), il est impossible de déterminer la valeur exacte de la tension d'entrée ve sur la broche A0 qui a généré ce nombre.
En effet, ve peut se situer partout sur la marche dont la « hauteur » est donnée par Ns. On prend donc « arbitrairement » le point milieu de la marche, situé à son intersection avec la droite d'équation Ns = ve / q. On obtient alors tout simplement la formule de conversion réciproque :
Sur ce principe, le programme ci‑dessous code l'affichage toutes les secondes sur le moniteur série de la valeur supposée de la tension d'entrée ve (variable inputVoltage) avec une résolution à 3 décimales (cf. la ligne nº 12) :
const int POTENTIOMETER_PIN = A0;
const float QUANTUM = 5.0 / 1024; // volts
void setup()
{
Serial.begin(115200);
}
void loop()
{
float inputVoltage = analogRead(POTENTIOMETER_PIN) * QUANTUM;
Serial.println(inputVoltage, 3);
delay(1000);
}
Par ailleurs, il est intéressant d'observer ce qui se passe quand on expérimente les positions extrêmes de la course du potentiomètre :
- Dans la position minimale (début de course, c'est‑à‑dire avec le bouton complètement tourné à gauche), le moniteur série affiche
0.000et le voltmètre 0.00 V, comme attendu. - Dans la position maximale (fin de course, c'est‑à‑dire avec le bouton complètement tourné à droite), le moniteur série affiche
4.995alors qu'on lit 5.00 V sur le voltmètre. Mais c'est logique car : - au point d'intersection de la dernière marche de la courbe en escalier avec la droite d'équation Ns = ve / q (cf. supra ), on a :
- le voltmètre, quant à lui, affiche 5.00 V puisque le potentiomètre est en fin de course ; son curseur est donc directement raccordé à la broche 5 V de la carte.
- Pour déterminer dans un programme la valeur de la tension d'entrée ve à partir de celle du nombre en sortie Ns on peut aussi employer la fonction de mise à l'échelle
mapprésentée au chap. C2‑IV . Il suffit de coder une expression d'appel de la forme : - Dans la pratique, il est rarement nécessaire de déterminer la tension d'entrée ve à laquelle correspond le nombre en sortie Ns retourné par un appel de la fonction
analogRead. Dans toutes sortes d'applications (potentiomètre, capteur, etc.), il est plus efficace de procéder directement par une relation de proportionnalité entre la valeur de Ns au regard de son excursion maximale Vmax et la grandeur que l'on cherche à quantifier.
map(analogRead(pin),
0, 1024, 0, Vmax) / 1000.0
map n'opère que sur des entiers). La division algébrique par 1000.0 permet d'obtenir un résultat en volts.
map peut être bien utile ! Ajustement de la tension de pleine échelle du CAN
Sur une carte Arduino, pour optimiser la résolution d'une conversion, c'est‑à‑dire, avoir un quantum de conversion le plus petit possible, il est possible d'ajuster la tension de pleine échelle Vmax. Il suffit de coder un appel de la fonction analogReference de la forme :
analogReference(ref)
A
et où l'argument ref est une constante énumérée parmi celles définies spécifiquement pour un modèle de carte donné.
En revanche, la valeur de pied d'échelle 0 V de la tension d'entrée est immuable sur le CAN intégré à la carte, quel que soit le modèle considéré.
Les possibilités d'ajustement de Vmax sont donc diverses selon les modèles de cartes. Mais en règle générale, la plupart disposent de deux alternatives :
- soit exploiter directement une référence de tension interne à la carte, avec seulement une ou quelques valeurs possibles, elles‑mêmes non ajustables ;
- soit appliquer une tension ajustée à volonté (mais la plus stable possible) sur une broche dédiée de la carte, typiquement nommée AREF. Dans ce cas, la valeur codée pour l'argument ref est la constante énumérée
EXTERNAL.
Une carte Arduino Uno possède une seule référence de tension interne, dont le potentiel est 1,1 V. Pour l'utiliser comme valeur de référence du CAN, dans l'appel de la fonction analogReference, il suffit de coder l'argument ref par la constante énumérée INTERNAL.
Le CAN présente alors un quantum q ≈ 1 mV cinq fois plus précis que par défaut (mais sur échelle de tension cinq fois plus réduite).
Pour ajuster l'échelle de tension du CAN avec une tension externe, une solution simple consiste à câbler un montage en pont diviseur de tension alimenté par une des bornes de tension de la carte (5V ou 3.3V).
Dans l'exemple représenté en figure ci‑contre (R1 = 3,3 kΩ et R2 = 4,7 kΩ), alimenté par la broche 5V, la tension de référence externe appliquée sur la broche AREF vaut :
Vref = 5 × 4,7 /(3,3 + 4,7) ≈ 2,94 V
Après l'appel analogReference(EXTERNAL), on obtient alors un quantum q ≈ 2,94 / 1024 ≈ 2,87 mV.
Et pour régler à nouveau la valeur de Vmax à sa valeur par défaut (5 V sur une carte Uno), il suffit de remettre hors tension la broche AREF et de coder l'instruction :
analogReference(DEFAULT);
La carte Arduino Due possède une broche AREF mais cette dernière est inopérante, à moins de dessouder le résistor BR1 de la carte A. Sans cette modification matérielle, l'échelle de tension du CAN intégré est donc non ajustable.
Écriture de sorties analogiques
Principe et caractéristiques générales du CNA
Sur les cartes Arduino à cœur ARM ou encore les modules ESP32, on dispose au moins un convertisseur numérique analogique intégré au microcontrôleur. Systématiquement, il s'agit d'un CNA à échelle de résistors W (en anglais, resistor ladder), une technologie simple et économique, suffisante pour les applications usuelles d'une telle carte.
La conversion numérique analogique consiste :
- à partir d'un nombre en entrée Ne à valeurs entières comprises 0 et une valeur Nmax ;
- à établir un tension de sortie vs aussi proportionnelle que possible à ce nombre entre une broche dédiée – typiquement, DACx – et la broche GND de la carte.
Dans la pratique, le CNA intégré au microcontrôleur des cartes Arduino à cœur ARM (Due, Zero, etc.) ou compatibles (ESP32) présente les caractéristiques générales suivantes.
- Il opère une conversion unipolaire, avec une excursion de vs comprises entre deux valeurs Vmin et Vmax ;
- Il admet pour Ne un encodage sur n bits (n = 8 à 12), procurant une échelle de valeurs comprises entre 0 et Nmax = 2n − 1 ;
Comme pour le CAN, le CNA peut être mis en œuvre selon deux modes de fonctionnement :
- en mode ponctuel (one shot), à l'aide des fonctions de haut niveau usuelles comme
analogWrite(cf. infra ) ; - en mode continu, exécuté en tâche de fond en parallèle du programme utilisateur, pour générer des signaux analogiques ; il faut pour utiliser des drivers logiciels fournis sous forme de fichiers de bibliothèque, ou encore opérer directement au niveau des registres du microcontrôleur.
Dans ce chapitre, le mode continu n'est pas abordé en raison de sa complexité de mise en œuvre. À titre d'exemple :
- pour une carte Arduino Due, on pourra se rapporter au lien suivant (en français) ;
- Pour une carte à module ESP32, on pourra se rapporter au lien suivant (en anglais).
Remarque. Les cartes Arduino Due et à module ESP32 disposent de deux CNA. On peut ainsi générer en mode continu deux signaux en parallèle.
La notion de quantum
Comme pour le CAN, on a la notion de quantum q d'une conversion numérique-analogique, qui représente l'accroissement en volt de la tension de sortie vs provoqué par un accroissement d'exactement une unité (autrement dit, +1) du nombre en entrée Ne.
Pour un CNA unipolaire comme celui intégré dans le microcontrôleur d'une carte Arduino, le quantum de la conversion s'exprime par la formule :
Parmi les cartes Arduino et compatibles les plus usuelles, on peut citer les deux cas suivants :
- Les deux CNA d'une carte Arduino Due (cf. chap. C1‑III ) génèrent une excursion de vs comprise seulement entre Vmin = 0,55 V et Vmax = 2,75 V et ont une résolution maximale sur 12 bits.
- Les deux CNA d'une carte à module ESP32 (comme la NodeMCU‑ESP32 de Joy‑It – cf. chap. C1‑III ) génèrent une excursion de vs comprise entre Vmin = 0,1 V et Vmax = 3,2 V et ont une résolution maximale sur 8 bits seulement.
Fonction de transfert du CNA
La fonction de transfert d'un CNA est la fonction mathématique qui à chaque valeur du nombre en entée Ne fait correspondre une valeur de la tension de sortie vs.
La fonction de transfert d'un CNA est plus simple que celle d'un CAN. Du fait que les grandeurs d'entrée et de sortie sont l'une et l'autre discrètes, ce n'est pas une fonction en escalier mais juste une fonction affine, voire linéaire si Vmin = 0 V – cf. sa courbe représentative en figure ci‑dessous.
Il en résulte que sa définition algébrique s'exprime simplement par la formule vs = Vmin + Ne . q.
Dans la pratique, la fonction de transfert réelle du CNA interne à un microcontrôleur présente moins de défauts comparativement à ce que l'on peut potentiellement observer pour un CAN. En règle générale :
- Au niveau macroscopique, la linéarité est satisfaisante. Seul le gain peut être différent de la valeur nominale et nécessiter une correction au cas par cas en mesurant les valeurs précises de Vmin et Vmax, ce qui permet également de corriger le défaut d'origine.
- Au niveau microscopique, on peut éventuellement constater des défauts de linéarité lors des transitions de bits, c'est‑à‑dire lorsque la valeur du nombre en entrée Ne passe de 2k − 1 à 2k avec k = n − 1 (par exemple, entre
127et128sur un convertisseur 8 bits).
Fonction d'écriture d'une sortie analogique
Sur une carte Arduino à cœur ARM, comme pour une entrée analogique (cf. supra ), il n'est pas nécessaire de coder une instruction de configuration de la broche avec la fonction pinMode pour utiliser une sortie analogique.
En effet, il s'agit d'une broche dédiée étiquetée DAC dont on fait un usage nominal, donc il n'y a pas ici de nécessité particulière d'un appel de la fonction pinMode en termes de lisibilité du programme.
De plus, même si, comme pour toutes les autres broches, elle adopte par défaut le mode d'une entrée non référencée (donc, avec un potentiel flottant – cf. chap. C2‑VIII ), le premier appel de la fonction analogWrite stabilise le signal tension de sortie conformément à la valeur codée par l'argument value (cf. infra).
Sur une carte Arduino à cœur ARM – et attention, pas sur un module ESP32 – pour écrire sur une broche DACx une tension de sortie vs par rapport à la broche GND, on code une expression d'appel de la fonction de haut niveau analogWrite de la forme :
analogWrite(pin, value)
A
et où :
- l'argument pin est une expression qui code le numéro de la broche utilisée sur le port analogique ;
- l'argument value est une expression qui code la valeur du nombre en entrée Ne.
La fonction analogWrite est de type void ; elle ne retourne donc aucune valeur.
Le codage de l'argument pin par un numéro de broche de la forme DACx est possible parce qu'il s'agit d'identificateurs de constantes qui sont déclarées dans un fichier d'en‑tête, comme par exemple variant.h pour les cartes Arduino Due G.
Pour une meilleure lisibilité du programme, il est néanmoins recommandé de déclarer une constante dont le nom explicite le dispositif auquel est reliée la broche de sortie analogique. Par exemple, on peut coder :
const int HEAT_SIGNAL_PIN = DAC0;
puis utiliser l'identificateur HEAT_SIGNAL_PIN à la place de DAC0 partout dans le programme, notamment comme argument de la fonction analogWrite.
Cas des modules ESP32
Pour l'emploi d'une sortie analogique, les cartes à module ESP32 présentent quelques différences par rapport aux cartes Arduino :
- Les broches ne sont pas étiquetées « DAC », il faut donc consulter le schéma de brochage de la carte, qui diffère selon le type de module embarqué.
- La fonction d'écriture se nomme
dacWriteet non pasanalogWrite. En effet, sur ces cartes, les broches sont polyvalentes et peuvent être aussi utilisées en MLI – et justement avec la fonctionanalogWrite(cf. infra ) qui ne peut pas faire double emploi.
DAC1 et DAC2 qui sont des constantes déclarées dans le fichier d'en‑tête pins_Arduino.h G. dacWrite se code avec la même syntaxe que celle de la fonction analogWrite (cf. supra ). dacDisable pour désactiver la possibilité d'écriture analogique sur la broche dont le numéro est passé en argument. Ajustement de la résolution du CNA
Sur les cartes Arduino à cœur ARM – Due, Zero, etc. – il est possible d'ajuster la résolution du CNA, en codant un appel de la fonction analogWriteResolution de la forme :
analogWriteResolution(bits)
A
et où l'argument bits est une expression qui code le nombre de bits sur lequel peut s'exprimer les valeurs de Ne passées par l'argument value à la fonction analogWrite.
La fonction analogWriteResolution est de type void. Son code source pour les cartes Arduino Due est consultable ici .
Comme pour un CAN, la valeur par défaut de la résolution du CNA dépend du type de carte. Elle vaut 8 sur les cartes Arduino (Due, Zero…) .
Elle peut être ajustée à n'importe quelle valeur comprise entre 1 et 32, sachant qu'un ajustement à une valeur supérieure à la résolution maximale ne présente évidemment aucun intérêt. Cette possibilité n'est offerte que dans la perspective d'évolution de la technologie matérielle.
Écriture de sorties numériques modulées
En rappel de l'introduction de ce chapitre, en l'absence de convertisseur numérique analogique (CNA) – ce qui est le cas sur les microcontrôleurs à AVR embarqués sur les cartes Arduino Uno, Mega, Nano… – il est quand même possible de faire varier la tension moyenne de certaines sorties du port numérique, par la technique dite de modulation par largeur d'impulsion.
Principe et caractéristiques de la MLI
La modulation par largeur d'impulsion W ou MLI – en anglais pulse width modulation, abrégée PWM – peut opérer sur certaines broches du port numérique d'une carte Arduino.
La MLI consiste à générer sur une telle broche un signal logique périodique et rectangulaire de tension u tel que :
- sa période T est suffisamment petite pour être négligeable au regard de l'échelle de temps de fonctionnement du système ;
- son rapport cyclique α est modulable en temps‑réel ; c'est le paramètre de la modulation qui permet de faire varier la valeur moyenne Umoy du signal de tension.
Le signal logique de sortie ainsi généré est cadencé par un timer interne W à la carte, piloté par le microcontrôleur en parallèle de l'exécution du programme.
Rappelons qu'un signal logique de tension u ne prend que deux valeurs possibles dites haute et basse. Pour une carte à microcontrôleur, ces deux valeurs sont 0 V et VDD (le potentiel haut de la carte).
Si le signal est périodique et rectangulaire, il peut être caractérisé par :
- sa période T, qui se décompose en la somme d'un temps haut TH et un temps bas TB ;
- son rapport cyclique α défini par α = TH/T (c'est un nombre compris entre 0 et 1 car nécessairement, TH ⩽ T).
Sachant que Umin= 0 V, il en résulte sur la broche une tension moyenne égale à :
Umoy = α.Umax
(Graphiquement, elle divise la courbe représentative du signal en délimitant deux aires A égales – cf. la figure ci‑dessus).
Cette tension moyenne Umoy est donc proportionnelle à α et, sachant que α ∊ [0, 1], elle est comprise entre 0 et Umax. En particulier, on a les deux cas limites suivants :
- Umoy = 0 si α = 0
- Umoy = Umax si α = 1.
Si la fréquence f = 1/T du signal est suffisamment élevée (dès 30 Hz environ, mais en général, on module via des fréquences beaucoup plus élevées, au moins 300 Hz), cette technique offre de nombreuses applications :
- Elle permet notamment de faire varier la luminosité d'une led (cf. l'exemple infra ). Pour l'œil humain, la discontinuité du signal est imperceptible par effet de persistance rétinienne W. Et cependant, la led apparaît significativement moins brillante que si elle était alimentée à la tension continue maximale du signal.
- De même, on peut moduler l'amplitude du son d'un buzzer (c'est‑à‑dire un petit dispositif capable d'émettre un son – cf. la photo ci‑contre).
- On peut également piloter la vitesse de rotation d'un moteur à courant continu, via circuit électronique d'alimentation appelé hacheur (car la sortie d'une carte à microcontrôleur ne délivre pas un courant suffisant pour alimenter un moteur).
- Même avec une valeur très faible du rapport cyclique, on parvient à vaincre les forces de frottement et à faire tourner le moteur à très basse vitesse grâce aux impulsions à pleine tension. Ce ne serait pas le cas avec des valeurs très faibles de la tension qu'on pourrait générer avec un CNA.
- En revanche, le fait d'appliquer une tension hachée génère dans les bobinages du moteur un courant en dent de scie qui peut poser des problèmes d'efficacité énergétique.
Fonction de modulation d'une sortie numérique
Avec une carte Arduino, cela peut sembler surprenant mais, comme pour une sortie analogique (cf. supra ), il ne serait en principe pas nécessaire de configurer une broche du port numérique utilisée en modulation de largeur d'impulsion.
En effet, sur le signal de tension modulée, la fonction analogWrite parvient à générer des niveaux HAUT et BAS conformes aux potentiels 0 V et VDD de la carte.
Toutefois, dès lors que l'on utilise une broche polyvalente, en termes de lisibilité du programme, il est préférable de coder un appel de la fonction pinMode avec la valeur OUTPUT pour l'argument mode (cf. chap. C2‑VIII ).
Avec une carte Arduino, pour moduler en largeur d'impulsion la tension de sortie par rapport à la broche GND d'une broche du port numérique étiquetée ∼x, on emploie la fonction analogWrite :
analogWrite(pin, value);
A
où :
- l'argument pin est une expression qui code le numéro de broche x du port numérique de la carte ;
- l'argument value est une expression à valeur entière (encodée dans le type
int), comprise entre0et une valeur Nmax ; elle code par proportionnalité la valeur du rapport cyclique α du signal, compris entre 0 et 1.
La fonction analogWrite est de type void, elle ne retourne donc aucune valeur.
En d'autres termes, après exécution d'une instruction de la forme :
analogWrite(pin, value);
la valeur du rapport cyclique du signal de MLI sur la broche pin vérifie la relation :
Après un appel de la fonction analogWrite, le signal de MLI est maintenu sur la broche jusqu'au prochain appel d'une des fonctions analogWrite, digitalWrite ou digitalRead appliquées à cette broche.
Dans le framework Arduino, l'identificateur analogWrite de la fonction de modulation est le même que celui d'écriture d'une sortie analogique par CNA (cf. supra ). En effet :
- Même si le principe est différent, la modulation engendre sur la broche un signal de tension dont la valeur moyenne Umoy est ajustable entre 0 et Umax comme la tension sur une sortie analogique (cf. supra ).
- Par ailleurs, sur les cartes Arduino, il n'y a pas de conflit possible entre MLI et CNA, car aucune broche ne cumule les deux fonctionnalités.
Comme pour un CNA, la mise en œuvre d'une sortie en MLI peut être caractérisée par la résolution du nombre codant le rapport cyclique α du signal. Elle est donc exprimée en nombre de bits n, de sorte que Nmax = 2n − 1.
Sachant la valeur du potentiel VDD, on peut alors en déduire la variation incrémentale δU de la tension moyenne sur la broche qu'il est possible de coder (l'équivalent du quantum pour un CNA) : on a δU = VDD / Nmax.
Comme pour le CNA (cf. supra ), l'amplitude réelle du signal de tension en MLI n'est pas exactement égale à sa valeur théorique VDD. Selon la valeur réelle de la tension d'alimentation de la carte, on peut observer un écart jusqu'à ±0,2 V.
Codage de l'argument value
Dans un appel de la forme :
analogWrite(pin, value)
le codage de l'expression value passée en argument dépend de la finalité d'emploi de la tension variable générée sur la broche pin et du paramètre de pilotage de cette tension.
Si le paramètre de pilotage est le rapport cyclique α du signal de tension, alors tout dépend de la manière dont α est lui‑même codé. Typiquement, on peut avoir les cas de figures suivants :
- Si α s'exprime comme un nombre décimal compris entre 0 et 1 – donc codé dans un type décimal comme
float– alors on peut coder value par une expression de la forme :
round(Nmax * α) - Si α est exprimé comme un nombre entier compris entre 0 et 100 – autrement dit un pourcentage – alors on peut coder value par une expression de la forme :
map(α, 0, 100, 0, Nmax)
Si le paramètre de pilotage est la valeur moyenne de la tension Umoy générée sur la broche alors, là aussi, tout dépend de la manière dont Umoy est codée. Typiquement, on peut avoir les cas de figures suivants :
- Si Umoy est exprimée en volts comme un nombre décimal compris entre 0 et VDD – autrement dit codé dans un type décimal comme
float– alors on peut coder value par une expression de la forme :
round(Nmax * Umoy / VDD) - Si Umoy est exprimée en millivolts comme un nombre entier compris entre 0 et VDD × 1000 – donc, par exemple codé dans le type
int16_t– alors on peut coder value par une expression de la forme :
map(Umoy, 0, VDD * 1000, 0, Nmax)
Plus généralement, le paramètre de pilotage peut être spécifique au dispositif relié à la broche utilisée en MLI. Par exemple, si ce dispositif est un moteur, le paramètre sera typiquement sa fréquence de rotation.
Dans un tel cas, le recours à la fonction de mise à l'échelle map (cf. chap. C2‑IV ) est très commode.
Cas pratiques sur cartes Arduino
À titre d'exemple emblématique, sur une carte Arduino Uno R3, les broches du port numérique pilotables en MLI portent les numéros 3 5 6 9 10 11 (elles sont toutes repérées par le symbole ∼ comme on peut le voir sur la figure ci‑contre).
On a les caractéristiques suivantes :
- La résolution est encodée sur 8 bits, autrement dit la valeur du rapport cyclique est codée par un nombre entier compris entre 0 (correspondant à α = 0) et 28 − 1 = 255 (correspondant à α = 1). Autrement dit, on peut régler le rapport cyclique α à 1/256 ≈ 0,004 près.
- La fréquence de modulation vaut :
- 490 Hz pour les broches 3 9 10 11 ;
- 980 Hz pour les broches 5 6 (le timer associé est le même que celui exploité par les fonctions
millisetdelay(cf. chap. C2‑IX ).
En se basant sur la valeur nominale VDD = 5 V de la carte, il en résulte une variation incrémentale de la tension moyenne égale à δU = 5 / 256 ≈ 0,02 V.
À titre de comparaison, une carte Arduino Mega, qui basée sur une architecture similaire à celle d'une carte Uno (un cœur AVR 8 bits cadencé à 16 MHz – cf. chap. C1‑III ), opère aux mêmes fréquences de MLI, mais sur plus de broches :
- 490,2 Hz pour les broches 2 à 3, 5 à 12 et 44 à 46 ;
- 976,56 Hz pour les broches 4 et 13.
Pour aller plus loin sur les techniques de MLI sur les cartes Arduino, on pourra consulter les pages web suivantes A .
Les deux montages académiques proposés ci‑après avec une carte Arduino Uno proposés ci‑après peuvent être testés dans l'environnement Tinkercad.
- Le montage représenté ci‑dessous d'un variateur de luminosité d'une led est constitué :
- d'une led dont l'anode est reliée (via une résistance de limitation de courant) à la broche PWM 3 du port numérique de la carte ;
- d'un potentiomètre relié à la broche A0 du port analogique de la carte.
- Le montage représenté ci‑dessous de commande d'une led RGB est constitué d'une led RGB dont :
- la cathode commune est directement reliée à la broche GND de la carte ;
- les trois anodes R (red) G (green) B (blue) sont respectivement reliées aux broches PWM 9 10 11 de la carte, chacune via une résistance de limitation de courant de 220 Ω.
brightness, calculée par mise à l'échelle avec la valeur lue sur le potentiomètre, comme dans le programme ci‑dessous (cf. la ligne nº 11) :
const int8_t POTENTIOMETER_PIN = A0;
const int8_t LED_PIN = 3;
void setup()
{
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int16_t potentiometerValue = analogRead(POTENTIOMETER_PIN);
uint8_t brightness = map(potentiometerValue, 0, 1023, 0, 255);
analogWrite(LED_PIN, brightness);
delay(10); // for a fluid Tinkercad simulation
}
analogWrite, appliquée à la broche correspondante. MediumOrchid dont le code est #BA55D3 s'obtient avec les trois appels successifs de la fonction analogWrite (cf. les lignes n° 12 à 14) dans le programme ci‑dessous.
const uint8_t LED_RED_PIN = 6;
const uint8_t LED_GREEN_PIN = 10;
const uint8_t LED_BLUE_PIN = 11;
void setup()
{
pinMode(LED_RED_PIN, OUTPUT);
pinMode(LED_GREEN_PIN, OUTPUT);
pinMode(LED_BLUE_PIN, OUTPUT);
// color: Medium Orchid #BA55D3
analogWrite(LED_RED_PIN, 0xBA);
analogWrite(LED_GREEN_PIN, 0x55);
analogWrite(LED_BLUE_PIN, 0xD3);
}
void loop()
{
delay(10); // for a quicker Tinkercad simulation
}
Spécificités sur les cartes à module ESP
Sur les cartes à module ESP, la plupart des broches GPIO peuvent être utilisées comme sorties pilotées en MLI. Cette faculté est indiquée sur les diagrammes de brochage par le symbole ∿ (cf. chap. C2‑VIII pour une cartes à module ESP8266 ou ESP32 ). Et avec certaines broches, on est évidemment assujetti aux mêmes contraintes que pour une sortie booléenne en termes de conflit avec d'autres fonctionnalités, notamment la liaison série au poste de travail.
Sur toutes ces broches, on a par défaut les caractéristiques de MLI suivantes :
- la résolution est de 8 bits (comme sur une carte Arduino) ;
- la fréquence de modulation est de 1 kHz ;
sachant que ces deux paramètres étant l'un et l'autre ajustables par appel de fonctions de haut niveau.
Ajustement de la résolution de modulation
Dans les frameworks ESP8266 et ESP32, on dispose de la même fonction analogWriteResolution, de type void, qui permet de changer la résolution de modulation, c'est‑à‑dire l'étendue des valeurs possibles de l'argument value de la fonction analogWrite. Un tel changement s'applique potentiellement à toutes les broches, en codant dans le programme un appel de la forme :
analogWriteResolution(resolution)
où l'argument resolution est une expression à valeurs entières qui code le nombre de bits sur lequel peut s'exprimer l'échelle de valeurs du rapport cyclique du signal de MLI (cf. supra ).
La valeur maximale de l'argument resolution est de 16 bits, permettant donc de coder le rapport cyclique du signal de MLI compris entre 0 et 65535. En théorie, cette résolution procure donc une variation incrémentale de la tension moyenne de sortie égale à δU = 3,3 / 65536 ≈ 0,05 mV ! Mais en réalité, une telle résolution est peu utile et flirte avec les limites de performances en vitesse du microcontrôleur. En effet, à la fréquence de modulation par défaut de 1 kHz, la période vaut T = 1 ms, donc une incrémentation unitaire de l'argument value de la fonction analogWrite engendre une variation du temps haut du signal de MLI égale à ΔTH 1/65536 ≈ 15 ns. Or le temps de cycle du processeur dure 6 ns sur un module ESP8266 et 4 ns sur un module ESP32.
Dans la pratique, une résolution à 12 bits est, en règle générale, tout à fait suffisante pour les applications exigeantes. Elle procure une variation incrémentale de la tension moyenne de sortie δU = 3,3 / 4096 ≈ 0,8 mV.
Ajustement de la fréquence de modulation
Dans les frameworks ESP8266 et ESP32, on dispose d'une fonction d'ajustement, de type void, pour ajuster la fréquence du signal de modulation :
- Pour un module ESP8266, la fonction se nomme
analogWriteFreq, et elle opère pour toutes les broches potentiellement utilisables en MLI. Elle n'accepte donc qu'un seul argument frequency, de typeuint32_t, qui code directement la valeur de la fréquence en Hz. - Pour un module ESP32, la fonction se nomme
analogWriteFrequencyet elle opère individuellement pour chaque broche potentiellement utilisables en MLI. Elle possède donc deux arguments : - pin qui désigne le numéro de la broche à laquelle s'applique l'ajustement ;
- frequency qui, comme ci‑dessus, exprime la valeur de la fréquence en Hz.
Dans les deux frameworks, la valeur maximale théorique de l'argument frequency est de 60000 Hz (60 kHz). Mais là encore (comme pour l'ajustement de la résolution – cf. supra ), il faut prendre garde à ne pas dépasser les limites de performances en vitesse du microcontrôleur. En effet, à une telle fréquence, la période du signal est d'environ 17 µs, donc avec une résolution sur seulement 10 bits, une incrémentation unitaire de l'argument value de la fonction analogWrite engendre une variation du temps haut du signal ΔTH ≈ 17/1024 ≈ 16 ns.
Dans la pratique, une fréquence de 20 kHz est, en règle générale, tout à fait suffisante pour les applications exigeantes.
En particulier, pour piloter un moteur à courant continu en variation de vitesse avec un hacheur W correctement dimensionné, une telle fréquence permet en principe d'atteindre le régime dit de conduction continue qui garantit une bonne stabilité du courant dans le rotor.