Micro contrôleurs AVR/Le Timer 2
Nous regroupons dans ce chapitre les quelques informations utiles concernant le timer 2. C'est un timer très proche du timer 0 : il est aussi sur 8 bits.
Le timer 2 n’est pas présent dans le processeur ATMega32U4 qui équipe la carte Arduino Leonardo. Il possède par contre un timer 3 et un timer 4.
Voici ci-contre, avec les conventions schématiques habituelles, le schéma de fonctionnement du timer 2.
On distingue ainsi le bit b0 du registre TIFR2 appelé TOV2 qui est mis à un automatiquement par le matériel. Ce ne sera pas la matériel qui le mettra à 0 s'il n'y a pas d'interruptions. C'est à vous programmeur de le faire ! Mais pour le faire il vous faut écrire un 1 dans ce bit b0 !
Les habituels bits de configuration de la division se trouvent dans le registre TCCR2B et fonctionnent exactement comme pour timer 0.
Le registre ASSR sert à choisir la source de l'horloge du timer 2. Pour nous, sauf mention contraire, ce sera toujours le quartz. Ce registre doit être configuré dans ce mode de fonctionnement par défaut.
Génération de signaux
modifierAttente passive du drapeau
modifierLes bits appelés drapeaux (flag en anglais) sont spéciaux : ils sont mis à 1 par le matériel mais doivent être relis à 0 par le programmeur (VOUS donc). Et comble de complexité la mise à 0 du bit correspondant se fait par une mise à 1 !
En utilisant une interruption
modifierL'attente passive de la section précédente peut être évitée à l'aide des interruptions. On imagine un programme qui fait des tas de choses mais qui sera interrompu régulièrement par un timer.
Comme d'habitude, la réalisation de l'interruption se fait par la transmission du front montant de TOV2 dans l'ellipse rouge. Et pour ce faire, il faut naturellement mettre TOIE2 de TIMSK2 à 1, ainsi que I de SREG.
Pour être complet, la mise à 1 de I se fait par un simple "sei();" en C. Son objectif est d'autoriser de manière générale les interruptions. Les bits de TIMSK2 sont manipulés de manière standard.
Exemple d'interruption
modifierVous disposez d'un shield permettant la commande de deux afficheurs. Celui-ci est câblé comme ceci :
Segment | pt | g | f | e | d | c | b | a |
---|---|---|---|---|---|---|---|---|
Arduino Pin | 11 | 9 | 10 | 8 | 7 | 6 | 12 | 13 |
Port | PB3 | PB1 | PB2 | PB0 | PD7 | PD6 | PB4 | PB5 |
D'autre part la broche PD4 est responsable de la commutation des deux afficheurs. Réaliser une interruption d'affichage et un compteur en programme principal capable de compter sur une variable 8 bits en décimal.
Voici une solution possible qu’il faudra adapter à votre shield :
// OK UNO + shield IUT
#define F_CPU 16000000UL
#define __DELAY_BACKWARD_COMPATIBLE__
#include <util/delay.h>
// deux ports sont utilisés dans le câblage du shield
const uint8_t affPortB[10]={0b00110101,0b00010000,0b00110011,0b00110010,0b00010110,0b00100110,0x27,0x30,0x37,0x36};
const uint8_t affPortD[10]={0b11000000,0b01000000,0b10000000,0b11000000,0b01000000,0b11000000,0xC0,0x40,0xC0,0xC0};
volatile unsigned char mux=0;
volatile uint8_t n=0;
ISR(TIMER2_OVF_vect) {
// changer d'afficheur à chaque interruption
mux++;
if ((mux & 0x01)==0x00) {
PORTB = affPortB[n & 0x0F];
PORTD = affPortD[n & 0x0F];
PORTD |= 0x10; // afficheur unité
} else {
PORTB = affPortB[(n & 0xF0)>>4];
PORTD = affPortD[(n & 0xF0)>>4];
PORTD &= ~0x10; // afficheur dizaine
}
}
int main() {
// config e/s
DDRB = 0x3F;
DDRD = 0xD0;
// choix du pré-diviseur par 1024
TCCR2B |= (1<<CS22);
TCCR2B |= (1<<CS21);
TCCR2B |= (1<<CS20);
// Acquittement du drapeau TOV2
TIFR2 |= 1<<TOV2;
// autorisation de l'interruption débordement timer 2
TIMSK2 |= (1<<TOIE2);
// autorisation générale des interruptions
sei();
// debut de la boucle infinie
while(1) {
// debut du comptage BCD
n++;
if ((n&0x0F)>0x09)
n = n+6;
if ((n&0xF0)> 0x90)
n = n+0x60;
// attente passive
_delay_ms(1000);
}
}
Cette façon de réaliser un compteur décimal en considérant deux parties de 4 bits qui ne varient que de 0 à 9 est à retenir.
Sans interruption et sans attente passive : le matériel fait tout
modifierVoici la documentation correspondante sous forme de schéma (ci-contre).
Ce mode de fonctionnement s’appelle la comparaison. L’idée générale est que lorsque le timer 2 (TCNT2) arrive à la même valeur que celle qui est contenue dans un registre (OCR2A ou OCR2B) une logique interne est capable de changer (ou pas) une sortie qui s’appelle OC2A ou OC2B.
Ce mode est essentiellement géré par les deux bits COM2A1 et COM2A0 comme indiqué dans le tableau ci-dessous :
- Mode non PWM pour la comparaison
COM2A1 | COM2A0 | Description |
---|---|---|
0 | 0 | Opération Normale PORT, OC2A déconnecté |
0 | 1 | Bascule OC2A sur la comparaison |
1 | 0 | Mise à 0 de OC2A sur la comparaison |
1 | 1 | Mise à 1 de OC2A sur la comparaison |
Generation de signal MLI
modifierLa Modulation de Largeur d'Implulsion ou MLI permet de faire varier des intensités lumineuses ou des vitesses de rotation de moteur.
Ce mode est géré par les bits WGM22, WGM21 et WGM20 en suivant le tableau suivant :
- Description des bits pour les modes de fonctionnement du timer 2
Mode | WGM22 | WGM21 | WGM20 | Mode de fonctionnement | Bas si | Mise à jour de OCRAx si | Drapeau TOV2 positionné si |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | Normal | 0XFF | immédiatement | MAX |
1 | 0 | 0 | 1 | PWM à phase correcte | OXFF | TOP | BOTTOM |
2 | 0 | 1 | 0 | CTC | OCR2A | immédiatement | MAX |
3 | 0 | 1 | 1 | PWM rapide | 0XFF | BOTTOM | MAX |
4 | 1 | 0 | 0 | Reservé | - | - | - |
5 | 1 | 0 | 1 | PWM à phase correcte | OCR2A | TOP | BOTTOM |
6 | 1 | 1 | 0 | Reservé | - | - | - |
7 | 1 | 1 | 1 | PWM rapide | OCR2A | BOTTOM | TOP |
Attention : ces trois bits n'appartiennent pas au même registre comme le montre le schéma ci-dessous !
Comme la figure ci-dessus ne le documente pas, nous donnons maintenant les modes de générations de signaux en mode PWM rapide.
- Mode PWM rapide
COM2A1 | COM2A0 | Description |
---|---|---|
0 | 0 | Opération Normale de PORT, OC2A déconnecté |
0 | 1 | WGM22 = 0: Opération Normale de PORT, OC2A déconnecté, WGM22 = 1: Bascule OC2A sur la comparaison |
1 | 0 | Mise à 0 de OC2A sur la comparaison et à 1 sur overflow (MLI non inversée) |
1 | 1 | Mise à 1 de OC2A sur la comparaison et à 0 sur l'overflow (MLI inversée) |