Utilisation des timers avec l’ATMEL AVR ATmega1280


On continu sur la lancée de l’article précédent en parlant microcontrôleur. Après avoir montré comment faire pour compiler de telle façon à ce que notre code puisse être exécuté sur l’AVR, il est temps de créer notre premier programme 🙂

Utilisation des timers 16 bits

Attention, les 8 bits ne s’utilisent pas exactement de la même façon. Perso je n’ai pas encore joué avec, donc j’en parlerai pas. On va juste voir comment fonctionne un timer 16 bits ici 🙂 Pour l’exemple, on prendra le TIMER4. Ainsi, la configuration de celui-ci se fait sur deux octets (8×2 bits) qui contiennent les flags suivants :

          7       6       5       4       3       2       1       0
TCCR4A:   COM4A1  COM4A0  COM4B1  COM4B0  -       -       WGM41   WGM40
TCCR4B:   FOC4A   FOC4B   -       -       WGM42   CS42    CS41    CS40

Le nom de l’octet est le premier élément de présent dans le tableau (TCCR4A et TCCR4B). Après cela, on retrouve les douces appellations des bits que nous pouvons règlé. Leurs désignations sont celles-ci :

  • COM4A0:1 Je ne sais pas trop, donc j’en parle pas pour le moment.
  • COM4B0:1 Je ne sais pas trop, mais c’est la même chose que les deux bits d’avant sauf pour une autre variable.
  • WGM40:2 Permet de défénir comment le compteur doit réagir quand sa valeur est la même que celle de OCR4Aqui est une variable de 16 bits à laquelle nous pouvons donner la valeur que l’on veut. Il existe pas mal de mode, mais, j’en connais que deux :
    • 000 qui est le mode normal, c’est-à-dire qu’il ne se passe rien au moment de la comparaison (si ce n’est l’émission d’une interruption).
    • 100 qui et le mode CTC. Je ne sais plus la signification de ce terme, mais ça réinitialise le compteur à la comparaison 😉
  • FOC4A:B Je ne connais pas non plus le but de ces bits 🙁
  • CS40:2 C’est les bits d’activations du compteur, et de réglage du « préscalaire ».  Le préscalaire permet de réduire la vitesse du « tic » de l’horloge interne. Parce que « naturellement », c’est du rapide : 8 Mhz = 8 000 000 tics par seconde, vas-y pour compter avec quelque chose qui dure plus de 2ms avec une variable 16 bits xD On a :
    • 000 Le compteur est stoppé. Oui, par défaut, il n’est pas activé ! Attention donc ^^ »
    • 001 Activation du compteur sans préscalaire. C’est la plus grande des vitesses possible.
    • 010 Activation du timer avec un préscalaire de 8. Ainsi, il n’y a plus 8 000 000 de tics dans une seconde pour une horloge à 8Mhz, mais qu’un million.
    • 011 Activation avec préscalaire de 64.
    • 100 Activation avec préscalaire de 256.
    • 101 Activation avec préscalaire de 1024.
    • 110 Je ne comprend pas encore bien.
    • 111 Je ne comprend pas encore bien non plus.

Utilisation des interruptions

C’est bien beau d’avoir des timers dans son programme, mais encore faut-il savoir quoi en faire. Comment ça se passe quand le timer atteint une somme recherchée ? En fait, pour cela il suffit d’utiliser les interruptions 🙂  Ça se passe dans le registre TIMSK4 pour TIMER4 :

          7       6       5       4       3       2       1       0
TIMSK4:   -       -       ICIE4   -       OCIE4C  OCIE4B  OCIE4A  TOIE4
  • ICIE4 Je ne comprend pas à quelle interruption ça correspond.
  • OCIE4C Quand la valeur du timer est la même que OCR4C, soit la comparaison avec le registre du TIMER4.
  • OCIE4B Pareil avec le registre C.
  • OCIE4A Pareil avec le regitre A.
  • TOIE4 Interruption quand le timer atteind sa valeur maximale. À savoir pour un timer 16 bits : 2¹⁶.

Il faudra faire attention à ne pas oublier d’activer les interruptions avec la fonction sei() en C. Ça vous évitera quelques minutes de débogage :p

Une fois le timer activé, il ne reste plus qu’à écrire le code à exécuter une fois l’interruption émise. Pour cela, on utilise une macro (je pense), qui s’implémente comme une fonction prenant en paramètre le nom de l’interruption qui la concerne. Cette « macro / fonction » s’appelle ISR. Et le nom des interruptions sont les suivants : TIMER4_COMPA_vect, TIMER4_COMPB_vect, TIMER4_COMPC_vect et TIMER4_OVF_vect.

Comme un exemple est toujours plus parlant, voici le code source d’un programme qui se contente de faire clignoter les leds. Comme je n’aime pas trop les maths, on va choisir les fréquences de clignotement à l’arrache, tant que ça reste suffisamment lent pour être visible pour l’œil humain 🙂

#include <avr/io.h>
#include <avr/interrupt.h>

//Implémentation du code à exécuter quand l'interruption
//de comparaison entre le TIMER4 et son registre B est
//émise.
ISR(TIMER4_COMPB_vect) {
   //On allume les leds
   PORTH = 0xFF;
}

//Implémentation du code à exécuter quand l'interruption
//de comparaison entre le TIMER4 et son registre A est
//émise
ISR(TIMER4_COMPA_vect) {
    //On etteind les leds
    PORTH = 0x00;
}

int main(int argc, char **argv) {
    //On active TIMER4 avec un préscalaire de 1024
    //pour qu'on ai le temps de voir quelque chose.
    TCCR4B |= 1<<CS40 | 1<<CS42;

    //On active l'interruption avec A et B
    TIMSK4 |= 1<<OCIE4A | 1<<OCIE4B;

    //On reset le timer quand il atteind la valeur de A
    //On remarque du coup qu'il n'ira JAMAIS jusqu'à
    //sa valeur d'overflow
    TCCR4B |= 1<<WGM42;

    //On entre la valeur de A
    OCR4A = 20000;

    //On entre la valeur de B
    OCR4B = 10000;

    //On "initialise" les leds.
    //(On a pas vu ça dans cet article)
    DDRH = 0xFF;

    //On active les interruptions
    sei();

    //On fait tourner le programme dans le vide
    while(1);

    return 0;
}

En gros comment ça se passe ? On initialise un timer qui va 1024 fois plus lentement que la vitesse du processeur (préscalaire de 1024), et dès que ça valeur est de 10000, l’interruption B est émise, ce qui active les leds. Arrivé à 20000, c’est l’interruption A qui se déclenche et qui rééteint les leds. Mais, grâce au flag WGM42 dans TCCR4B, la valeur du timer retombe à 0. Et c’est une boucle sans fin 🙂

Bonne chance à vous pour vos programmes !

,