Programmation Avr, seconde partie

Bon, j’espère que mon précédent billet vous aura permis de comprendre un peu comment fonctionnait la programmation avr.Il reste néanmoins encore de nombreux points qui pourraient êtres abordés, je voulais vous en présenter encore au moins 2 : les timers et les interruptions. Une fois ces deux points maîtrisés, vous serez capable déjà pas mal de petites choses avec vos microcontrolleurs.

Aujourd’hui : Les timers

Comme son nom peut vous laisser le deviner, un timer sert à comptabiliser le temps écoulé. Son principal intéret réside dans le fait que son exécution se déroule en parallèle du programme principal. Votre timer ne sera donc pas affecté par le nombre de d’instructions de votre programme.
Il est bien sur possible pour le programme principal d’interroger le timer, mais il est également possible de configurer le timer pour renvoyer une valeur directement sur une pin matérielle.
Avant d’aller plus loin sur la mise en place d’un timer, il nous faut aborder la notion de pré-scaller. En effet, si notre timer fonctionnait uniquement à la vitesse de l’horloge, nous serions assez rapidement embêté : à 1MHz, par exemple, un signal de 1mS correspondrait à 1000 cycles d’horloge, et pour un timer 8 bit tel que celui de notre ATTiny85, correspondrait à plus de 3 débordements de valeur. Autant dire que ce n’est pas très pratique.
C’est là qu’intervient le prescaler : il permet de faire fonctionner le timer à un sous-multiple de la fréquence d’origine, en divisant la fréquence par 8, 64, 256, 1024. Bien sur, en utilisant le préscaler, on diminue la résolution, il faut donc l’utiliser à bon escient.

Voyons maintenant ça en pratique : faire clignoter une led, mais sans utiliser les fonctions _delay_ms. La led est connectée sur le port PB1 (pin 6 de l’Attiny85). On veut faire changer l’état de notre Led dix fois par seconde. A 1MHz, il faudrait compter jusqu’à…. 100000, ce qui n’est pas directement possible avec notre registre 8 bits. Nous allons donc utiliser le prescaler, en divisant l’horloge par 1024 : 100000/1024 = 97.65, donc ça rentre.

# include <avr/io.h>
int main ( void )
{
DDRB |= (1 << PORTB1) ; //On configure PB1 en tant que sortie
//Todo : Configuration du timer avec prescaler de 1024
    for(;;)
    [
      if()//On vérifie si le timer a atteint un dixieme de seconde
      {
       PORTB ^= (1 << 0) ;//On inverse l'état de la led
       //on réinitialise le timer
       }
    }
}

TCCR0B

La datasheet nous indique que les bits permettant de régler le timer sont les bits CS00 à CS02, le tableau suivant nous expliquant les valeurs à donner en fonction de la configuration voulue.
Clksrc

Dans notre cas, nous voulons un prescaler de 1/64, il faut donc passer les bits CS00 et CS01 à 1, ce qui nous donne :

#include <avr/io.h>
int main ( void )
{
DDRB |= (1 << PORTB1) ; //On configure PB1 en tant que sortie
TCCR0B |= (1 << CS00) | (1<<CS02); //Set up timer1 with prescaler 1/1024
    for(;;)
    [
      if()//On vérifie si le timer a atteint un dixieme de seconde
      {
       PORTB ^= (1 << 0) ;//On inverse l'état de la led
       //on réinitialise le timer
       }
    }
}

Il ne nous reste plus qu’à lire notre timer, pour savoir s’il dépasse 97, et, si c’est le cas, inverser l’état de notre led, et réinitialiser le timer. Ces opérations se font via le Time Counter Register, à savoit TCNT0 sur notre ATTiny85 (il peut y en avoir plus d’un selon votre microcontrolleur). Selon la datasheet toujours, ce registre est accessible en lecture/écriture, ce qui nous permettra la lecture, mais aussi sa remise à Zero. Voici ce que nous donne le code :

#include <avr/io.h>

int main ( void )
{
DDRB |= (1 << PORTB1) ; //On configure PB1 en tant que sortie
TCCR0B |= (1 << CS00) | (1<<CS01); //Set up timer1 with prescaler 1/1024
    for(;;)
    [
      if(TCNT0>=97)//On vérifie si le timer a atteint un dixieme de seconde
      {
       PORTB ^= (1 << 0) ;//On inverse l'état de la led
       TCNT0 = 0;//on réinitialise le timer
       }
    }
}

A bientôt pour la dernière session : les interruptions.

–edit–
L’article a été mis à jour suite à des erreurs qui m’avaient été signalé. N’hésitez pas si vous en trouvez d’autres ;)

Tags: , , ,

4 réponses to “Programmation Avr, seconde partie”

  1. Julien Dit:

    Bonjour et bravo pour cet engouement pour les AVR. C’est toujours utile de connaitre ce qui se cache derrière les bibliothèques.

    Par contre, as-tu tenté de programmer ton ATtiny avec Arduino ?

    Vivement les interruptions… externes seulement ? car sur les timers, tu n’as pas parlé de TIMSK, le vecteur d’interruptions dédiées aux compteurs.

  2. nerick Dit:

    Bonjour,
    pour les interruptions, je comptais également voir les interruptions sur timer au prochain chapitre, c’est pour ça que j’ai commencé par les timers ;)
    Par contre, non, l’attiny85 j’ai pas essayé de le programmer avec l’arduino… Mais certains l’ont déjà fait à priori.

  3. alec Dit:

    euh excusez moi mais je voudrai revenir sur les calculs, je n’ai pas tout compris. vous avez écrit :
    « à 8MHz, par exemple, un signal de 10mS correspondrait à 8000 cycles d’horloge »

    ->dans une seconde à 8Mhz on a 8 000 000 cycles/sec non ?
    donc pour 10ms on devrait avoir 80 000 cyles non ?

    « et pour un timer 8 bit tel que celui de notre ATTiny85, correspondrait à plus de 30 débordements de valeur. »

    ->pour trouver ce nb de débordements vous avez divisé le nb de cycles par 255 (valeur maxi d’un byte) ?

    je suis débutant dans la programmation AVR et je pose ces questions pour comprendre correctement les principes.
    merci de votre aide. ces tutos sont simples et concis même si
    les calculs me déroutent un peu :)

  4. nerick Dit:

    Bonjour,
    effectivement, j’ai fait une petite coquille dans le calcul, il faut lire un signal de 1ms pour que le calcul soit juste, je corrige ça dans l’article ;)

    En ce qui concerne le nombre de débordements, c’est effectivement en divisant par 255 dans ce cas, car il s’agit d’un registre 8 bits. Attention, selon le microcontrolleur utilisé, il peut également s’agir de registres 16 ou 32 bits, la valeur de débordement change dans ce cas.

Laissez une réponse