INTERRUPTION par OVERFLOW




GÉNÉRALITÉS
Nous avons vu dans la page TIMER/COMPTEUR qu'avec la surveillance du Flag TOV on pouvait savoir à quel moment le timer/compteur avait débordé.
Mais cela implique une surveillance permanente de la mise à 1 du FLAG TOV ce qui ralentit le programme puisqu'il doit surveiller en permanence la mise à 1 de celui-ci.

Il est possible de laisser la surveillance du FLAG TOV au microcontrôleur ce qui permet d'améliorer grandement l'efficacité du programme.

Cette surveillance ce fait grâce à une interruption interne appelée INTERRUPTION par OVERFLOW (débordement).

L'Atméga 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 débordement interviendra lors du passage de 255 à 0,
• Le TC1 est un timer/compteur de 16 bits qui compte jusqu'à 65536 (0 à 65535), le débordement interviendra lors du passage de 65535 à 0,
• Le TC2 est un timer/compteur de 8 bits qui compte jusqu'à 256 (0 à 255), le débordement interviendra lors du passage de 255 à 0.

Le Timer 0 est utilisé par les fonctions DELAY et MICRO, on préfèrera utiliser les TIMER 1 et 2 pour nos montages.

MISE en OEUVRE
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) :

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

Le programmeur selon le fonctionnement voulu doit configurer différents registres :
• La fréquence de l'horloge utilisé, principalement celle du quartz de la carte de l'arduino,
• Le prescaler,
• Le prescaler du timer/compteur,
• Le timer/compteur utilisé (8 ou 16 bits),
• La valeur de départ du registre du timer/compteur considéré.

En effet en fonction de l'interval de débordement voulu il est nécessaire de prépositionner ses différents registres en association avec la fréquence de l'horloge et la définition du timer/compteur.

Pour illustrer ce que l'on vient de dire reprenons notre programme on l'on testé le FLAG TOV 1 pour connaitre le moment du débordement et utilisons une interruption par OVERFLOW pour surveiller le débordement.

Il faut activer les interruptions par overflow en positionnant le byte 0, TOIE1 du registre TIMSK1 à 1 :

byte toie du registre timsk1
Byte TOIE du registre TIMSK1
Il faut également activer les interruptions d'une manière générale soit :
• L'IDE de l'Arduino active par défaut les interruptions d'une manière générale,
• En positionnant le byte 7, I : Global Interrupt Enable, du registre SREG à 1.

byte i du registre sreg
Byte I du registre SREG

Byte TOIE du registre TIMSKn et GIE du registre SREG

Le PROGRAMME
Description du programme :
Configuration des différents registres pour notre programme :

Pour une fréquence de clignotement de 1 Hz
                                                                                    
Pour une fréquence de clignotement de 2 Hz
Pour obtenir cela on utilise le prescaler avec une division par 4 et le prescaler 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 1s il faut : 1s / .000016s = 62500

Le timer/compteur doit compter 62500 impulsions pour que cela réalise 1 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 - 62500 = 3036.

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.

En lieu et place de l'instruction TCNT1 = 3036, on peut utiliser les deux registres du timer/compteur1 en plaçant à l'intérieur les valeurs appropriées :
TCNT1H = 0b00001011 = 11,
• TCNT1L = 0b11011100 = 220.

Pour activer l'interruption par OVERFLOW il faut positionner le byte 0 du registre TMSK1 à 1 par l'instruction :
• TIMSK1 = 0b00000001;
TIMSK1 |= (1 << 0);

Appeler la routine d'interruption par l'instruction :
• ISR (TIMER1_OVF_vect) { code à exécuter }

Pour obtenir cela on utilise le prescaler avec une division par 4 et le prescaler 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.

En lieu et place de l'instruction TCNT1 = 34286, on peut utiliser les deux registres du timer/compteur1 en plaçant à l'intérieur les valeurs appropriées :
TCNT1H = 0b10000101 = 133,
• TCNT1L = 0b11101110 = 238.

Pour activer l'interruption par OVERFLOW il faut positionner le byte 0 du registre TMSK1 à 1 par l'instruction :
• TIMSK1 = 0b00000001;
TIMSK1 |= (1 << 0);

Appeler la routine d'interruption par l'instruction :
• ISR (TIMER1_OVF_vect) { code à exécuter }


Le programme
Utilisation du Timer 1

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 : WGM Timer/compteur Mode normal 
TCCR1B = 0b00000011;//WGM12 et WGM13 à 0 et division par 64 (timer/compteur) 
//Division Totale 256 
 
TCNT1 = 3036; 
 
TIMSK1 |= (1 << 0); // Autorisation Interruption par overflow 
 
}
 
 
ISR(TIMER1_OVF_vect) // Appel de la routine d'interruption 
{                                           //Fréquence de clignotement 1Hz 
 
TCNT1 = 3036; // Rechargement du timer1 
digitalWrite(led, digitalRead(led) ^ 1); //Fonction Ou Exclusif 
 

 
void loop() 

 
}

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 : WGM Timer/compteur Mode normal 
TCCR1B = 0b00000011;//WGM12 et WGM13 à 0 et division par 64 (timer/compteur) 
//Division Totale 256 
 
TCNT1 = 34286; 
 
TIMSK1 |= (1 << 0); // Autorisation Interruption par overflow 
 

 
ISR(TIMER1_OVF_vect) // Appel de la routine d'interruption 
{                                           //Fréquence de clignotement 2Hz 
 
TCNT1 = 34286; // Rechargement du timer1 
digitalWrite(led, digitalRead(led) ^ 1); //Fonction Ou Exclusif 
 

 
void loop() 

 
}

Utilisation du Timer 2
Nous allons dans un deuxième temps utiliser le Timer 2.

Le problème est que notre timer ne peut compter que jusqu'à 256.

Si l'on garde la fréquence de base de 16Mhz il nous faudrait une boucle qui se réaliserait 16 Mhz / 256 = 62500 fois pour obtenir une temporisation de 1 seconde.

Soit 62500 débordements et appel de la boucle overflow.

Essayons de réduire ce nombre.

Pour cela il faut ralentir le temps de comptage de notre timer 2 pour obtenir une valeur plus faible et laisser respirer notre programme.

Il s'agit de trouver un diviseur 62500 qui nous donne une base pour la temporisation que nous multiplierons par le nombre de boucle à effectuer pour obtenir la temporisation voulue.

Pour cet exemple j'utilise le prescaler la division du timer pour manipuler les registres.

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

Pour le comptage du timer 2 : 250 * 0,000016s = 0,004s.
Lorsque le timer 2 déborde cela représente un temps de 0,004s.
Il faudra prépositionner notre timer 2 avec la valeur 6 pour qu'il déborde après 250 incrémentations.

Nous prendrons les valeurs :
• 6 pour notre timer 2 et,
• 250 pour le nombre de boucle à effectuer.

Nota : Pour choisir des valeurs différentes avec la meilleure précision possible il faudrait modifier la fréquence de l'horloge.

Pour obtenir cela on utilise le prescaler avec une division par 8 et le prescaler du timer/compteur 2 par 32.

La division totale est de : 8*32 = 256. On aurait pu utiliser le prescaler du timer/compteur 2 réglé directement sur 256 ou une autre configuration.


Pour activer l'interruption par OVERFLOW il faut positionner le byte 0 du registre TMSK2 à 1 par l'instruction :
• TIMSK2 = 0b00000001;
TIMSK2 |= (1 << 0);

Appeler la routine d'interruption par l'instruction :
• ISR (TIMER2_OVF_vect) { code à exécuter }

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

Pour le comptage du timer 2 : 250 * 0,000016s = 0,004s.
Lorsque le timer 2 déborde cela représente un temps de 0,004s.
Il faudra prépositionner notre timer 2 avec la valeur 6 pour qu'il déborde après 250 incrémentations.

Nous prendrons les valeurs :
• 6 pour notre timer 2 et,
• 125 pour le nombre de boucle à effectuer.

Nota : Pour choisir des valeurs différentes avec la meilleure précision possible il faudrait modifier la fréquence de l'horloge.

Pour obtenir cela on utilise le prescaler avec une division par 8 et le prescaler du timer/compteur 2 par 32.

La division totale est de : 8*32 = 256. On aurait pu utiliser le prescaler du timer/compteur 2 réglé directement sur 256 ou une autre configuration.


Pour activer l'interruption par OVERFLOW il faut positionner le byte 0 du registre TMSK2 à 1 par l'instruction :
• TIMSK2 = 0b00000001;
TIMSK2 |= (1 << 0);

Appeler la routine d'interruption par l'instruction :
• ISR (TIMER2_OVF_vect) { code à exécuter }

 
Le programme
Utilisation du Timer 2

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

pinMode (led, OUTPUT); //Broche 13 en sortie 
 
bitClear (TCCR2A, WGM20); // WGM20 = 0 
bitClear (TCCR2A, WGM21); // WGM21 = 0  
 
CLKPR = 0b10000000; //Activation Prescaler 
CLKPR = 0b00000011; //Division par 8 

TCCR2B = 0b00000011; // Division par 32 et WGM22 = 0 
//Total division par 256 
 
TIMSK2 |= (1<<0); // Autorisation Interruption par Overflow Timer 2, TOIE2 
TCNT2 = 6; // Timer à 6 
 
}
 
  
ISR(TIMER2_OVF_vect) // Appel de la routine d'interruption 
{ //Fréquence de clignotement 1Hz 
 
if (compteur++ > 250) // Incrémentation et test si on atteint 250 : 1s 

compteur = 0; // Raz comptage 

digitalWrite(led, digitalRead(led) ^ 1); // Inversion état de la LED 

 TCNT2 = 6; // Timer à 6 


 
void loop() 
{ }
const byte led = 13; //Déclaration de la broche de la Led 
 
int compteur = 0;//Déclaration de la variable compteur
 
 
void setup () 

pinMode (led, OUTPUT); //Broche 13 en sortie 
 
bitClear (TCCR2A, WGM20); // WGM20 = 0 
bitClear (TCCR2A, WGM21); // WGM21 = 0  
 
CLKPR = 0b10000000; //Activation Prescaler 
CLKPR = 0b00000011; //Division par 8 

 TCCR2B = 0b00000011; // Division par 32 et WGM22 = 0 
//Total division par 256 
 
TIMSK2 |= (1<<0); // Autorisation Interruption par Overflow Timer 2, TOIE2 
TCNT2 = 6; // Timer à 6 
 
}
 
  
ISR(TIMER2_OVF_vect) // Appel de la routine d'interruption 
{ //Fréquence de clignotement 2Hz 
 
if (compteur++ > 125) // Incrémentation et test si on atteint 125 : 0,5s 

compteur = 0; // Raz comptage 

digitalWrite(led, digitalRead(led) ^ 1); // Inversion état de la LED 

 TCNT2 = 6; // Timer à 6 


 
void loop() 
{ }