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

Mesurer une suite de délais avec Timer5
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#1 Message par Superphénix » mar. 21 avr. 2020 01:40 lien vers la Data-Sheet : Cliquez ici

Bonjour

Je souhaite mesurer précisément (au moins au 2000ème près) le temps qui s'écoule entre les fronts descendants sur le pin RC0 d'un PIC16F1779. J'utilise déjà des interruptions pour 4 autres pins.
Ce que j'ai pensé faire c'est que ma fonction d'interruption teste en tout premier si l'interruption viens de RC0 et si oui, alors elle prends directement la valeur du Timer5 (16bits) pour l'envoyer vers une fonction qui fait la soustraction avec la valeur précédente. Et si non, elle teste si l'interruption vient des autres boutons pour renvoyer vers d'autres fonctions...
Les délais à mesurer entre deux fronts descendants feront entre approximativement 0.04 et 4 secondes. Et si jamais on dépasse environ 4s, alors le compteur doit être remis à 0 et le timer éteint jusqu'au prochain front descendant.

Est ce que c'est la meilleur méthode pour mesurer le temps dans mon cas ? Et quelle source d'horloge vaut t-il mieux choisir ?
Ne se pourrait t-il pas qu'après avoir lu TMR5L pile au moment où TMR5=0b1111111111111111, je lise TMR5H qui est en train de passer à 0b00000000 et que le résultat lu donne 0b0000000011111111 ?

Mesurer une suite de délais avec Timer5
satinas
Expert
Expert
Messages : 1225
Enregistré en : novembre 2015

#2 Message par satinas » mar. 21 avr. 2020 07:33 lien vers la Data-Sheet : Cliquez ici

Bonjour, tu chômes pas :)
Le mode capture du module CCP il sert pas à ça ? je le connais pas bien.
Le fait qu'il y ait plusieurs sources d'interruption et pas de réglage des priorités sur les 16F, rallonge le temps de prise en compte des événements, mais bon si on parle de ms cela devrait passer, mais pour le 2000ème (de quoi ?), c'est une autre histoire, tout dépend de ton horloge. L'oscillateur interne est moins précis qu'un quartz, la PLL monte à Fosc = 32MHz avec les deux.
Pour le timer 16 bits lu en 2 fois, j'ai rien vu dans le datasheet si ce n'est qu'il parle de ce problème. Tu peux faire 2 lectures de TMRH avec entre les deux la lecture de TMRL. Si TMRH a changé, TMRL doit être de faible valeur.
Dans l'exemple plus bas, si TMRH a changé ils font une nouvelle lecture complète.

https://www.google.fr/url?sa=t&rct=j&q= ... h20zCiybHs

Example 12-2: Reading a 16-bit Free-Running Timer

Code : Tout sélectionner

; All interrupts are disabled
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
MOVF TMR1H, W ; Read high byte
SUBWF TMPH, W ; Sub 1st read with 2nd read
BTFSC STATUS,Z ; Is result = 0
GOTO CONTINUE ; Good 16-bit read
;
; TMR1L may have rolled over between the read of the high and low bytes.
; Reading the high and low bytes now will read a good value.
;
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
; Re-enable the Interrupt (if required)
CONTINUE ; Continue with your code

Writing a 16-bit value to the 16-bit TMR1 register is straight forward. First the TMR1L register is
cleared to ensure that there are many Timer1 clock/oscillator cycles before there is a rollover into
the TMR1H register. The TMR1H register is then loaded, and finally the TMR1L register is loaded.
Example 12-3 shows this:
Example 12-3: Writing a 16-bit Free Running Timer

Code : Tout sélectionner

; All interrupts are disabled
CLRF TMR1L ; Clear Low byte, Ensures no
; rollover into TMR1H
MOVLW HI_BYTE ; Value to load into TMR1H
MOVWF TMR1H, F ; Write High byte
MOVLW LO_BYTE ; Value to load into TMR1L
MOVWF TMR1H, F ; Write Low byte
; Re-enable the Interrupt (if required)
CONTINUE ; Continue with your code

Sinon il existe des pic 16 bits, adapté au C, et très bons contre les maux de tête.

Mesurer une suite de délais avec Timer5
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 2616
Enregistré en : juillet 2016
Localisation : Terre

#3 Message par Temps-x » mar. 21 avr. 2020 15:38 lien vers la Data-Sheet : Cliquez ici

Bonjour Superphénix, satinas, et tout le forum,

Si tu veux de la précision sur les temps, il faut passer par ASM

:roll: paulfjujo avait raison : certains diront que 100% ASM est le summum.. ..

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

Mesurer une suite de délais avec Timer5
venom
Avatar de l’utilisateur
Confirmé
Confirmé
Messages : 960
Âge : 38
Enregistré en : avril 2016
Localisation : Klyntar
Contact :

#4 Message par venom » mar. 21 avr. 2020 21:01 lien vers la Data-Sheet : Cliquez ici

Salut a tous,

Sacré Temps-X. Toujours là pour glisser un petit "ASM" :wink: :lol:








@++
Mon site web
Mon discord : venom#4888

Mesurer une suite de délais avec Timer5
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#5 Message par Superphénix » mar. 21 avr. 2020 22:09 lien vers la Data-Sheet : Cliquez ici

Bonjour, tu chômes pas :)

Je profite du confinement ^^

Bon, j'ai passé toute la journée à lire la doc sur CCP, et le Timer1. Du coup j'ai déjà mieux compris tout ça et j'ai réglé quelques problèmes, dont la "lecture" de TMR1H/L que je vais bien faire avec le mode capture de CCP :)

Ce que j'ai écrit pour l'instant :

Code : Tout sélectionner

CCP2CAP = 0b00000000 ;   // RC0   ─┐
CCP2PPS = 0b00010000 ;   // xPPS <─┘
SSP2CON = 0b10000100 ;   // Capture sur front descendant.
TSCON   = 0b00110001 ;   // Tosc/4 , :1/8
T5GCON  = 0b00000000 ;   // GE=0
PIE4bits.TMR5IE = 1 ;    // Enable overflow interrupt

Ensuite j'ai prévu utiliser le interrupt flag généré par un overflow du Timer5 (TMR5IF) pour remettre le timer à 0 et éteindre le module, quand il ne se passe plus rien au bout du temps d'overflow.

Par contre j'arrive pas à trouver ce qui lie le bon CCPx au bon Timer. (CCP2 --> Timer5)

Le 2ème problème est qu'au maximum je peut mesurer des temps de 0.52s, alors qu'il me faudrait aller jusqu'à environ 4s. Je pourrais éventuellement régler le problème plus tard en utilisant un quartz de 500kHz au lieux du 4MHz. Pour le mode 32kHz j'ai trouver la tolérance dans la doc, elle n'est que de 1% (pas assez). Mais je me demande s'il n'y aurait pas une autre solution?

Sinon il existe des pic 16 bits, adapté au C, et très bons contre les maux de tête.

Pour l'instant j'ai pas l'intention de changer parce que dans les filtres de recherches de Microship c'était le seul PIC qui correspondait à ce que je cherchais, par contre c'est quoi un PIC adapté au C ?

Si tu veux de la précision sur les temps, il faut passer par ASM

Je sais, mais si je réapprends à utiliser l'ASM pour un programme aussi long j'y suis encore après le confinement, la 2ème vague de l'épidémie et la découverte de Sars cov 3 en 2035. :-D

Mesurer une suite de délais avec Timer5
satinas
Expert
Expert
Messages : 1225
Enregistré en : novembre 2015

#6 Message par satinas » mer. 22 avr. 2020 07:18 lien vers la Data-Sheet : Cliquez ici

Bonjour,

Dans le datasheet il y a beaucoup de choses, alors quand tu lis une info, bien vérifier à quoi elle correspond, quel chapitre. Par exemple SSP2CON (introuvable dans la doc) pourrait concerner le module MSSP qui permet de communiquer en SPI ou I2C, qu'est ce qu'il fait là ?.

Pour la compréhension le premier paragraphe décrivant une fonction est souvent bien résumé.
Le paragraphe 24.1 capture dit qu'elle utilise exclusivement le Timer 1, stocke TIM1H:L dans CCPRH:L dès qu'un front est détecté.
Au choix :
- Every edge (rising or falling)
- Every falling edge
- Every rising edge
- Every 4th rising edge
- Every 16th rising edge
Une fois le Timer 1 configuré avec Fosc/4, le réglage de la capture se fait avec CCPxCON et CCPxCAP, tout y est.
Ensuite on dispose de 2 flags d'interruption, celui de la capture et celui du timer overflow.

Pour les temps longs, tu peux compter le nombre d'overflow du Timer 1.
Je sais pas si Timer 1 est remis à 0 à chaque capture, je te laisse le découvrir :)
Avec un quartz de 4MHz, Tcap est à 1 us, c'est suffisant non ?
C'est 1/2000 de seconde ou 1/2000 de la valeur mesurée ?

Un langage évolué a besoin d'une ram linéaire intégrant la pile, de nombreux registres, et des instructions facilitant le passage d'arguments aux sous-programmes.
Les pic 8 bits n'ont rien de tout ça. La ram est paginée, un seul registre W, la pile ne stocke que les adresses de retour lors d'appels de sous-programmes, pas les arguments. Sur les modèles récents de 16F et 18F ils ont ajouté des instructions pour améliorer la situation.

Mesurer une suite de délais avec Timer5
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2597
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#7 Message par paulfjujo » mer. 22 avr. 2020 10:43 lien vers la Data-Sheet : Cliquez ici

Bonjour,

La capture CCP ayant un domaine de capture restreint ...

utilises -tu la pin RB0 ?
si RB0 Int est disponible pour capturer l'evenement qui t'interesse sur RC0 ( liaison hard RC0 -> RB0)
It RB0 sur front Montant =>

* déclencher TMRxON sur un timer 16 bits (TRM1 ?)
avec un compteur d'overflow (si multiple overflow prévus ), ou simplement le test du TRMxIF pour savoir si il faut rajouter 1x65536
* modifier interrupt RB0 pour pouvoir agir sur l'evenement front Descendanrt

sur evenement Front Descendant RB0 :
lecture du timer

Meme en C, via l'usage du comptage par timer , on arrive à une bonne résolution de mesure temporelle ..

:sifflotte: on a pas inventé le C pour rien ...

avec les 18F rescent, on ne se preoccupe plus du tout de la pagination des bank RAM ( en C)
(sauf si MikroC a des buggs !) contrairement au vieux 16F et le IRP_bit à gerer
oops ou si on veut y mettre un registre à decalage 96 bits en ASM
Aide toi, le ciel ou FantasPic t'aidera

Mesurer une suite de délais avec Timer5
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#8 Message par Superphénix » jeu. 23 avr. 2020 01:53 lien vers la Data-Sheet : Cliquez ici

SSP2CON (introuvable dans la doc)

Oups, faute de frappe, c'est : CCP2CON :sifflotte:

Le paragraphe 24.1 capture dit qu'elle utilise exclusivement le Timer 1, stocke TIM1H:L dans CCPRH:L dès qu'un front est détecté.

Hmm, je l'utilise déjà pour le mode PWM... A la page 275 il est marqué "All references to Timer1 and Timer1 Gate apply to Timer3 and Timer5." Du coup je me suis dit qu'à chaque fois que je vais rencontrer le mot "Timer1" je vais considérer que ça vaut pour mon Timer5. Et j'ai vu qu'il existe aussi CCPR2H:L, CCPR7H:L, CCPR8H:L. C'est pour ça que j'ai fini par me poser la question de comment lier un CCPRxH:L au bon Timer. :?:

Pour les temps longs, tu peux compter le nombre d'overflow du Timer 1.

Ok. Je vais faire comme ça.

Je sais pas si Timer 1 est remis à 0 à chaque capture, je te laisse le découvrir :)

J'ai cherché mais n'ayant rien trouvé je m'étais dit que j'allais le savoir en testant.

C'est 1/2000 de seconde ou 1/2000 de la valeur mesurée ?

C'est 1/2000 de la valeur mesuré. Selon mes calculs avec un préscalaire de 1:8 et sans pertes de temps j'ai 1/5000 pour un temps mesuré de 0.04s. Mais vue que je vais finalement faire la technique du comptage d'overflows je peut la remettre à 1:1. Donc 1/40000. Si on compte le temps perdu par la mise à 0 éventuelle après lecture de TIM1H:L, je ne sais pas où j'arrive mais ça devrait passer...

utilises -tu la pin RB0 ?

Oui, elle me sert pour autre chose déjà.

D'accord pour les PICs adaptés aux langages évolués.

Mesurer une suite de délais avec Timer5
satinas
Expert
Expert
Messages : 1225
Enregistré en : novembre 2015

#9 Message par satinas » jeu. 23 avr. 2020 06:58 lien vers la Data-Sheet : Cliquez ici

Bonjour,
Il doit pas le remettre à zéro le Timer 1, afin de pouvoir programmer plusieurs captures différentes.
En soustrayant les captures de type unsigned int, on obtient la bonne valeur, même si le timer a fait un overflow entre les deux.
unsigned int mesure = capture_2 - capture_1
c'est valable s'il y a 0 ou 1 overflow.
S'il peut y avoir plus d'1 overflow
unsigned long mesure = capture_2 - capture_1
if (nb_overflow) mesure += 65536UL * (nb_overflow - (capture_2 < capture_1))

En remettant à zéro le timer, on simplifie, mais la mesure est moins précise car ce reset n'est pas immédiat.
unsigned long mesure = 65536UL * nb_overflow + capture;

C'est une vraie bête de course ce pic. Et j'ai rien contre les 8 bits, hein
C'est quoi le sujet de demain, qu'on puisse se préparer à l'avance :-)

Mesurer une suite de délais avec Timer5
Superphénix
Débutant
Débutant
Messages : 54
Enregistré en : mars 2020

#10 Message par Superphénix » dim. 26 avr. 2020 03:10 lien vers la Data-Sheet : Cliquez ici

Bon, ça fait 2 jours que je suis bloqué, et je me rends compte maintenant que mon blocage est dû à une fonction d'affichage de nombres, créé il y a presque un mois et que j'utilise pour débuger, qui n'affiche pas correctement les valeurs supérieurs où = à 2^15. Du coup je ne peut pas encore répondre par rapport aux timer.
Il faut donc d’abord résoudre le problème de ma fonction d'affichage ^^

Code : Tout sélectionner

void AFF_NBERS(unsigned long nbr, char rng, char ali) // Nombre de 0 à 999999 ; Digit N°4 à N°27 ; Alignement 1 à 6 digits ou 'L' à gauche, 'R' à droite.
{
    unsigned char i=0, flag=0, DIG[6]={0, 0, 0, 0, 0, 0} ;
   
    DIG[0] = (nbr%1000000)/100000 ;   // Problème par ici ???
    DIG[1] = (nbr%100000)/10000 ;
    DIG[2] = (nbr%10000)/1000 ;
    DIG[3] = (nbr%1000)/100 ;
    DIG[4] = (nbr%100)/10 ;
    DIG[5] = nbr%10 ;
   
    if (ali=='L')
    for(i=0; i<6; i++)
    {
        if ((DIG[i]!=0)||(i==5)) flag = 1 ;
        if (flag==0) rng-- ;
        if (flag==1) DIGIT(rng+i, DIG[i]+48) ;  // La fonction DIGIT sert juste à afficher un chiffre entre 0 et 9 sur un digit de l'écran, et elle marche bien.
    }
   
    else if (ali=='R')
    {
        for(i=0; i<6; i++)
        {
            if (DIG[i]!=0) flag = 1 ;
            if ((flag==0)&&(i!=5)) DIG[i]=127 ;
        }
       
        for(i=0; i<6; i++) if(DIG[5-i]!=127) DIGIT(rng-i, DIG[5-i]+48) ;
    }
       
    else
    for(i=0; i<ali; i++) DIGIT(rng-i, DIG[5-i]+48) ;
}


Je pense que le problème vient du type de donné "unsigned long" que j'utilise pour mon nombre.
Normalement le unsigned long avec XC8 devrait faire 32 bits et donc permettre de monter jusqu'à 4,2Mrd. Là on dirait un signed int...
Quand mon nombre est supérieur à 2^15 l’affichage me donne un nombre très élevé qui commence par un 9.
Du coup je ne comprends pas :?: :?:


Retourner vers « Langage C »

Qui est en ligne

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