Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Commentez, partagez et proposez des Tutos en langage C !
le Timer : TMR0 ,la suite
Jérémy
Administrateur du site
Administrateur du site
Messages : 2722
Âge : 44
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#1 Message par Jérémy » dim. 23 août 2015 15:14

Bonjour à tous,

Ce Tutoriel est la suite du tuto N°7 avec un peu plus de précision.

Dans le précédent Tuto, nous avons créer une temporisation d'environ une seconde. Cette imprécision n'est pas forcement acceptable dans toutes les circonstances . Pour corriger ce problème , il va falloir peaufiner notre initialisation de Timer.

Objectif :

- faire une temporisation de 1 seconde précise avec le Timer0 , en jouant sur la valeur d’initialisation.

Pour bien comprendre :

Reprenons notre exemple , comme quoi, notre µC fonctionne à 1Hz . donc 1 instruction/seconde.

Imaginons que nous souhaitions une temporisation de 10 secondes . Plusieurs solutions s'offre à nous :

1/ la première que nous utiliserons jamais et vous allez comprendre pourquoi. Il s'agirait de regarder à chaque instructions la valeur de notre compteur. ça donnerai :

- instruction
- lire notre timer (timer=1): si égale à 10 on fait une tâche
- instruction
- lire notre timer (timer=2) : si égale à 10 on fait une tâche
|
|
|
|
- instruction
- lire notre timer (timer=10) : si égale à 10 on fait une tâche

On voit bien que lire en permanence la valeur de notre Timer serait complétement idiot et pas du tout fonctionnel.

2/ La deuxième , que vous utiliserez je n'en doute pas.

On va utiliser ce fameux Flag. Plutôt que de scruter le Timer en permanence, nous allons utilisez l'interruption de débordement et son drapeau. Mais!, me direz vous le drapeau ne se lève que quand le compteur atteint 255 et repasse à 0 . Donc il ne se lève que toutes les 255 secondes :?: Et oui vous avez raison et compris c'est un bon point !
Pour ce faire nous allons initialiser notre TMR avec une valeur de départ . C'est ici ou se trouve toute la subtilité qu'il faut bien comprendre.

Comme on peut écrire sur notre Timer, on peut donc l’initialiser à 245 . alors quand il arrivera a 255 et lèvera son drapeau il se sera écoulé nos 10 secondes.
255-10 = 245 .

Sans vouloir vous découragez , et j’espère que vous l'aurez compris , je viens de réduire à sa plus simple expression l'utilisation d'un Timer. Ainsi j’espère que vous aurez compris le principe de fonctionnement général .

revenons à nos moutons et à notre compteur de 1seconde.

Pour RAPPEL :

Avec la configuration précédente nous obtenions 1.015 s . c'est à dire 15ms de trop.
Nous avions :
- une instruction toutes les 128µs.
- 1 débordement tous les = 128*256=32,768 ms

En toute logique il va donc falloir retrancher ces 15ms . Commençons par ne pas dépasser les 1 seconde .

Donc au lieu de multiplié par 31 nous allons multiplié par 30.
30 x 32.768 = 983.04 ms
il nous manque donc 16.96 ms pile poil.

en sachant qu'une instruction dure 128µs il nous faut donc combler ces 16.96ms avec autant d’instructions .
16,96ms = 16960µs
16960/128 = 132.5

Comme rien n'est simple, le fait de modifier notre Timer en initialisant une valeur au départ celui-ci nous prends 2 instructions . Donc c'est 130.5 instructions qu'il faut pour bien combler.
Il nous faudra donc compter 130 instructions dans la première boucle au lieu de 255 quand on partait de zéro.
Comme dans notre exemple nous allons retrancher ces 130 instructions à notre compteur . donc 255 - 130 =125

Il faudra que notre compteur au départ soit initialisé à 125 au lieu de 0. Ainsi sa première boucle durera de 125 à 255 soit 130 instructions soit 130*128=16640 µs= 16.640ms
sans oublié de rajouter nos 2 instructions pour initialiser le TMR0 16640+128+128 = 16896µS
Pour résume une première boucle de comptage de 16.8960ms et 30 boucles de 32.768ms = 999.936 ms = 0.999936s .

On remarque que ça ne tombe pas pile poil. pour ne pas vous embrouiller, je ne recommencerai pas les Tuto, mais par contre vous pouvez vous entrainez en faisant un exercice pour tomber pile poil . soit en jouant sur le PRE-SCALER , soit en passant le compteur en 16bit .
Pour vérifier : 1s - 0.999936 = 0.000064 s soit 64µs de moins , cela correspond à une demi instruction ( 128/2=64) qu'on retrouve quand on a arrondi 130.5 à 130 .

Pour un bon programme il faudra bien sur tomber parfaitement sur le bon nombre d'instruction, sinon votre tempo se décale dans le temps. Si j'ai le temps je ferais la correction avec un exemple !

Code : Tout sélectionner

//#################################       DECLARATION      #########################################

 char compteur = 0;          // Déclaration de la variable compteur en char ( 0 à 255) et on l'initialise à 0 en même temps
 
//#################################        FONCTION       #########################################

void interrupt() {           // Ici c'est notre fonction d'interruption

                             // On regarde quel drapeau a été mis à 1, pour connaitre la source de l'interutpion
  if (INTCON.TMR0IF == 1)         // Ici le bit TMR0IF (bit2) du registre INTCON est testé
  {
   ++compteur;               // On incremente notre compteur sur une interrutpion

   INTCON.TMR0IF = 0;        // IMPORTANT !!! On ré-arme notre drapeau en le remettant à 0
  }
}

//#########################     FONCTION PRINCIPALE ET CONFIGURATION    #################################

void main() {                // ceci contiendra notre programme, c'est la fonction principale(main) et elle est obligatoire.

     ANSELC = 0;             // Met le PORT C en numérique

     PORTC = 0;              // Affecte 0 au PORT C

     TRISC = 0b00000000;     // Place le PORT C en sortie pour afficher les leds
     
     T0CON 
= 0b11000111 ;    // Configuration du TIMER0
     TMR0L = 125;            // chargement de la valeur 125 dans le TIMER du bas
     TMR0H = 0;              // chargement de la valeur 0 dans le TIMER du haut
     
     INTCON 
= 0b10100000;    // Configuration de l'interruption

 //#################################     Boucle infinie    #########################################

 while(1)                 // Ici c'est notre boucle sans fin.
 {
      if (compteur == 31) // Si notre compteur d'interruption à atteint la valeur calculée de 31
         {
          PORTC = ~PORTC; // alors on inverse nos sorties
          compteur = 0;   // On remet à 0 notre compteur pour une nouvelle tempo
          TMR0L = 125;    // On re-initialisenotre compteur à la bonne valeur seulement pour la premiere boucle
         }

  }
 }                        // Fin de notre fonction principale, la boucle est bouclée         


Attention La temporisation parfaite :
► Afficher le texte


► Afficher le texte
C'est en faisant des erreurs, que l'on apprend le mieux !!!

le Timer : TMR0 ,la suite
hoffmann
Membre
Membre
Messages : 11
Enregistré en : mai 2018

#2 Message par hoffmann » ven. 25 mai 2018 16:46

Jérémy a écrit :Source du message Comme on peut écrire sur notre Timer, on peut donc l’initialiser à 245 . alors quand il arrivera a 255 et lèvera son drapeau il se sera écoulé nos 10 secondes.
255-10 = 245 .



Pour être un chouilla plus précis, il y a deux possibilités pour que l'interruption se fasse :

Soit débordement (comme écris dans le tutoriel), soit le registre TMR0L = a ce qui se trouve dans le registre TMR0H.
(pas besoin de compter a rebours).

The Timer0 interrupt flag bit (TMR0IF) is set when
either of the following conditions occur:
• 8-bit TMR0L matches the TMR0H value
• 16-bit TMR0 rolls over from ‘FFFFh’

le Timer : TMR0 ,la suite
Jérémy
Administrateur du site
Administrateur du site
Messages : 2722
Âge : 44
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#3 Message par Jérémy » sam. 26 mai 2018 08:21

Bonjour hoffmann,

Ta précision est valable seulement sur certains PIC qui ont un Timer0 possible en 16-bit. Et encore je pense qu'il faille activée cette option car sinon il risque d'y avoir des collisions ? as tu la DS du PIC que tu viens de cité ?
C'est en faisant des erreurs, que l'on apprend le mieux !!!

le Timer : TMR0 ,la suite
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2586
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#4 Message par paulfjujo » sam. 26 mai 2018 11:11

bonjour,

hoffmann a écrit :
Jérémy a écrit :Source du message Comme on peut écrire sur notre Timer, on peut donc l’initialiser à 245 . alors quand il arrivera a 255 et lèvera son drapeau il se sera écoulé nos 10 secondes.
255-10 = 245 .



Pour être un chouilla plus précis, ....

certains MCU n'ont qu'un timer TMR0 sur 8 bits seulement .
de meme que le debordment en 16 bit se fait au passage 65535 à 65536 =>soit 0 en 16 bits
sur 8bits
256-10=246
Aide toi, le ciel ou FantasPic t'aidera


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 4 invités