0% ont trouvé ce document utile (0 vote)
126 vues85 pages

Cours 3 Timers

Transféré par

meriem.harreche
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
126 vues85 pages

Cours 3 Timers

Transféré par

meriem.harreche
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Microcontrôleurs

Timers de l’ATMEGA 328

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 :

Ils sont soumis à des contraintes de taille (intégration), de consommation


électrique (autonomie) et de coûts importants (grande série) ;
Ils sont en général dédiés à une tâche bien précise. La taille des programmes et
la quantité de mémoire (vive et morte), dont ils disposent, sont modestes (face à
un micro-ordinateur) ;
Ils doivent communiquer avec des dispositifs d'entrées-sorties (IO) : boutons,
relais, résistances variables, optocoupleurs, moteurs électriques, LED, circuits
intégrés logiques, etc. ;

D.Naceur
2
Electronique des Systèmes Embarqués
D’où la solution: Le microcontrôleur

Un microcontrôleur intègre sur un unique composant :


• un processeur (CPU), avec une largeur du chemin de données allant de 4 bits pour les
modèles les plus basiques à 32 ou 64 bits pour les modèles les plus évolués ;
• de la mémoire vive (RAM) pour stocker les données et variables ;
• de la mémoire morte (ROM) pour stocker le programme. Différentes technologies
peuvent être employées : EPROM, EEPROM, mémoire flash (la plus récente) ;
• souvent un oscillateur pour le cadencement. Il peut être réalisé avec un quartz,
un circuit RC ou encore une PLL ;
• des périphériques, capables d'effectuer des tâches spécifiques. On peut mentionner
entre autres :
 les convertisseurs analogiques-numériques (CAN) (donnent un nombre binaire à
partir d'une tension électrique),
 les convertisseurs numériques-analogiques (CNA) (effectuent l'opération inverse),
 les générateurs de signaux à modulation de largeur d'impulsion (MLI, ou en anglais,
PWM pour Pulse Width Modulation),
 les timers/compteurs (compteurs d'impulsions d'horloge interne ou d'événements
externes),
 les chiens de garde (watchdog),
 les comparateurs (comparent deux tensions électriques),
 les contrôleurs de bus de communication (UART, I²C, SSP, CAN, FlexRay,
USB, Ethernet, etc.). D.Naceur
3
Electronique des Systèmes Embarqués
• Le fonctionnement des périphériques peut être paramétré et commandé par
le programme et/ou les entrées-sorties. Les périphériques peuvent générer une
interruption qui, contraint le processeur à quitter le programme en cours pour
effectuer une routine de traitement de l’interruption, lorsque l’événement qui la
déclenche survient.

• Les microcontrôleurs peuvent généralement se placer dans un état


de sommeil, dans lequel ils présentent une très faible consommation électrique.
Un signal envoyé par l'un de leurs périphériques (timer, broche d'entrée-sortie,
watchdog, ...) permet de les faire sortir de cet état de sommeil.

• Certains microcontrôleurs ont un nombre très restreint de broches, si bien


qu'une broche donnée peut correspondre à plusieurs périphériques internes. La
fonction choisie doit alors être sélectionnée par logiciel.
Le choix des périphériques à intégrer dans un microcontrôleur est délicat. Les
fabricants doivent réaliser un compromis entre des besoins contradictoires :
utiliser des fréquences élevées, réduire la taille du circuit, apporter des
fonctionnalités nombreuses, élaborer une architecture flexible, assurer des
coûts modérés, etc.
D.Naceur
4
Electronique des Systèmes Embarqués
Les Timers

Un timer est un registre qui s’incrémente (ou se


décrémente) chaque fois qu’il reçoit une impulsion
d’un signal d’horloge.
Un timer est un compteur capable de compter le
temps qui s’écoule, et de capturer des évènements
qui arrivent, c’est un compteur de temps ou
d'évènements.

C'est un périphérique matériel destiné à compter :

• soit des évènements extérieurs, potentiellement non-périodiques : c'est


sa fonction de compteur ;
• soit des évènements internes périodiques (tops d'horloge) : c'est sa
fonction de temporisateur, de mesure le temps.
D.Naceur
5
Electronique des Systèmes Embarqués
•Tant qu'il est « activé », un timer compte. C'est sa fonction : il s'incrémente
chaque fois qu'il détecte un nouvel évènement.
En cas de débordement, il reprend à 0 (sauf mode de fonctionnement
particulier)

•Un timer sert généralement à :


• mesurer des durées
• déclencher périodiquement des routines d'interruptions
• générer des signaux MLI
.

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} ;

•un registre de comptage : c'est lui qui stocke la valeur de comptage ;


•des unités de comparaison, chacune munie d'un registre de comparaison : ces
registres contiennent une valeur destinée à être comparée à celle du compteur ; dans
le but de changer l'état d'une broche de sortie de l'unité de comparaison, ou de
déclencher une interruption ;
•des registres de contrôle : pour configurer son mode de fonctionnement.
D.Naceur
7
Electronique des Systèmes Embarqués
D.Naceur
8
Electronique des Systèmes Embarqués
TCNT Timer/Counter
(Register),
TCCR Timer/Counter
Control Register,
OCR Output Compare
Register,
ICR Input Capture
Register,
TIMSK Timer/Counter
Interrupt Mask
Register
TIFR Timer/Counter
Interrupt Flag
Register

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

Ce débordement entraîne la mise à 1 d’un bit dans un


registre de contrôle associé au timer. Ce bit est appelé
un flag et indique que le timer vient de compter jusqu’à 256

D.Naceur
10
Electronique des Systèmes Embarqués
Au niveau des diviseurs de fréquences possibles sur l’ATmega328P, on retrouve :

Un prescaler (diviseur de fréquence « général »), permettant de diviser la fréquence du


microcontrôleur par 1, 2, 4, 8, 16, 32, 64, 128, ou 256
Et 3 prédiviseurs « secondaires » (un pour chaque timer), permettant de rediviser la
fréquence issue du prescaler par :
1, 8, 64, 256, ou 1024 s’il s’agit du timer0
1, 8, 64, 256, ou 1024 s’il s’agit du timer1
1, 8, 32, 64, 128, 256, ou 1024 s’il s’agit du timer2

La fréquence rythmant l’avancée de chaque timer correspondra donc au final à la


fréquence du microcontrôleur, divisée par le rapport de division du prescaler, puis
encore divisée par le rapport de division du prédiviseur propre au timer en
question. Ainsi, par exemple :
– si la fréquence du microcontrôleur est de 16 MHz
– si le prescaler est réglé sur 4
– et si le prédiviseur du timer est réglé sur 32
– Alors la fréquence arrivant au timer sera de 16MHz / 4 / 32, soit 125 kHz.
Attention: gardez toujours à l’esprit que TOUCHER AU PRESCALER OU au
PRÉDIVISEUR de fréquence des timer arduino peut ALTÉRER LE FONCTIONNEMENT
DU RESTE DE VOTRE PROGRAMME ! Car ces timers peuvent servir à bien des
fonctions, en arrière plan ! D.Naceur
11
Electronique des Systèmes Embarqués
D.Naceur
12
Electronique des Systèmes Embarqués
il est possible de faire fonctionner les timer à « pleine vitesse », tout comme à vitesse
réduite. Pour ce faire, on peut jouer sur le prescaler, et le prédiviseur propre au timer
visé. Au niveau du prescaler, on peut diviser la fréquence du microcontrôleur par :

Division par 1 (comme si le prescaler était désactivé)


Division par 2
Division par 4
Division par 8
Division par 16
Division par 32
Division par 64
Division par 128
Division par 256 (réduction maximale de la fréquence d’horloge, à ce niveau)

Ainsi, par exemple : si le quartz de votre ATmega328P a une fréquence de 16 MHz,


alors les fréquences possibles en sortie du prescaler seront : 16 MHz, 8 MHz, 4 MHz, 2
MHz, 1 MHz, 500 kHz, 250 kHz, 125 kHz, ou 62500 Hz.

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.

Très important : pour éviter tout changement involontaire de rapport de division de


fréquence d’horloge, le fabricant impose une procédure en 2 étapes pour changer ce rapport
de fréquence, au niveau du prescaler. Il faudra donc :
– tout d’abord mettre à 1 le bit CLKPCE et tous les autres bits à 0 (en envoyant par exemple
le nombre 0b10000000 dans le registre CLKPR)
– et ensuite, dans un délai maximal de 4 cycles d’horloge, de mettre à 0 le bit CLKPCE, tout
en spécifiant dans les 4 derniers bits le rapport de division de fréquence souhaitée (pour
cela, il suffira donc d’envoyer le nombre 0b0000xxxx dans le registre CLKPR, en remplaçant
xxxx par des valeurs 1 ou 0, selon le rapport de division que vous voulez, comme visible dans
le tableau ci-dessus)

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 :

CLKPR = 0b1000 0000; // On indique au microcontrôleur qu’on souhaite changer de rapport


de fréquence
CLKPR = 0b0000 0101; // Puis on indique le rapport voulu (ici « 0101 » sur les 4 derniers
bits, donc division par 32)

Remarque : il faut « presque impérativement » que ces deux lignes de code


se suivent. Car une fois que vous aurez spécifié au microcontrôleur votre
souhait de changement de rapport de fréquence (1ère ligne), il faudra lui
indiquer le nouveau rapport dans un délai inférieur ou égal à 4 cycles
d’horloge (2ème ligne).

Autre remarque importante : modifier le rapport de division du prescaler (par


défaut à 1) impactera directement tout un tas de systèmes, internes au
microcontrôleur. D.Naceur
16
Electronique des Systèmes Embarqués
Les Prédiviseurs (diviseurs de fréquences secondaires, propres à chaque
timer)

À 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.

Au niveau de l’ATmega328P, on retrouve donc 3 prédiviseurs, puisqu’il y a 3


timers. Mais attention, car tous ces prédiviseurs ne sont pas identiques. En
effet, leur rapport de division n’est pas forcément le même, suivant s’il s’agit du
timer0, du timer1, ou timer2.

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.

Ralentir ou accélérer le timer

Pour ralentir un timer , il suffit d’utiliser le prédiviseur pour diviser la fréquence du


signal d’horloge. Pour cela,
 Il suffit de positionner certains bits du registreTCCR2B (CS22 CS21 CS20)
 Le compteur comptera de 0 à 255 puis passera en débordement, le
flagTOV2 (Timer/Counter 2 Overflow Flag) se positionne à 1. Il s’agit là du bit 0 du
registre TIFR2. Chaque fois que le bit 0 du registre TIFR2 passe à 1, cela signifie que
notre timer a compté un certain laps de temps (connu) ; il suffit alors de repositionner le
flag TOV2 à 0 et d’incrémenter un compteur (une variable) pour continuer ce processus.

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.

Initialisation des registres de contrôle


Mode normal : WGM20 , WGM21 et WGM22 mis à 0 par une instruction adéquate
(bitClear dans le langage Arduino).
Prédiviseur à 256: CS22 CS21 CS20 mis à 1 1 0 ; il suffit d’écrire la valeur binaire
0b00000110 dans le registre TCCR2B.

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.

Prédivision selon les bits 0 à 2 du registre TCCR2B


Débordement: une bascule est positionnée à 1 : flag TOV2 (bit 0 du registre TIFR2
Autorisation de l’interruption par le timer: il faut que le flag TOIE2 (Timer/Counter2 Overflow Interrupt
Enable) qui est le bit 0 du registre TIMSK2 (Timer/Counter2 Interrupt Mask Register), soit à 1 ; c’est ce qu’on
appelle une autorisation d’interruption locale.

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

2 External Interrupt Request 0 INT0_vect

3 External Interrupt Request 1 INT1_vect

4 Pin Change Interrupt Request 0 PCINT0_vect

5 Pin Change Interrupt Request 1 PCINT1_vect

6 Pin Change Interrupt Request 2 PCINT2_vect

7 Watchdog Time-out Interrupt WDT_vect

8 Timer/Counter2 Compare Match A TIMER2_COMPA_vect

9 Timer/Counter2 Compare Match B TIMER2_COMPB_vect

10 Timer/Counter2 Overflow TIMER2_OVF_vect

11 Timer/Counter1 Capture Event TIMER1_CAPT_vect


D.Naceur
30
Electronique des Systèmes Embarqués
L’exemple de Programme par interruption

Nous allons donc modifier le programme vu


précédemment pour que l’inversion de la LED se fasse par
une interruption provenant du timer 2. Les autres
conditions restent identiques : initialisation, réglage du
prédiviseur. La boucle principale peut accueillir le
programme de l’utilisateur ; à titre d’exemple, un
programme très classique faisant clignoter une autre LED
(branchée sur la broche 5 d’Arduino) en utilisant la
fonction delay(). Bien que cette fonction soit bloquante,
cela n’empêche pas la LED reliée à la broche 13 de
clignoter.
D.Naceur
31
Electronique des Systèmes Embarqués
•// Clignotement d'une LED (mot anglais pour DEL) à 1 Hz par une
•// interruption en provenance du timer 2,
•// 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
• bitClear (TCCR2A, WGM20); // WGM20 = 0
• bitClear (TCCR2A, WGM21); // WGM21 = 0
• TCCR2B = 0b00000110; // Clock / 256 soit 16 micro-s et WGM22 = 0
• TIMSK2 = 0b00000001; // Interruption locale autorisée par TOIE2
• sei(); // Active l'interruption globale
•}

•byte varCompteur = 0; // La variable compteur

•// Routine d'interruption
•ISR(TIMER2_OVF_vect) {
• TCNT2 = 256 - 250; // 250 x 16 µS = 4 ms
• 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 32
•}
Modes de fonctionnement du TIMER
Le Timer possède plusieurs modes de fonctionnement, nous allons introduire Le mode CTC
(Clear Timer on Compare Match Mode)

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.

Rôle d’un registre OCR


On peut charger un nombre dans le registre OCR2A ; lorsque le timer 2, en comptant,
devient égal à OCR2A , cela provoque la mise à 1 d’un flag appelé OCF2A , qui est le bit 1
du registre TIFR2 (Timer/Counter 2 Interrupt Flag Register) et si on a autorisé les
interruptions, ce flag va commander une interruption qui sera traitée par la routine
d’interruption ISR(TIMER2_COMPA_vect).

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

On se propose d’utiliser maintenant le timer 1, qui est sur 16


bits, pour faire clignoter la LED à la fréquence de 1 Hertz.
Comme le cycle du timer 1 est plus long, il n’est plus
nécessaire de faire appel à la variable varCompteur qui
comptait jusqu’à 125.
•Le Timer tourne à la fréquence de 16 MHz / 256 = 62500 Hz,
soit une période de 16 µs.
•Pour faire clignoter notre LED à 1 Hz, il faut inverser cette
LED toutes les 500 ms
•Le timer compte 500 ms / 16 µs = 500000 / 16 = 31250 fois.

C’est donc cette valeur qu’on chargera dans le


registre OCR1A D.Naceur
Electronique des Systèmes Embarqués
40
D.Naceur
41
Electronique des Systèmes Embarqués
D.Naceur
42
Electronique des Systèmes Embarqués
TCCR1A = 0b00000000

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.

La PWM peut être utilisée pour:

contrôler la luminosité d’une LED


Fournir une sortie analogique
Générer des signaux audio.
Fournir un contrôle de vitesse variable pour les moteurs.
Générer un signal modulé, par exemple pour piloter une LED infrarouge pour
une télécommande.
D.Naceur
46
Electronique des Systèmes Embarqués
Modulation simple de la largeur d'impulsion avec analogWrite

Le langage de programmation d'Arduino rend donc la PWM facile à utiliser; il


suffit simplement d’écrire analogWrite(pin, dutyCycle), où dutyCycle est une
valeur comprise entre 0 et 255, et pin est l'une des broches PWM (3, 5, 6, 9, 10
ou 11). La fonction analogWrite fournit une interface simple à la generation de
la PWM, mais ne fournit aucun contrôle sur la fréquence. (Notez que malgré le
nom de la fonction, la sortie est un signal numérique.)

On peut utiliser uniquement analogWrite pour la génération de la PWM , mais il


existe d'autres options qui offrent plus de flexibilité.

En manipulant directement les registres de temporisation, on peut obtenir plus


de contrôle que la fonction analogWrite n'en fournit.

D.Naceur
47
Electronique des Systèmes Embarqués
Modulation de la largeur d'impulsion manuelle

On peut toutefois implémenter "manuellement" PWM sur n'importe quelle


broche en activant et désactivant la broche à plusieurs reprises pendant les
durées souhaitées. par exemple:
void loop()
{
digitalWrite(13, HIGH);
delayMicroseconds(100); // Approximativement 10% duty cycle @ 1KHz digitalWrite(13, LOW);
delayMicroseconds(900);
}

Cette technique a l'avantage de pouvoir utiliser n'importe quelle broche de sortie


numérique. De plus, on a un contrôle sur le cycle et la fréquence. Un
inconvénient majeur est que toute interruption affectera la synchronisation, ce
qui peut provoquer un retard considérable à moins qu’on ne désactive toutes les
interruptions.
Un deuxième inconvénient est qu’on ne peut pas laisser la sortie s'exécuter
pendant que le processeur fait autre chose. Enfin, il est difficile de déterminer les
constantes appropriées pour un rapport cyclique et une fréquence particulière, à
moins de compter soigneusement les cycles ou d'ajuster les valeurs tout en
regardant un oscilloscope.
D.Naceur 48
Electronique des Systèmes Embarqués
Le principe de la PWM sera illustré à travers la persistance rétinienne sur une LED qui sera
alternativement allumée et éteinte.

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.

Rapport cyclique et PWM


D.Naceur
54
Electronique des Systèmes Embarqués
Application:

Ecrire un programme qui augmente progressivement, de 1 en 1, la


luminosité de la LED de 0, extinction totale, à 255, luminosité maximum,
puis recommence à 0. On choisira le timer2 pour générer la PWM et on
fixera le temps de ce cycle à 1000ms

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.

En utilisant un byte pour stocker la valeur de la luminosité,


nous pouvons profiter du débordement qui se produit lorsque,
étant à 255, l’ajout de 1 fait repasser la valeur de la luminosité à
0.

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:

•const byte pinDEL = 3;


•byte luminosite = 0;

•void setup()
•{
•}

•void loop()
•{
• analogWrite(pinDEL, luminosite);
• luminosite++;
• delay(4);
•}

D.Naceur
57
Electronique des Systèmes Embarqués
Les Autres Modes de fonctionnement des timers
La génération des PWM

•Nous avons vu le mode normal et le mode CTC


•Nous allons introduire deux autres modes de
fonctionnement qui servent, entre autres, à fabriquer la
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

Architecture du bloc timer à l’intérieur du microcontrôleur ATmega328P


Le signal d’horloge clkTn (en jaune) arrive à la logique de contrôle, en
provenance de l’extérieur (Tn) ou bien de l’horloge interne et du
prescaler. La logique de contrôle incrémente ou décrémente le
timer TCNTn (en vert) et celui-ci est comparé aux valeurs des
registres OCRnA et OCRnB (en bleu). Lorsqu’il y a égalité, un signal est
envoyé à un bloc appelé « Waveform Generation » (Génération de la
forme d’onde) (en rouge) et c’est ce bloc qui met en forme la PWM en
positionnant à 0 ou à 1 le registre des broches OCnA ou OCnB (en
violet). Bien entendu, ces broches doivent avoir été déclarées comme
des sorties auparavant.
Le timer0 génère donc de la PWM sur les broches OC0A et OC0B. La
figure (extraite de la datasheet de l’ATmega328P) montre que ces
broches (en rouge) sont les broches 12 et 11 du microcontrôleur (PD6
et PD5).

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é.

Si TOP vaut 255, le timer/counter TCNT2 compte de 0 à 255


puis au coup suivant qui devrait être 256, il se remet à 0
(overflow) ; une période représente 256 opérations de
comptage. Ces opérations de comptage se font à la fréquence
de l’horloge divisée par la valeur N du prescaler. La fréquence
du signal PWM obtenu est donc :

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

Dans le schéma suivant, le timer se réinitialise lorsqu'il correspond à OCRnA, ce


qui donne une fréquence de sortie plus rapide pour OCnB que dans les modes
précédents.

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).

Cas du Fast PWM Mode,


• on veut que notre timer/counter compte de 0 à 255 ; les 3 bits (des
registres de contrôle TCCR2A et TCCR2B) WGM22:0 doivent être égaux
à la valeur 3 (ce qui règle TOP = 255).

• 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é.

•Pour un rapport de 50%, on charge le registre OCR2B avec la valeur


D.Naceur 76
128. Electronique des Systèmes Embarqués
La figure suivante montre comment le timer2 évolue ; le registre OC2B est mis à 0
quand le timer2 est égal à OCR2B et mis à 1 quand le timer2 est remis à 0.

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,

• on veut que le timer2 compte de 0 à 255 et décompte de


255 à 0 ; les 3 bits (des registres de
contrôle TCCR2A et TCCR2B) WGM22:0 doivent être égaux à
la valeur 1 (ce qui règle TOP = 255).

• On veut récupérer un signal PWM non inversé sur la broche


OC2A (la broche 17 du microcontrôleur ATmega328P ou
encore la sortie 11 du module Arduino Uno). Les 2 bits (du
registre de contrôle TCCR2A) COM2A1:0 doivent être égaux à
la valeur 2 pour que le signal soit non inversé.

•Pour un rapport de 50%, on charge le registre OCR2A avec la


valeur 128. D.Naceur
79
Electronique des Systèmes Embarqués
La figure ci-après montre comment le timer2 évolue ; le registre OC2A est mis à 0
quand le timer2 devient égal à OCR2A en s’incrémentant et le registre OC2A est
mis à 1 quand le timer2 devient égal à OCR2A en se décrémentant.

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

1. Spécifier le mode de fonctionnement du timer (cf. TCCR0A, TCCR0B), parmi


ceux vus ici :
•mode normal
•mode remise à zéro sur comparaison (CTC)
2. Spécifier le mode temporisateur, avec la période d'interruption souhaitée :
1.choix du prédiviseur (cf. TCCR0B)
2.calcul de la valeur de comparaison, si mode CTC(cf. OCR0A )
3. Autoriser l'interruption souhaitée (cf. TIMSK0)
•soit celle de débordement, si mode normal
•soit celle de comparaison, si mode CTC
4. Reset du registre de comptage (TCNT0 = 0)
•si l'on souhaite un 1er cycle complet (sachant qu'après la 1ère
comparaison/débordement, le registre est forcément remis à zéro)

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 :

L'inversion (toggle) permet de générer le signal carré


84
Références:

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/

Vous aimerez peut-être aussi