Le TIMER/COMPTEUR






Le TIMER/COMPTEUR
Faisant suite au PRESCALER, le TIMER/COMPTEUR joue un rôle central.

Un TIMER/COMPTEUR fonctionne de deux façons soit :
• En TIMER lorsqu'il compte les tops de son horloge, 16 Mhz pour un arduino uno,
• En COMPTEUR  lorsqu'il compte les tops d'une autre source.

L'Atmega 328 qui équipe l'arduino uno possède 3 timers/compteurs :
• Le TC0 est un timer/compteur de 8 bits qui compte jusqu'à 256 (0 à 255),
• Le TC1 est un timer/compteur de 16 bits qui compte jusqu'à 65536 (0 à 65535),
• Le TC2 est un timer/compteur de 8 bits qui compte jusqu'à 256 (0 à 255).

Chaque timer/compteur : TC est équipée,
   • D'un prédiviseur associé au TC correspondant,
   • De deux registres indépendants de comparaison par TC, de taille identique au timer/compteur : TCn Contrôle Registre A et TCn Contrôle Registre B.
   •
D'une possibilité de faire fonctionner le compteur en mode Normal ou CTC (Clear-Timer-on Compare).

De 3 sources d'interruption indépendantes :
   • Interruption par dépassement du comptage d'un timer/compteur : OVERFLOW,
        •
Signalé par un Flag (drapeau) TCn IFR Overflow,
   • Interruption par égalité entre les valeurs contenues dans un ou les deux registres de comparaison A et B,
        • Signalé par un Flag (drapeau) TCn IFR A ou B.

D'un masque d'interruption, autorisant individuellement les interruptions :
   • Par Comparaison A,
   • Par Comparaison B,
   • Par Overflow.

D'une autorisation générale des interruptions.

Chaque partie permettant le déclenchement d'une interruption est contrôlée par des registres internes au microcontrôleur.

Comme vu sur la page
 le timer/compteur peut se représenter comme un escalier.

compteur 8 bits
                  
compteur 16 bits
Compteur 8 bits
                                                                                                                    
Compteur 16 bits

L'horloge d'un arduino uno est de 16 Mhz. Cela vaut dire qu'un top d'horloge survient tous les 62,5 ns (nanoseconde) :

A chaque top d'horloge on gravit une marche de l'escalier.

• Pour le timer/compteur 0 ou 2 : 62,5 ns * 256 = 16 µs. L'escalier est gravi en 16µs (62,5 Khz),
• Pour le timer/compteur 1 : 62,5 ns * 65536 = 4,096 ms. L'escalier est gravi en 4,096 ms (244 Hz).
 
duree compteur 8 bits
       
duree compteur 16 bits
                                                                           
Compteur 8 bits
                                                                                                                    
Compteur 16 bits

Ces temps de comptage sont très rapides et peuvent être ralenti grâce au PRESCALER qui est commun aux trois timers/compteurs de l'arduino uno.

Chaque timer/compteur possède un prédiviseur qui lui est propre et qui permet de diviser la fréquence du signal d'horloge venant du PRESCALER.

prescaler suivit d'un timer/compteur
Prescaler suivit d'un timer/compteur avec son prédiviseur
Le PRÉDIVISEUR des TIMERS
Chaque prédiviseur est contrôlé par un registre :
TCCR0B pour le TC0,
TCCR1B pour le TC1,
TCCR2B pour le TC2.

Les rapports de division possible de ces prédiviseurs sont différents suivant le timer/compteur utilisé. Il sont à multiplier par le prescaler commun aux trois timers/compteurs s'il a été utilisé.

Exemple :
• Prescaler commun réglé sur un rapport de division par 8,
• Prédiviseur d'un TCn réglé sur un rapport de division par 8,

Le TCn correspondant s'incrémentera tous les :
• Rapport de division total : 8 * 8 = 64,
• Le TCn s'incrémentera tous les 64 tops d'horloge soit :
    • 4µs, soit une fréquence de : 250 Khz.

Pour le TC0 on peut régler le prédiviseur pour obtenir un rapport de division égale à : 1, 8, 64, 256, 1024.

rapport de division du prescaler du tc0
Rapport de division du prescaler du TC0 

Pour le TC1 on peut régler le prédiviseur pour obtenir un rapport de division égale à : 1, 8, 64, 256, 1024.

rapport de division du prescaler du tc1
Rapport de division du prescaler du TC1 

Pour le TC2 on peut régler le prédiviseur pour obtenir un rapport de division égale à : 1, 8, 32, 64, 128, 256, 1024.

rapport de division du prescaler du tc2
Rapport de division du prescaler du TC2 
Le FONCTIONNEMENT des TIMERS/COMPTEURS
Les timers/compteurs peuvent être utilisés seuls ou en association avec d'autres registres.

Chaque timer/compteur possède un registre qui contient le nombre de top d'horloge qui arrive jusqu'à lui, et qui est fonction du prescaler et de son propre prédiviseur. Ces registres sont :
TCNT0 pour le TC0, composé d'un registre 8 bits,
TCNT1 pour le TC1, composé de deux registres 8 bits : TCNT1H et TCNT1L. Par souci de simplification nous ne parlerons que d'une manière globale pour TCNT1,
TCNT2 pour le TC2, composé d'un registre 8 bits.

prescaler et timer 0
       
prescaler et timer 1
        
prescaler et timer 2
                              
Prescaler et timer 0
                                                                             
Prescaler et timer 1
                                                                              
Prescaler et timer 2

Le comptage d'un timer dépend du réglage du prescaler (commun aux trois timers/compteurs) et du prédiviseur de chaque timer/compteur.

Configuration d'un timer/compteur
Un timer compteur peut s'utiliser en mode :
Normal ou,
CTC (Clear Timer on Compare).

Pour utiliser un timer/compteur en mode normal il faut le configurer.

Ce rôle est réalisé par des bytes contenus dans deux registres différents :

Ces bytes sont : WGMn2, WGMn1, WGMn0.
WGMn1 et WGMn0 sont contenus dans TCCRnA,
WGMn2 est contenu dans TCCRnB,
• Pour le timer/compteur 1, un byte supplémentaire WGM13, est contenu dans TCCR1B uniquement pour le timer/compteur 1.

n
, représentant le numéro du timer/compteur.

Ces bytes doivent être mis à 0 pour un fonctionnement du timer/compteur correspondant en mode normal.


wgmn1 et 0 dans registre tccrna
Position de WGMn1 et WGMn0 dans TCCRnA pour les 3 timers/compteurs
Ligne de commande :
TCCRnA = 0b00000000;
ou :
bitClear (TCCRnA, WGMn0);
bitClear (TCCRnA, WGMn1);
ou,
TCCRnA &=~ (1 << WGMn0);
TCCRnA &=~ (1 << WGMn1);


wgmn2 dans registre tccrnb
Position de WGMn2 dans TCCRnB pour le timer/compteur 0 et 2
Ligne de commande :
TCCRnB = 0b00000000;
ou,
bitClear (TCCRnB, WGMn2);
ou,
TCCRnB &=~ (1 << WGMn2);

Comme on l'a vu précédemment plusieurs bytes jouant des rôles différents peuvent se trouver dans le même registre d'un microcontrôleur.

Ainsi les bytes :
• CSn0, CSn1, CSn2 et WGMn2 se trouvent dans le registre TCCRnB,
• CSn0, CSn1, CSn2 et WGMn2 et WGM13 se trouvent dans le registre TCCR1B.

Il faut veiller lors de la manipulations des bytes de ce registre à ne modifier que ceux que l'on désire sans toucher aux autres.. 


position bytes registre tccrn
CS0, CS1, CS2 et WGMn2 dans le registre TCCRnB pour le timer/compteur 0 et 2
Ligne de commande :
TCCRnB = 0b00000000;
ou,
bitClear (TCCRnB, WGMn2);
ou,
TCCRnB &=~ (1 << WGMn2);

position bytes registre tccr1b
WGM13 et WGM12, CS12, CS11, CS10 dans le registre TCCR1B pour le timer/compteur 1

Particularité dans le timer/compteur, il existe un byte WGM13 en plus.

Notre schéma devient en incorporant la sélection du mode de fonctionnement du timer/compteur.

mode normal ou ctc
Mode normal ou CTC timer/compteur 0 et 2

Le FLAG des TIMERS/COMPTEURS
Nous avons vu que le timer/compteur incrémentait son registre TCNTn, au rythme de l'horloge et du réglage du prescaler ou du prédiviseur du timer/compteur considéré.

Lorsque le timer/compteur déborde, retour à zéro, cela déclenche un FLAG ou Drapeau.

Le timer/compteur possède un registre TIFRn, qui contient un byte appelé TOV qui est mis à 1 lorsque le timer/compteur déborde.

byte tov du registre tifrn
Byte TOV du registre TIFRn

En surveillant ce byte on peut utiliser le timer/compteur pour mesurer le temps qui passe.

Il suffit de surveiller le passage à 1 de TOV pour savoir que le timer/compteur a débordé.

flag tov du registre tifrn
Flag TOV du registre TIFRn
MISE en ŒUVRE du TIMER/COMPTEUR
Pour illustrer ce que l'on vient de voir je vous propose un petit programme utilisant le prescaler et le timer/compteur. 
Dans ce programme on utilisera des : 
• Instructions de haut niveau pour l'allumage et l'extinction de la Led, 
• Instructions de bas niveau pour la commande du prédiviseur et du timer/compteur 1. 


Description du programme :
Ces deux programmes réalisent le clignotement d'une led à une fréquence de 1 Hz.

Pour obtenir cela on utilise le prescaler avec une division par 4 et le prédiviseur du timer/compteur 1 par 64.

La division totale est de : 4*64 = 256. On aurait pu utiliser le prescaler du timer/compteur 1 réglé directement sur 256.

La fréquence au timer/compteur 1 est de : 16Mhz / 256 = 62,50 KHz = 16µs. Le timer/compteur 1 est incrémenté toutes les 16 µs.

Pour réaliser une tempo de 500 ms il faut : 0.5s / .000016s = 31250.

Le timer/compteur doit compter 31250 impulsions pour que cela réalise 0,5 s.

Si l'on veut faire déborder le timer/compteur 1 pour activer le Flag correspondant il faut prépositionner le registre :
•  TCNT1 à : 65536 - 31250 = 34286.

Le registre TCNT1 peut compter jusqu'à 65536. Pour cela le microcontrôleur utilise deux registres.
TCNT1H qui est l'octet de poids fort,
• TCNT1L qui est l'octet de poids faible.

Dans le premier programme on utilise le timer/compteur 1 d'une manière générale TCNT1 = 34286.

Dans le deuxième on utilise les deux registres du timer/compteur 1 :
TCNT1H = 0b10000101 = 133,
• TCNT1L = 0b11101110 = 238.


const byte led = 13;//Déclaration de la broche de la Led 
 
void setup()  

pinMode (led, OUTPUT);//Broche 13 en Sortie 
 
CLKPR = 0b10000000; //Activation du prescaler 
CLKPR = 0b00000010; //Division par 4 
 
TCCR1A = 0b00000000;//WGM10 et WGM11 à 0 
TCCR1B = 0b00000011;//WGM12 et WGM13 à 0 et division par 64 
//Division Totale 256 
 
TCNT1 = 34286; //Registre TCNT1 général
 

 
void loop()  

if (bitRead(TIFR1, 0) == 1) //Test du Flag

//Fréquence du Clignotement de la Led : 1Hz  
digitalWrite(led, digitalRead(led) ^ 1); // Inversion de la LED 
 
TCNT1 = 34286;  
 
bitSet (TIFR1, 0); //Remise à 0 du FLAG TIFR1 
 

}
       
const byte led = 13;//Déclaration de la broche de la Led 
 
void setup()  

pinMode (led, OUTPUT);//Broche 13 en Sortie 
 
CLKPR = 0b10000000; //Activation du prescaler 
CLKPR = 0b00000010; //Division par 4 
 
TCCR1A = 0b00000000;//WGM10 et WGM11 à 0 
TCCR1B = 0b00000011;//WGM12 et WGM13 à 0 et division par 64 
//Division Totale 256 
 
TCNT1H = 0b10000101; //Registre TCNT1H (octet de poids fort)
TCNT1L = 0b11101110; //Registre TCNT1L (octet de poids faible)

 
void loop()  

if (bitRead(TIFR1, 0) == 1) //Test du Flag

//Fréquence du Clignotement de la Led : 1Hz  
digitalWrite(led, digitalRead(led) ^ 1); // Inversion de la LED 
 
TCNT1H = 0b10000101; 
TCNT1L = 0b11101110; 
 
bitSet (TIFR1, 0); //Remise à 0 du FLAG TIFR1 

}
                                      
Programme TIMER/COMPTEUR 1, TCNT1 général
                                                 
Programme TIMER/COMPTEUR 1, TCNT1 décomposé

La surveillance du Flag TOV n'est pas la meilleure solution puisque le programme doit surveiller en permanence la mise à 1 de celui-ci.
Pour décharger le microcontrôleur de cette surveillance et optimiser grandement l'efficacité du programme il est préférable d'utiliser les INTERRUPTIONS.