AVR – Chapitre 3 – Utiliser les compteurs

Un  compteur (timer en anglais), en électronique, est une fonction qui permet de générer un tic (tick) à une fréquence définie. C’est fonction est cruciale pour beaucoup d’applications comme la gestion du temps, la communication, mais aussi pour générer des valeurs analogiques (dans le prochain chapitre).

En théorie…

un peu de maths

Pour l’ATtiny, le concept est simple : un compteur est réglé pour incrémenter un registre de 8 bits à chaque tic en fonction :

  • de l’horloge du processeur
  • d’un diviseur

Ce registre, une fois arrivé au maximum (255 pour 8 bits) va déclencher une interruption de dépassement de compteur au prochain incrément.

Ainsi, pour une fréquence d’horloge de 8 MHz, avec un diviseur configuré à 256, on peut s’attendre à une interruption de dépassement toutes les 8,192 ms. \displaystyle t = \frac{{2}^{taille\ du\ registre\ du\ compteur} \times diviseur}{frequence} = \frac{{2}^{8}\times 256}{8\times {10}^{6}} = 8,192\ ms.

8 millisecondes c’est court !

La documentation de l’ATtiny85 nous donne les diviseurs disponibles (page 80) et la configuration du registre TCCR0B en conséquence (les bits CS00, CS01 et CS02). On peut donc utiliser un de ces diviseurs :

  • 1 (pas de diviseur)
  • 8
  • 64
  • 256
  • 1024

Il est également possible d’utiliser une horloge externe, mais celle disponible ici suffira.

Dans notre cas il s’agit de compteur 8 bits, et la manière la plus élégante d’arriver à compter des secondes est de compter un certain nombre d’interruptions, et de n’agir qu’à une seule de ces interruptions. Dans le cas des compteurs 16 bits, il est possible d’utiliser une autre méthode que je ne décrirai pas pour le moment.

En laissant passer 122 interruptions pour dépassement, on peut approximer la seconde :
\displaystyle 122 \times 8,192 = 999,424\ ms

 … et en pratique !

Reprenons rapidement les étapes pour utiliser un compteur pour faire clignoter une diode :

  • on note la fréquence de l’horloge du microcontrôleur
  • on définit un diviseur pour le compteur 0, à la valeur de 256
  • on prépare une section qui va gérer l’interruption pour dépassement du compteur 0
  • on y déclare une condition qui ne changera l’état de la diode toutes les 122 interruptions, soit toutes les secondes

maintenant, le code !

 

 

Nous voici donc capable d’exécuter du code à intervalle régulier, ce qui va avoir une multitude d’utilités pour la suite !

 

7 réflexions au sujet de « AVR – Chapitre 3 – Utiliser les compteurs »

  1. Bonjour,

    Je suis tombée par hasard sur votre site internet au gré de mes recherches concernant les microcontrôleurs. Je ne suis pas électronicienne, mais traductrice, ce qui m’oblige au quotidien à me documenter en français sur des sujets techniques variés. Il se trouve que je traduis souvent des communiqués de presse ou articles techniques sur les microcontrôleurs. Je voulais vous remercier pour les précieuses informations que j’ai pu trouver sur votre site, et vous féliciter pour votre effort de rédaction en français. Grâce à vous, je comprends un peu mieux ce que je traduis. Je reviendrai vous lire à l’occasion.

    Bonne continuation à vous.

    Isis

    1. Bonsoir,

      Je suis heureux que ces articles puissent vous aider dans votre travail. Merci pour votre soutien. Et n’hésitez pas à me demander toute précision.

      Bonne soirée,

      Geoffrey

  2. bonjour,
    je suis agreablement surpris par votre site car je me suis également lancé comme vous ds un projet sur un Avr ATmega128
    actuellement j’utilise celui ci sur un robot qui me permettra de cartographier une pièce ,mon second projet est egalement en cours( faire la domotique de ma maison.)

    pour revenir a l’objet de mon message je souhaite crée 4 chronometres en utilisant le TIMER0(les autres Timers etant utiliser en PMW pour gerer des servos ).

    pour cela je veux creer 4 fonctions
    – getStopwatch1(0) //permet d’initialiser le chronometre
    – startStopwatch1() //demarrer le chrono
    – getStopwatch1() //pour connaitre la valeur actuelle du chrono
    – stopStopwatch1() // pour arreter le chrono

    pour l’instant je sais pas comment m’y prendre (pourtant j’ai fais des choses bien plus compliquées comme faire dialoguer ensemble 3 avrs en i2C)

    je cherche donc une solution, peut etre avez vous deja travaillé sur un tel projet .si oui je serais heureux de partager votre savoir

    cordialement,

    1. Bonjour,

      La premier problème selon moi est de déterminer la taille en bits de la donnée que l’on va vouloir récupérer ; s’agit-il d’un temps exprimé en secondes ? en heures ? en millisecondes ? Ceci va nous permettre de déterminer le diviseur et la taille de la boucle (en nombre d’interruptions). Il faut également déterminer la grandeur de ce que l’on va mesurer ; envisage t-on d’aller de 0 à 60 ? de 0 à 1000 ? bien au-delà ? Ceci va permettre de connaitre la taille de l’entier dont on à besoin, et le cas échéant, des adaptations qu’il faudra faire pour gérer un entier dont la taille est supérieur à 64bits.

      L’implémentation reste simple cependant ; imaginons que je souhaite un chronomètre mesurant des centièmes de secondes pendant une durée d’au moins un an (oui, c’est possible). J’utilise un microcontrôleur à 8MHz, avec un compteur de 8 bits. En cherchant le diviseur idéal, avec la formule dans l’article, on obtient :

      nombre_interruptions = unité_cherchée / ( ( diviseur * taille_compteur ) / cadence_microcontrôleur ) = 0.01 / ( ( d * 2^8 ) / ( 8 * 10^6 ) )

      pour d=1 : nombre_interruptions = 312.5 soit une marge d'erreur de (312.5/312) - 1 = 0.16%
      pour d=8 : nombre_interruptions = 39.06 soit une marge d'erreur de (39.06/39) - 1 = 0.15%
      pour d=64 : nombre_interruptions = 1.22 soit une marge d'erreur de (1.22/1) - 1 = 22%

      un diviseur au delà n’a aucun sens ici. Le diviseur idéal est ici 8.
      D’autant que le nombre d’interruptions est inférieur à 256 ce qui permet de le stocker dans un entier de 8 bits.

      Ensuite, on choisit la taille de l’entier qui stockera la valeur actuelle du chronomètre. Vu qu’on souhaite un compteur d’un an, soit 366j = 31622400s, que l’on multiplie par 100 pour avoir des centièmes de seconde, on s’aperçoit que ceci tient dans un entier de 32 bits (qui lui peut aller jusqu’à 497 jours en comptant des centièmes).

      Voici un exemple de code qui pourrait faire ce que l’on souhaite :

      #include
      #include

      #define F_CPU 8000000L
      #define MAX_INTERRUPTS 39

      uint32_t chrono;
      uint8_t its_counter;

      void startStopwatch(){
      //On active les interruptions pour dépassement du compteur 0
      TIMSK0 |= 1< =MAX_INTERRUPTS){
      //Si on arrive au maximum d'interruptions, on réinitialise, ...
      tts_counter=0;
      //... et on incrémente le compteur de centième
      chrono++;
      }
      //On réactive les interruptions
      sei();
      }

      Cependant, ces opérations sont réalisées parmi d’autres dans le processeur du microcontrôleur, et il n’est pas impossible que la valeur de la « seconde » puisse varier, parfois plus longue et parfois plus courte. Ce code peut être tout à fait acceptable pour des applications domestiques (allumer une lampe, calculer la durée moyenne d’ouverture d’une porte, …) mais pour des applications plus pointues, il peut être nécessaire d’utiliser du matériel spécialisé comme les horloges RTC.

      Bonne continuation !

  3. merci pour cette reponse tres rapide
    vous avez raison pour les diverses operations il faudra que je m’assure des durées exactes en fonctions des cycles du Uc.de plus j’ai appris que certaines fonctions comme le Delay sont basées sur le Timer0 (donc peu etre que l’usage du prescaler 8 me changera mes valeur de delay a voir).

    en tous cas merci,pour les infos je vais l’essayer de suite ds mon projet

  4. Bonsoir, j’aime bien vos « tutos » sur les AVR je voudrais créer un signal video vga pour cela je dois faire des signaux de synchronismes de quelque micro-secondes pensez-vous qu’il est possible de réalisé cela ?
    Par exemple pour le signal horizontal sa serait tout les 31 micro-secondes.
    Merci

    1. Un signal à 31㎲ de période doit avoir une fréquence d’environ 32㎑. C’est possible avec un AVR, il suffit d’écrire une fonction porteuse et de l’appeler le nombre de fois nécessaire. Cf mon article sur la télécommande pour LED RGB.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*