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 ---
Forum général sur le langage C !

Modérateur : Jérémy

Mesure de temps avec un Timer
Simlock
Membre
Membre
Messages : 21
Enregistré en : mai 2016
Localisation : Sur mon siege

#1 Message par Simlock » mar. 7 mars 2017 16:43 lien vers la Data-Sheet : Cliquez ici

Bonjour !

Je souhaite mesurer la durée d'un état haut avec un PIC16f886 et son Timer. Je rencontre quelques soucis d'imprécision et je voulais donc avoir vos avis et expériences.

J'utilise un Quarz 20Mhz.

Tout simplement, ma boucle principale est composé de :

Code : Tout sélectionner


while 
(1)
    {
        ms      = 0;
        TMR1H    = 0x00;
        TMR1L    = 0x00;

        PORTAbits.RA1 = 1;
        T1CON   = 0x01; // Start timer
        
        for 
(i=; i<30000 ; i++)
        {
            for (j=; j<60 ; j++)
            {
                if (TMR1IF)
                {
                    TMR1IF = 0;
                    ms++;
                }
            }
        }
        PORTAbits.RA1 = 0;
        T1CON   = 0x00; // Stop timer

        SYS_CalculRetard (ms);
    }
 


Et pour calculer la durée :

Code : Tout sélectionner


void SYS_CalculRetard 
(unsigned int millisecond)
{
    unsigned int timer  = 0;
    unsigned int us     = 0;
    unsigned int ms     = 0;
    
    
    us 
= millisecond * (535/5);
    ms = (millisecond * (65/5)) + (us / 1000);
    us = us % 1000;
    
    
    
    timer 
= ((TMR1H << 8) + TMR1L);
    timer /= 5;
    
    us 
= us + (timer % 1000);
    ms = ms + (timer / 1000) + (us / 1000);
    us %= 1000;
    
    millisecond 
= 0;
}


Pour des petits délais je n'ai pas de soucis, j'arrive à avoir une précision qui se rapproche de la microseconde mais dès que je passe au seconde... c'est pas la même.

Exemple pour ce code :
A l'aide d'un analyseur logique avec un taux d’échantillonnage de 4MHz : voir Mesure1.png
Le programme lui me retourne ms = 6252 et us = 478



Maintenant, j'augmente la durée de mon état haut avec

Code : Tout sélectionner

for (j=; j<80 ; j++) 

A l'aide d'un analyseur logique avec un taux d’échantillonnage de 4MHz : voir Mesure2.png
Le programme lui me retourne ms = 8227 et us = 97


Plus le delai est grand et plus l’imprécision est grande mais trop grande je trouve (je m'attendais à quelques centaine de us voir une milliseconde).

Est ce que mon calcul est efficace ? Un soucis avec l'oscillateur ou normal ? Merci !
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Modifié en dernier par Simlock le mer. 8 mars 2017 09:43, modifié 1 fois.

Mesure de temps avec un Timer
Jérémy
Administrateur du site
Administrateur du site
Messages : 2722
Âge : 44
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#2 Message par Jérémy » mar. 7 mars 2017 17:15 lien vers la Data-Sheet : Cliquez ici

SAlut Simlock,

JE te propose de mettre un lien de la Data-sheet de ton PIC ! (procédure) .

Je pense que c'est ton programme qui ne va pas : Il te faut travailler avec des Interruptions si tu veux de la précision, sinon c'est mort !

La tout de suite j'ai pas trop le temps ! peut être ce soir .

A+
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Mesure de temps avec un Timer
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 » mar. 7 mars 2017 18:20 lien vers la Data-Sheet : Cliquez ici

re, sur le trajet du retour à la maison j'ai pensé à ton histoire !

Il faut absolument que tu passes par une Interruption pour compter . Comme on ne sait pas la précision que tu souhaite partons sur 1ms .
Ensuite tu nous montre le réglage de ton OSCillateur pour obtenir une Interruption toutes les millisecondes .
A chaque interruption tu incrémente ton compteur de ms .

En l'état ton programme est très imprécis, voir bug carrément ! ( sauf si il n'est pas entier).

Tu as un super outils plutôt pratique pour régler ton OSC . : Timer calculator , mais c'est plus enrichissant de tout calculer avant , et de vérifier après avec !
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Mesure de temps avec un Timer
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 2595
Enregistré en : juillet 2016
Localisation : Terre

#4 Message par Temps-x » mer. 8 mars 2017 00:54 lien vers la Data-Sheet : Cliquez ici

Bonjour Simlock, Jérémy, et bonjour à tous,

Quel Timer utilises tu, je dirais que c'est le Timer1, peux tu le confimer ?

Timer0
Timer1
Timer2

C'est normal d'avoir une imprécision, sur un temps de quelque seconde, car il faut tenir compte du débordement de ton Timer
soustraire la différence, qui est multiplier par le nombre de débordement.

Quelle est le temps que tu veux mesurer, mini, et maxi .

Il y a peut être une autre solution, y a tu réfléchis ?

A+
:roll: Les requins, c'est comme le langage ASM, c'est le sommet de la chaîne alimentaire. :wink:

Mesure de temps avec un Timer
Simlock
Membre
Membre
Messages : 21
Enregistré en : mai 2016
Localisation : Sur mon siege

#5 Message par Simlock » mer. 8 mars 2017 10:36 lien vers la Data-Sheet : Cliquez ici

Bonjour Jérémy et Temps-x,

Merci pour votre aide.

Je souhaite maximum une précision de 5ms, je ne m'inquiète pas beaucoup c'est relativement lent pour un PIC. Mais je voulais m'amuser un peu et voir si je pouvais atteindre une précision de l'ordre de la microseconde :langue:

Pourquoi mon programme buggerait ? Je n'ai pas mis tout mon programme, je pensais que ces petits bouts suffiraient. La grosse boucle qu'il y a dans mon programme est juste là pour maintenir une broche à l'état haut et comparer ensuite la mesure du programme avec ce que je vois avec l'analyseur logique.

Configuration de l'horloge :

Code : Tout sélectionner

#pragma config FOSC = HS
OSCCON = 0x70; // Sert à rien vu que j'utilise l'oscillateur externe à 20MHz
OSCTUNE = 0x00;
 


Je pensais pouvoir me passer des interruptions puisque lorsque le timer 1 atteint le maximum de son registre, il reset en levant le flag TMR1IF donc il me suffit juste d'incrémenter une variable pour dire lors de mon calcul final "attention ! il y a eu déjà x 65535 tick". Mais le registre, lui, continue de tourner et s'incrémenter. Le seul débordement que j'aurai serait le temps que j'arrête le timer ?

Par contre, si je joue avec l'interruption, cela veut dire que lorsqu'il y en a une, je dois :
    - Aller dans la fonction à exécuter en cas d'interruption (géré par le compilateur soit)
    - Reset le flag
    - Reconfigurer le registre TMR1H et TMR1L de sorte que l'interruption s'effectue en 1us (par exemple)
    - Incrementer mes variables de mesure.
Il y a un jeu d'instruction énorme si je veux être précis alors que si je laisse juste le timer s'incrémenter tout seul, j'ai juste à l'arrêter et lire combien de coup d'horloge il a effectué ?

J'espère que j'ai été clair et que je ne dis pas n'importe quoi :lol:

Mesure de temps avec un Timer
Jérémy
Administrateur du site
Administrateur du site
Messages : 2722
Âge : 44
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#6 Message par Jérémy » mer. 8 mars 2017 19:55 lien vers la Data-Sheet : Cliquez ici

Hello,

J'avoue ne pas comprendre ta méthode !

Tu es donc obligé d'imposer un temps de comptage, je suppose que ce sont tes boucle qui font cela ! Achauqe fois que tu incremente ton ms, en fait il s'est écoulé 13.107ms .

Moi j'aurais fait comme ceci, mais je suis pas très calé

Tu tourne à 20Mhz ! on divise par 4 car il faut 4 coup d'horloge pour exécuter une instruction . ce qui fait 5 000 000 d'instructions par secondes. soit 0.2µs par instructions.

Tu compte le nombre d'instructions effectues et tu multiplie par 0.2µs . Un truc du genre

Tu lance ton Timer préalablement remis à zéro . Il te suffit donc de compter le nombre d'instruction obtenu durant le laps de temps .
A chaque débordement du timer tu as eu donc 65535 instructions de passées.
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Mesure de temps avec un Timer
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 2595
Enregistré en : juillet 2016
Localisation : Terre

#7 Message par Temps-x » jeu. 9 mars 2017 01:41 lien vers la Data-Sheet : Cliquez ici

Bonjour Simlock, et Jérémy, et bonjour à tous,

Je souhaite maximum une précision de 5ms


C'est une précision que tu veux, ou un temps, car 5ms(5000µs) c'est largement faisable, sans passer par les diviseurs.

Avec le Timer1 (65535 /5)/1000 =13,107 ms

Comme je fais de l'assembleur, qui est mon langage de programmation, voici comment je fais :

Code : Tout sélectionner



remonte
       btfss PORTA
,1                            ; est ce que RA1 est à l'état haut
       goto remonte                             ; non RA1 n'
est pas à l'état haut
                                               ; oui, RA1 est à l'
état haut                    

      clrf TMR1L                                  
; remis à zéro de TMR1L
      clrf TMR1H                                 
; remis à zéro de TMR1H

      bsf T1CON
,TMR1ON                        ; lancer le timer1            
       
boucle
       btfsc PORTA
,1                            ; est ce que RA1 est à l'état bas
       goto boucle                               ; non, RA1 n'
est pas à l'état bas
                                                      ; oui, RA1 est à l'
état bas

      bcf T1CON
,TMR1ON                    ; arrêt du timer1




Après on récupère la valeur de TMR1H, et TMR1L, normalement, il faudrait contrôler si le Timer1 à débordé


A+
:roll: Les requins, c'est comme le langage ASM, c'est le sommet de la chaîne alimentaire. :wink:

Mesure de temps avec un Timer
Simlock
Membre
Membre
Messages : 21
Enregistré en : mai 2016
Localisation : Sur mon siege

#8 Message par Simlock » ven. 10 mars 2017 11:02 lien vers la Data-Sheet : Cliquez ici

Bonjour,

Jérémy a écrit :Tu tourne à 20Mhz ! on divise par 4 car il faut 4 coup d'horloge pour exécuter une instruction . ce qui fait 5 000 000 d'instructions par secondes. soit 0.2µs par instructions.

Tu compte le nombre d'instructions effectues et tu multiplie par 0.2µs . Un truc du genre

Ok... regarde mon programme et tu vas voir que je le fait déjà. Multiplier par 0.2 revient à diviser par 5.

Désolé si j'ai pas très bien expliqué mon problème mais je crois que vous n'avez pas compris. Je ne demande pas un programme pour mesurer une durée, ça je l'ai déjà et il fonctionne, j'ai même mis des images. Je demande pourquoi j'ai une aussi grosse imprécision.


Je reviens à mon premier post.

Pour la première mesure, l'analyseur logique trouve 6 253 110us et mon programme mesure 6 252 478us soit un écart de 632us.
Pour la seconde mesure, l'analyseur logique trouve 8 293 471us et mon programme mesure 8 227 097us soit un écart de 66 374us.

Je précise que pour une dizaine de milliseconde, j'ai une précision à la microseconde !

J'ai donc résolu mon problème pour la seconde mesure, je reposte mon code avec une correction mineure sur le nom des variables pour éviter toute confusion (millisecond remplacé par overflow car plus logique) :

Code : Tout sélectionner



void SYS_CalculRetard 
(unsigned int overflow)
{
    unsigned int timer  = 0;
    unsigned int us     = 0;
    unsigned int ms     = 0;
    
    us 
= overflow * (535/5);
    ms = (overflow * (65/5)) + (us / 1000);
    us = us % 1000;
    
    
    timer 
= ((TMR1H << 8) + TMR1L);
    timer /= 5;
    
    us 
= us + (timer % 1000);
    ms = ms + (timer / 1000) + (us / 1000);
    us %= 1000;
}

Le PIC ici peux maximum contenir une variable de 16bits soit 65 535. Or si ma variable overflow dépasse 612, je sors donc des capacités du PIC et ma variable revient à 0 et je rate donc 65 535us d'ou mon écart brusque plus haut. (613 * (535/5) = 613 * 107 = 65591)

Donc pour revenir au sujet de base, j'ai donc maintenant :
Pour la première mesure, l'analyseur logique trouve 6 253 110us et mon programme mesure 6 252 478us soit un écart de 632us.
Pour la nouvelle mesure, l'analyseur logique trouve 9 313 553us et mon programme mesure 9 312 710us soit un écart de 842us.

Pourquoi j'ai ce décalage et comment puis-je faire pour améliorer ça ?

Merci pour votre aide et votre patience ^^

Mesure de temps avec un Timer
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2589
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#9 Message par paulfjujo » ven. 10 mars 2017 17:43 lien vers la Data-Sheet : Cliquez ici

bonjour Simlock,




Code : Tout sélectionner


unsigned lond TuS
=0;
 unsigned int timer=0;
 float f1;
 
 
......
 
 
 while 
(1)
   {
   TuS=0;
   overflow     = 0;
        TMR1H    = 0x00;
        TMR1L    = 0x00;

        PORTAbits.RA1 = 1;
        T1CON   = 0x01; // Start timer
        
        for 
(i=; i<30000 ; i++)
        {
            for (j=; j<60 ; j++)
            {
                if (TMR1IF)
                {
                    TMR1IF = 0;
                    overflow++;
                }
            }
        }
        T1CON   = 0x00; // Stop timer
        PORTAbits.RA1 = 0;
         Tus=(unsigned long)overflow <<16;
        timer = ((TMR1H << 8) + TMR1L);
        TuS=Tus + timer;              // <- en cycles
        f1= (float)Tus * 0.2;      // en µSec
    } 



Les division par 5 sur des entiers .... ça laisse toujours des restes .. donc des inexactitudes
si tu testes dans un premier temps le comptage en cycles ...
et utilises ta calculette pour diviser par 5 ..
ou la valeur de f1 !

ou prend un quartz de 16MHz ..plus de probleme d'arrondi !
Aide toi, le ciel ou FantasPic t'aidera

Mesure de temps avec un Timer
Simlock
Membre
Membre
Messages : 21
Enregistré en : mai 2016
Localisation : Sur mon siege

#10 Message par Simlock » lun. 13 mars 2017 09:56 lien vers la Data-Sheet : Cliquez ici

Merci paulfjujo, déjà tu me simplifies beaucoup le calcul car je ne savais pas que "unsigned long" permettait de stocker un nombre sur 32bits. Je pensais que ce n'était pas possible sur in PIC16F. :-)

J'ai donc essayé avec un Quartz 16MHz et donc sur une attente de 11 641 733us j'obtient dans le programme 11 641 067us. Soit 666us de différence.
Je pense que c'est l'imprécision de l'oscillateur et que je ne peux faire autrement. A moins d'acheter THE quartz super précis et qui ne dévie jamais...

En tout cas c'est bien plus précis que ce que je dois faire à la base :lol:

Merci pour l'aide apportée, j'ai appris quelques subtilités sur le chemin mais si vous avez d'autres suggestion sur l'imprécision je suis preneur.


Retourner vers « Langage C »

Qui est en ligne

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