Cours 3 Timers
Cours 3 Timers
D.Naceur
1
Electronique des Systèmes Embarqués
Introduction : le domaine visé, les systèmes embarqués
La plus grande partie des systèmes électroniques complexes utilisés de nos jours
sont des systèmes embarqués : téléphones mobiles, horloges, baladeurs,
récepteurs GPS, électroménager, automobile, transport aérien/maritime/fluvial.
Les systèmes embarqués se démarquent des systèmes informatiques traditionnels
selon plusieurs aspects :
D.Naceur
2
Electronique des Systèmes Embarqués
D’où la solution: Le microcontrôleur
D.Naceur
6
Electronique des Systèmes Embarqués
Composition d'un timer type
•des broches :
• d'entrée : pour compter ses changements d'états ; ce sont les « évènements
externes » que le timer peut compter ;
• de sortie : pour signaler que le compteur a atteint une valeur particulière ;
•un sélecteur : sélectionne l'entrée dont les changements d'états (évènements) seront
comptés, en général :
• l'horloge interne
• ou une broche externe ;
•un prédiviseur :
• dans le cas où le compteur est connecté à l'horloge, il est possible de ralentir
le comptage en ne comptant qu'1 top d'horloge sur n ;
• n : c'est le prédiviseur. Il est généralement choisi parmi un ensemble de
puissances de 2, par exemple : {1, 16, 64, 256} ;
D.Naceur
9
Electronique des Systèmes Embarqués
Si le registre du timer comporte 8 bits, il est alors capable de
compter de 0 à 255 (en hexadécimal, de 00 à FF). Lorsqu’il
arrive à 255 (FF), un coup d’horloge supplémentaire devrait
le faire passer à 256 (soit 100 en hexadécimal), Le registre
passe donc à 0 ; on dit qu’il subit un débordement
D.Naceur
10
Electronique des Systèmes Embarqués
Au niveau des diviseurs de fréquences possibles sur l’ATmega328P, on retrouve :
D.Naceur
13
Electronique des Systèmes Embarqués
À noter que la valeur du prescaler peut être changée à tout moment, de manière
logicielle (dans le code arduino, donc). Et pour ce faire, il suffit simplement de
changer un ou plusieurs bits du registre « CLKPR », interne à l’ATmega328P. Voici le
détail de chacun des bits de ce registre :
14
Com c’est le bit « CLKPCE » (tout à gauche) qui permet d’indiquer au microcontrôleur que
l’on souhaite modifier la valeur du prescaler. Et une fois cette indication faite, il suffira de
renseigner les bits CLKPS3, CLKPS2, CLKPS1, et CLKPS0 au microcontroleur, pour spécifier le
rapport de division souhaité. Ainsi, selon la valeur de ces bits, la fréquence en sortie du
prescaler sera égale à la fréquence d’horloge en entrée, divisée par le rapport correspondant.
D.Naceur
15
Electronique des Systèmes Embarqués
Exemple : si vous souhaitez activer le prescaler, pour qu’il divise la fréquence
d’horloge par 32, alors il faudra écrire les 2 lignes de code suivantes, dans
votre programme Arduino :
À peu de choses près, il s’agit de la même chose que pour le prescaler. Alors
que le prescaler ralentit « tout » le microcontrôleur, les prédiviseurs, quant à
eux, ne ralentissent que les timers auxquels ils sont associés. Par contre, les
prédiviseurs sont « alimentés » avec la fréquence du prescaler. C’est à dire que
la fréquence d’un timer donné, sera en fait égale à la fréquence d’horloge du
microcontrôleur, divisée par le rapport de division du prescaler, puis encore
divisée par le rapport du prédiviseur associé à ce timer.
D.Naceur
17
Electronique des Systèmes Embarqués
L’intérêt d’un timer est qu’il compte sans cesse et que pendant ce temps, le programme peut
réaliser autre chose. Le temps que le timer met pour compter 256 coups dépend bien sûr de
la fréquence de l’horloge ; à 16 MHz c’est très rapide, mais il est possible de diviser cette
fréquence d’horloge grâce aux prédiviseurs du microcontrôleur. On peut alors diviser la
fréquence de base (16 MHz) par 8, 32, 64, 128, 256 ou 1024 ; pour cela, il faut utiliser
d’autres registres de contrôle associés au timer.
Par exemple, si on règle le prédiviseur à 1024 pour diviser la fréquence, le timer comptera donc
à une fréquence de 15625 Hz. D.Naceur
18
Electronique des Systèmes Embarqués
Architecture du bloc timer à l’intérieur du microcontrôleur ATmega328P
19
Les timers fonctionnent sous différents modes configurés par les bits
WGM20 , WGM21 et WGM22 des registres de contrôle TCCR2A et TCCR2B,
WGM signifie Waveform Generation Mode
D.Naceur
20
Electronique des Systèmes Embarqués
Exemples:
Le comptage « Normal » : le timer visé compte jusqu’à atteindre
sa valeur maximale possible, puis envoie un signal de
débordement (overflow), avant de revenir à zéro (et continuer à
compter)
Le comptage « CTC » : là, le timer va compter jusqu’à déclencher
une alerte « en cours de route » (levée de drapeau, ou « flag » ),
lorsque sa valeur courante sera égale à une valeur de référence
qu’on aura préalablement définie (spécifiée dans un registre dit
« de comparaison »). À ce moment-là, une interruption pourrait
être générée, si souhaité. Et dans tous les cas, le timer, quant à
lui, aura repris son comptage depuis zéro !
D.Naceur
21
Electronique des Systèmes Embarqués
Comme pour tout registre, on peut lire la valeur d’un timer ou bien
écrire une valeur particulière dans le timer. Mais ce qui est surtout
important, ce sont les registres de contrôle associés au timer car ce
sont eux qui permettent de modifier le comportement du timer et de
contrôler ce qu’il fait.
D.Naceur
22
Electronique des Systèmes Embarqués
Exemple d’utilisation simple:
On se propose d’utiliser le timer 2 dans son rôle le plus simple, compter le temps,
donc on va s’intéresser aux registres de contrôle qui lui sont associés. Ce que nous
allons dire reste bien entendu valable pour les timers 0 ou 1. On veut faire clignoter
une LED à 1 Hz, ce qui signifie que toutes les 500 ms (demi-période), il faut inverser
la LED, c’est-à-dire l’allumer si elle est éteinte et l’éteindre si elle est allumée.
D.Naceur
23
Electronique des Systèmes Embarqués
Pour accélérer un timer, il faut le faire déborder avant qu’il compte 256 : pour cela, il
suffit de partir d’une valeur différente de 0 pour effectuer le comptage puisqu’il est
possible d’écrire dans le registre du timer.
Il faut surveiller le flag TOV2 ; chaque fois qu’il est à 1, on repositionne le flag à 0 et
on incrémente un compteur. Lorsque ce compteur arrive à une certaine valeur, on a
atteint 500 ms , il faut alors agir sur la LED.
Pour que le timer ait ce comportement, il doit être utilisé en mode normal ; dans ce
mode, le timer compte en incrémentant, et le flag est positionné à 1 chaque fois que le
timer repasse par 0.
Pour que le timer soit en mode normal, il faut que les 3bits
WGM20 , WGM21 et WGM22 des registres TCCRxA et TCCRxB
soient à 0.
Pour avoir le facteur de division souhaité, il faut mettre les bits 0 à
2 CS20 , CS21 et CS22 du registre TCCRxB aux valeurs adéquates.
D.Naceur
24
Electronique des Systèmes Embarqués
Calcul théorique du comptage
Le timer 2 sera utilisé en le faisant compter à la fréquence de 62500 Hz (fréquence
d’horloge divisée par 256). Un cycle d’horloge dure donc 16 µs (l’inverse de la
fréquence). Pour avoir 500 ms (500000 µS), il faut compter 500 000 µs / 16 µs = 31250
fois. Cette valeur est décomposable en 125 * 250. Le timer doit compter 250 fois pour
déborder ; il suffit de le faire partir de la valeur 6. Chaque fois qu’il déborde, une
variable compteur est incrémentée ; quand cette variable atteint 125, on a bien 500
ms qui se sont écoulées et on agit sur la LED.
Rq: La dernière chose à savoir, c’est que pour réinitialiser le flag TOV2 par logiciel, il
faut écrire à 1 le bit 0 du registre TIFR2 ; l’instruction est bitSet (et
non bitClear comme on aurait pu le croire).
D.Naceur
25
Electronique des Systèmes Embarqués
le programme, écrit en langage Arduino :
•/*
• * Clignotement d'une LED à 1 Hz par le timer 2.
• */
•const byte Led = 13; // Pour utiliser la LED du module
•#define LedToggle digitalWrite (Led, !digitalRead(Led))
•
•void setup ()
•{
• pinMode (Led, OUTPUT);
• bitClear (TCCR2A, WGM20); // WGM20 = 0
• bitClear (TCCR2A, WGM21); // WGM21 = 0
• TCCR2B = 0b00000110; // Clock / 256 soit 16 micro-s et WGM22 = 0
• TIFR2 = 0b00000001; // TOV2
• TCNT2 = 256 - 250; // Chargement du timer à 6
•}
•
•byte varCompteur = 0; // La variable compteur
•
•void loop () {
• if (bitRead (TIFR2, 0) == 1) { // Flag TOV2 mis à 1 ?
• TCNT2 = 256 - 250; // Rechargement du timer à 6
• bitSet (TIFR2, TOV2); // Remise à zéro du flag TOV2
• if (varCompteur++ > 125) { // Incrémentation et a atteint 125 ?
• varCompteur = 0; // On recommence un nouveau cycle
• LedToggle; // Inversion de la LED
• }
• }
•}
D.Naceur
26
Electronique des Systèmes Embarqués
Introduction aux interruptions internes aux timers:
La surveillance du débordement du timer revient à surveiller le flag TOV2 , ce
qui prend du temps et interfère avec le déroulement du programme principal. Afin
de libérer le programme de cette tâche de surveillance, nous allons faire appel aux
interruptions commandées par les timers.
Un microcontrôleur fonctionne de la même façon : un événement interne (timer)
ou bien externe (broche) demande une interruption au microcontrôleur. Celui-ci va
s’interrompre dans son programme principal, puis va exécuter un sous-programme
(on parle de routine d’interruption). Une fois que cette routine est exécutée, le
microcontrôleur reprend son programme principal, là où il s’était arrêté, et continue
son exécution. Pour cela, il a fallu que le microcontrôleur sauve différents registres
sur une pile et les rétablisse en fin de routine d’interruption. Il faut aussi que le
programmeur ait autorisé les interruptions ; si le programme doit réaliser une tâche
selon une chronologie très rigoureuse, il peut être nécessaire de ne pas les autoriser
pour ne pas déranger le microcontrôleur et c’est donc au programmeur de décider
d’autoriser ou non les interruptions. La fonction sei() permet d’autoriser les
interruptions alors que la fonction cli() permet de les ignorer ; on peut aussi utiliser
les fonctions interrupts() et noInterrupts() du langage Arduino.
D.Naceur
27
Electronique des Systèmes Embarqués
L’interruption du timer 2
Toutes les demandes d’interruption arrivent sur une porte OU et sont éventuellement
bloquées par le signal GIE (Global Interrupt Enable) activé par la fonction sei(). La figure
suivante nous permet de comprendre comment le timer 2 peut faire une demande
d’interruption.
Note: En langage C, ce bit I est modifiable via les appels sei() cli()
D.Naceur 28
Electronique des Systèmes Embarqués
Ce circuit se trouve à l’intérieur du microcontrôleur qui équipe le module Arduino Uno.
Pour que le timer déclenche une interruption, il faut qu’il y soit autorisé ( TOIE2 à 1) ET qu’il déborde
( TOV2 à 1), ces deux conditions arrivant sur une porte ET en amont de la porte OU. Il faut aussi que les
interruptions soient autorisées de façon générale : c’est le rôle du flag GIE , le bit 7 du
registre SREG (Status Register) qui alimente une porte ET en aval de la porte OU.
D.Naceur 29
Electronique des Systèmes Embarqués
ATmega328P
Si toutes les conditions que nous venons de voir sont réunies, l’interruption arrive au
microcontrôleur qui va donc interrompre son programme principal pour aller exécuter sa routine
d’interruption (ISR pour Interrupt Routine Service). Le système Arduino a prévu une routine au nom
réservé qu’il suffit de compléter : celle-ci commence par ISR(TIMER2_OVF_vect)signifiant qu’il
s’agit d’une routine d’interruption déclenchée par le vecteur d’overflow du timer 2. Cette routine remet
automatiquement à 0 le flag TOV2 , ce qu’il fallait faire soi-même lorsqu’on surveillait le flag sans faire
appel aux interruptions.
Vector Number Interrupt definition Vector name
Les registres OCR (Output Compare Register) ont la même taille que le timer auquel ils sont
associés et il y en a deux par timers, repérés par les lettres A et B.
33
Pour autoriser les interruptions, il faut les autoriser de façon générale (avec sei() ou
bien interrupts() et il faut aussi autoriser l’interruption produite par le flag OCF2A .
Ceci se réalise en positionnant à 1 le bit OCIE2A (Timer/Counter 2 Output Compare
Match A Interrupt Enable). Ce bit OCIE2A est le bit 1 du
registre TIMSK2 (Timer/Counter 2 Interrupt Mask Register).
TIMSK2 = 0b00000010
34
Le mode CTC (Clear Timer on Compare Match Mode)
Le timer 2 a été utilisé dans le mode normal et il avait été nécessaire de positionner à
0 trois bits appelés WGM2 situés dans les registres TCCR2A etTCCR2B.
Dans ce mode CTC le timer/counter est remis à zéro quand sa valeur correspond à
celle du registre OCR2A. Le timer 2 compte traditionnellement de 00 (appelé
BOTTOM) à FF (appelé MAX) ; grâce au mode CTC, nous pouvons le faire compter
de BOTTOM à la valeur de OCR2A (appelée TOP).
En effet, dans l’exemple précédent, nous faisions compter notre timer de 6 à 255
pour qu’il compte 250, et nous lui faisions faire cela 125 fois pour obtenir un temps
total égal à la demi-période de clignotement de notre LED. Nous allons faire
exactement la même chose, avec les mêmes paramètres, pour obtenir le même
résultat (clignotement de la LED du module Uno à la fréquence de 1 Hz), mais cette
fois, nous ferons compter le timer de 0 à 250.
D.Naceur 35
Electronique des Systèmes Embarqués
La figure 2 montre le timer 2 dans le mode CTC ; il compte de 00 à TOP (qui vaut OCR2A soit
250) et lorsqu’il atteint cette valeur, il est remis à zéro et une interruption est générée par le
flag OCF2A . 36
Allure d’un signal mode CTC
Selon cette figure « OCn » peut être utilisé comme signal de sortie de la broche « OCnx »
associée.
La fréquence du signal est obtenue par l’équation suivante :
N étant le facteur de pré division pouvant prendre les valeurs 1, 8, 64, 128, 256, ou 1024.
D.Naceur
37
Electronique des Systèmes Embarqués
TCCR2A = 0b00000010
TCCR2B = 0b00000110
TIMSK2 = 0b00000010
D.Naceur
38
Electronique des Systèmes Embarqués
•// Clignotement d'une LED à 1 Hz par le mode CTC et une
•// interruption en provenance du timer 2, flag OCF2A, pendant que le programme
•// principal fait clignoter une autre LED (période 10s).
•const byte Led = 13; // Pour utiliser la LED du module
•const byte Led2 = 5; // Led clignotante du programme principal
•#define LedToggle digitalWrite (Led, !digitalRead(Led))
•#define Led2Toggle digitalWrite (Led2, !digitalRead(Led2))
•void setup () {
• pinMode (Led, OUTPUT);
• pinMode (Led2, OUTPUT);
• cli(); // Désactive l'interruption globale
• TCCR2A = 0b00000010;
• TCCR2B = 0b00000110; // Clock / 256 soit 16 micro-s et WGM22 = 0
• TIMSK2 = 0b00000010; // Interruption locale autorisée par OCIE2A
• OCR2A = 250;
• sei(); // Active l'interruption globale
•}
•byte varCompteur = 0; // La variable compteur
•
•// Routine d'interruption
•ISR(TIMER2_COMPA_vect) {
• if (varCompteur++ > 125) { // 125 * 4 ms = 500 ms (demi-période)
• varCompteur = 0;
• LedToggle;
• }
•}
•void loop () {
• // Mettre ici le programme. Exemple :
• Led2Toggle;
• delay (5000); // Demi-période de la deuxième LED 39
•}
Utilisation du Timer 1 pour le meme exemple: Mode CTC
avec Interruption
TCCR1B = 0b00001100
TIMSK1 = 0b00000010
OCR1A = 31250
D.Naceur
43
Electronique des Systèmes Embarqués
•// Clignotement de la LED (mot anglais pour DEL) avec une
interruption
•// générée par le mode CTC du timer 1 - Fréquence 1 Hz
•
•const byte ledPin = 13;
•
•void setup() {
• pinMode (ledPin, OUTPUT);
• noInterrupts();
• TCCR1A = 0;
• TCCR1B = 0b00001100;
• TIMSK1 = 0b00000010;
• TCNT1 = 0;
• OCR1A = 31250;
• interrupts();
•}
•ISR(TIMER1_COMPA_vect)
•{
• digitalWrite (ledPin, !digitalRead (ledPin)); // LED Toggle
•}
•void loop() {
• // Mettre ici le programme principal.
•} D.Naceur
44
Electronique des Systèmes Embarqués
La PWM (Pulse Width Modulation )
Jusqu’à présent, nous avons vu l’émission de signaux numériques par
le biais des broches numériques et de digitalWrite(...) et
l’allumage et l’extinction de LED. Ces signaux numériques ont soit
une valeur égale à LOW, c’est à dire 0V, soit une valeur égale à HIGH,
ce qui correspond à la tension d’alimentation de l’Arduino, VDD, soit
5V pour les Arduino à base de micro-contrôleurs AVR ou bien 3,3V
pour les Arduino à base de micro-contrôleurs ARM.
Mais les sorties numériques ne nous permettent pas, par exemple,
de régler la luminosité de la LED, ou de faire varier la vitesse de
rotation d’un moteur. Pour pouvoir faire cela, il serait nécessaire de
pouvoir disposer de sorties permettant des tensions intermédiaires
entre LOW et HIGH.
Mais ceci n’existe pas sur les Arduino à base d’AVR. L’alternative est
d’utiliser une PWM, pour Pulse Width Modulation, ou MLI pour
Modulation de largeur d’impulsion.
D.Naceur
45
Electronique des Systèmes Embarqués
La PWM permet d’avoir un pseudo signal analogique pouvant prendre 256
valeurs (0 à 255) à partir de certaines sorties digitales.
En effet, pour générer une tension variable ou pseudo analogique en sortie
d'une broche digitale de l'Arduino, il va falloir changer très rapidement l'état
de la sortie. Le fait de passer d'un état LOW à HIGH très vite, cela va engendrer
la variation de la valeur moyenne de la tension.
Le signal est modulé avec une fréquence fixe (490 Hz sur la broche digitale 9
de l’Arduino Uno par exemple) . La PWM est caractérisé par son rapport
cyclique, qui correspond au pourcentage du temps pendant lequel le signal est
à 1 par rapport au temps pendant lequel le signal est à 0.
D.Naceur
47
Electronique des Systèmes Embarqués
Modulation de la largeur d'impulsion manuelle
Prenons par exemple une période de 10ms, soit une fréquence de 100Hz. Si la LED est
allumée pendant 5ms et éteinte pendant 5ms, comme sur la figure ci-dessous, l’impression
sera une luminosité de 50% de la luminosité maximum.
PMW à 50%
La fréquence est de 100Hz, le rapport cyclique de 50%
D.Naceur
49
Electronique des Systèmes Embarqués
Si la LED est allumée pendant 1ms et éteinte pendant 9ms, l’impression sera une luminosité de
10% comme sur la figure ci-dessous.
PWM à 10%
La fréquence est de 100Hz et le rapport cyclique de 10%.
Le pourcentage de temps passé à l’état HIGH sur la période du signal est appelé le rapport
cyclique. Il varie donc de 0%, le signal est tout le temps LOW, à 100%, le signal est tout le
temps HIGH.
D.Naceur
50
Electronique des Systèmes Embarqués
Les capacités PWM des Arduino
Les micro-contrôleurs proposent donc des dispositifs permettant de
disposer de PWM autonomes où le signal voulu est engendré
indépendamment de l’exécution du programme. Toutes les broches ne
sont pas utilisables. Sur l’Arduino Uno, les broches concernées portent le
symbole ’~’. Sur le Uno et les Arduino à base d’ATMega 328, 6 broches
sont disponibles, sur le Mega, 15 broches sont disponibles.
La fréquence de la PWM est prédéterminée sur l’Arduino. Il est possible
de la changer comme nous le verrons plus loin mais ce n’est pas une
possibilité accessible très simplement. La fréquence n’est pas la même
selon les broches. Sur le Uno, la fréquence est de 490Hz sur les
broches 3, 9, 10 et 11
et de 980Hz sur les Modèle d’Arduino Broches PWM
broches 5 et 6. Uno, Pro Mini, Nano 3, 5, 6, 9, 10 et 11
Mega 2 à 13, 44 à 46
Leonardo 3, 5, 6, 9, 10, 11 et 13
Due 2 à 13
Zero 2 à 13
D.Naceur
Electronique des Systèmes Embarqués 51
Mise en œuvre
Nous allons mettre en œuvre la PWM avec une simple LED. La
broche 3 est choisie car elle dispose de la fonction PWM.
D.Naceur
52
Electronique des Systèmes Embarqués
En ce qui concerne la programmation, la fonction permettant
de fixer le rapport cyclique de la PWM est la
fonction analogWrite(...).
Le premier argument de analogWrite(...) est la broche
concernée et le second argument le rapport cyclique. Le
rapport cyclique n’est pas donné de 0 à 100 mais de 0 à 255.
Il faut donc faire une règle de 3 pour calculer la valeur à
appliquer pour le rapport cyclique voulu. Par exemple, la
valeur à appliquer pour un rapport cyclique de 75% sera égal
à 0,75 x 255 = 191.
•analogWrite(3, 191); // éclaire notre DEL
à 75%
D.Naceur
53
Electronique des Systèmes Embarqués
La figure ci-dessous montre différents réglages de PWM.
D.Naceur
55
Electronique des Systèmes Embarqués
.Le temps de cycle
étant à 1000ms, le délai entre chaque
augmentation est donc de 1000 / 255 = 3,922 ms ≈ 4ms.
Remarque:
Il n’est pas nécessaire de programmer la broche en sortie pour
son utilisation en tant que sortie PWM. Cette programmation
s’effectue automatiquement lors du premier analogWrite().
Malgré tout il faut que la fonction setup() soit présente
même si elle est vide.
D.Naceur
56
Electronique des Systèmes Embarqués
Solution:
D.Naceur
57
Electronique des Systèmes Embarqués
Les Autres Modes de fonctionnement des timers
La génération des PWM
D.Naceur
58
Electronique des Systèmes Embarqués
PWM et broches de sortie
Le module Arduino Uno est capable de générer de la PWM
sur 6 broches de sorties grâce à la fonction analogWrite.
D’une manière transparente pour l’utilisateur, cette fonction
utilise les timers du microcontrôleur pour générer sur les
sorties, un signal carré de fréquence fixe mais de largeur
variable pour l’impulsion à l’état haut. Le tableau suivant
indique quel timer est utilisé pour générer la PWM et sur
quelles sorties du module Uno elle est générée.
Timers Sortie PWM Sortie Arduino Broche ATMEGA Nom de la broche
Timer0 OC0A 6 12 PD6
Timer0 OC0B 5 11 PD5
Timer1 OC1A 9 15 PB1
Timer1 OC1B 10 16 PB2
Timer2 OC2A 11 17 PB3
Timer2 OC2B 3 5 PD3
D.Naceur
59
Electronique des Systèmes Embarqués
60
D.Naceur
61
Electronique des Systèmes Embarqués
Brochage du microcontrôleur ATmega328P
62
Génération de la PWM
Deux modes de fonctionnement des timers peuvent être utilisés pour générer de la
PWM :
•Le mode « Fast PWM Mode »
•Le mode « Phase Correct PWM Mode »
Le mode Fast PWM Mode (rapide), permet d’obtenir une PWM ayant une fréquence
plus élevée que le Phase Correct PWM Mode (pratiquement un facteur deux), mais
en contrepartie, une résolution du signal moins bonne. En effet, le mode Fast est
basé sur une opération à simple pente, ce qui signifie que le timer/counter ne fait
que s’incrémenter pour aller chercher la valeur de comparaison OCRnx. Lorsqu’il y a
égalité, un signal est envoyé au bloc Waveform Generation qui va alors générer le
signal PWM désiré. Le mode Phase Correct est basé sur une opération à double
pente, ce qui signifie que le timer/counter s’incrémente de la valeur BOTTOM à la
valeur TOP puis se décrémente de TOP à BOTTOM. Ces deux opérations prennent
plus de temps, ce qui donne une période plus longue donc une fréquence moins
élevée.
D.Naceur
63
Electronique des Systèmes Embarqués
Fast PWM Mode
On est dans ce mode si les 3 bits WGM2 de 0 à 2 sont égaux à la valeur 3 ou 7 (on écrit
alors WGM22:0 = 3 ou 7. Ce mode est un mode à simple pente, ce qui signifie que le
timer/counter ne fait que s’incrémenter entre la valeur BOTTOM jusqu’à la valeur TOP,
puis redémarre depuis BOTTOM, etc.
BOTTOM est égal à 00 et TOP est égal à FF (ou 255) si WGM22:0 = 3 ou OCR2A
si WGM22:0 = 7.
D.Naceur
64
Electronique des Systèmes Embarqués
L’unité de comparaison génère alors la forme d’onde du signal PWM
sur la broche OC2x. Ce signal PWM peut être inversé. Pour que le
signal PWM soit non inversé, il faut que les 2 bits COM2x1:0 soient
égaux à la valeur 2 (COMnx signifie Compare Match Output « x » Mode
du timer « n »). Dans ce cas, la forme d’onde du signal PWM est
générée automatiquement en mettant à 0 le registre OC2x lorsque le
timer/counter TCNT2 atteint la valeur OCR2x, et en le positionnant à 1
le registre OC2x lorsque le timer/counter TCNT2passe de la valeur TOP
à BOTTOM. Dans la figure, le rapport cyclique de la PWM est changé
plusieurs fois par la mise à jour du registre OCR2x.
D.Naceur
65
Electronique des Systèmes Embarqués
Diagramme temporel du Fast PWM Mode 66
D.Naceur
67
Electronique des Systèmes Embarqués
Plus la valeur dans le registre de comparaison de sortie
est élevée, plus le rapport cyclique est élevé.
D.Naceur
68
Electronique des Systèmes Embarqués
Mode PWM à correction de phase (Phase Correct PWM)
On est dans ce mode si les 3 bits WGM22:0 = 1 ou 5 ; ce mode produit une forme
d’onde de PWM à haute résolution, basée sur un mode opératoire à double pente. Le
timer/counterTCNT2 compte de façon répétitive depuis BOTTOM jusqu’à TOP puis
redescend à BOTTOM. Encore une fois, BOTTOM est égal à 00 et TOP est égal à FF (ou
255) si WGM22:0 = 1 ou OCR2A si WGM22:0 = 5.
Le timer/counter est donc incrémenté depuis BOTTOM jusqu’à ce qu’il atteigne la
valeur TOP, puis la direction de comptage est inversée et le timer/counter est
décrémenté de TOP jusqu’à BOTTOM. La valeur de TCNT2 est donc égale à TOP
pendant un cycle d’horloge.
L’unité de comparaison génère alors la forme d’onde du signal PWM sur la broche
OC2x. Ce signal PWM peut également être inversé, comme nous le verrons plus loin.
Pour que le signal PWM soit non inversé, il faut que les 2 bits COM2x1:0 soient égaux à
la valeur 2. Dans ce cas, la forme d’onde du signal PWM est donc générée en mettant à
0 le registre OC2x lorsque le timer/counter TCNT2 atteint la valeur OCR2x quand il
s’incrémente, et en le positionnant à 1 le registre OC2x lorsque le
timer/counter TCNT2 atteint la valeur de OCR2x quand il se décrémente. C’est ce que
montre la figure ci-après ; la petite marque horizontale sur les pentes du timer
représente le moment où le timer/counter TCNT2 est égal à la valeur du
registre OCR2x. Dans la figure, le rapport cyclique de la PWM est changé plusieurs fois
par la mise à jour du registre OCR2x. 69
Diagramme temporel du Phase Correct PWM Mode 70
D.Naceur
71
Electronique des Systèmes Embarqués
Si TOP vaut 255, le timer/counter TCNT2 compte de 0 à 255
puis décompte jusqu’à 0 ; la période pour faire cela vaut donc
510 cycles d’horloge (2 fois 255). Si Fclk est la fréquence
d’horloge et N le facteur de division du prescaler, la fréquence
du signal PWM obtenu est donc :
Cette fréquence est donc à peu près deux fois moins élevée
que dans le mode Fast.
D.Naceur
72
Electronique des Systèmes Embarqués
Le PWM rapide et le PWM à phase correcte ont un mode supplémentaire qui
permet de contrôler la fréquence de sortie. Dans ce mode, le timer compte de 0 à
OCRA (la valeur du registre de comparaison de sortie A), plutôt que de 0 à 255.
Cela donne beaucoup plus de contrôle sur la fréquence de sortie que les modes
précédents. (Pour encore plus de contrôle de fréquence, on utilise le timer 16 bits)
Notez que dans ce mode, seule la sortie B peut être utilisée pour PWM ; OCRA ne
peut pas être utilisé à la fois comme valeur supérieure et comme valeur de
comparaison PWM. Cependant, il existe un mode spécial "Toggle OCnA on
Compare Match" qui basculera la sortie A à la fin de chaque cycle, générant un
rapport cyclique fixe de 50% et une demi-fréquence dans ce cas
D.Naceur
73
Electronique des Systèmes Embarqués
D.Naceur
74
Electronique des Systèmes Embarqués
Valeurs extrêmes du registre OCR2A
Dans les deux modes, les valeurs extrêmes du
registre OCR2A représentent des cas particuliers pour
générer le signal PWM. Dans le mode Fast, si OCR2A est égal
à BOTTOM, le signal de sortie sera un pic étroit pour chaque
cycle d’horloge MAX + 1 du timer et si OCR2A est égal à
MAX, la sortie sera constamment à l’état haut ou bas selon
le mode de sortie PWM (inversé ou non inversé) réglé par
les 2 bits COM2A1:0 . Dans le mode Phase Correct,
si OCR2A est égal à BOTTOM, la sortie sera constamment à
l’état bas et si OCR2A est égal à MAX, la sortie sera
constamment à l’état haut, ceci pour un mode PWM non
inversé ; pour un mode PWM inversé, la sortie aura les
valeurs logiques opposées. On rappelle que MAX vaut FF (ou
255). D.Naceur
Electronique des Systèmes Embarqués
75
Exemples:
Nous allons voir comment fabriquer un signal PWM de rapport 50%
dans chacun des deux modes, avec le timer2. Peu importe la fréquence,
il suffit de régler le prescaler en fonction de ce qu’on veut (bits CS22:0 à
régler).
• On veut récupérer un signal PWM non inversé sur la broche OC2B (la
broche 5 du microcontrôleur ATmega328P ou encore la sortie 3 du
module Arduino Uno). Les 2 bits (du registre de
contrôle TCCR2A) COM2B1:0 doivent être égaux à la valeur 2 pour que
le signal soit non inversé.
D.Naceur
77
Electronique des Systèmes Embarqués
Le programme suivant est celui de ce premier exemple avec N = 1 : d’après la formule
donnée plus haut, la fréquence est de 62,500 kHz.
•/* ----------------------------------------------
•Exemple 1 de l'article Timers IV
•N = 1 pour le prescaler
•La PWM de frequence 62500 Hz
•est sur la sortie 3 du module UNO
•-------------------------------------------------
•*/
•
•void setup(){
• pinMode (3, OUTPUT); //DDRD |= 0x08 ou //DDRD |= 1<<3
• TCCR2A = 0b00100011;
• TCCR2B = 0b00000001;
• OCR2B = 128;
•}
•
•void loop(){
•}
D.Naceur
78
Electronique des Systèmes Embarqués
Cas du Phase Correct PWM Mode,
D.Naceur
80
Electronique des Systèmes Embarqués
Le programme suivant est celui de ce deuxième exemple avec N = 8 : d’après la
formule donnée plus haut, la fréquence est de 3,9216 kHz.
•/* ---------------------------------------------
•Exemple 2 de l'article Timers IV
•N = 8 pour le prescaler
•La PWM de frequence 3921,6 Hz
•est sur la sortie 11 du module UNO
•------------------------------------------------
•*/
•
•void setup(){
• pinMode (11, OUTPUT); //DDRB |= 0x08 ou //DDRB |= 1<<3
• TCCR2A = 0b10000001;
• TCCR2B = 0b00000010;
• OCR2A = 128;
•}
•
•void loop(){ D.Naceur
81
•} Electronique des Systèmes Embarqués
Il est évident que ces deux exemples ne peuvent pas être obtenus en même
temps puisqu’un timer ne peut travailler que dans un seul mode à la fois.
Conclusion
Nous n’avons fait que survoler la génération d’un signal PWM par les timers du
microcontrôleur ATmega328P. Encore une fois, le recours à la documentation du
constructeur est nécessaire pour bien programmer les timers dans les modes
PWM, mais cette programmation au cœur même du microcontrôleur permet de
compléter la fonction analogWrite du langage Arduino.
En effet, l’IDE d’Arduino configure les timers avant même d’exécuter la fonction
setup. Le timer2 et le timer1 sont initialisés en mode Phase Correct PWM avec un
prescaler où N vaut 64, ce qui donne une fréquence de 490 Hz.
La Timer 0 est initialisée sur Fast PWM.
Quand la fonction analogWrite est appelée, elle agit sur les bits
COM2A ou COM2B pour connecter les sorties et obtenir la PWM dessus. Vous
savez maintenant comment agir sur les registres de contrôle pour changer la
fréquence de vos signaux PWM.
D.Naceur
82
Electronique des Systèmes Embarqués
Exemple de programmation du timer 0 : procédure à suivre
D.Naceur
83
Electronique des Systèmes Embarqués
Registre de contrôle A du timer 0 (suite) : TCCR0A
•Les 2 bits de poids forts - COM0A1 et COM0A0 - sont utilisés pour émettre un signal sur la
broche de sortie associée à la comparaison A - OC0A - dont la forme évolue lorsque le compteur
prend la valeur du registre de comparaison A
•En mode normal ou CTC, ces 2 bits peuvent être réglés ainsi :
https://www.locoduino.org/
https://www-lisic.univ-littoral.fr/~hebert/microcontroleur/atmel/
https://perso-laris.univ-angers.fr/~delanoue/polytech/microcontroleur/ArduinoCottenceau19-20.pdf
https://passionelectronique.fr/arduino/
https://docs.arduino.cc/tutorials/generic/secrets-of-arduino-pwm/