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

Utilisation du timer1/3/5 en mode asynchrone
unistereo
Membre
Membre
Messages : 5
Enregistré en : mars 2019

#1 Message par unistereo » mer. 6 mars 2019 12:23

Bonjour,

Ceci est mon premier post sur ce forum, alors permettez-moi de tous vous saluer bien bas.

Pour un premier post, j'arrive avec un problème :sifflotte:, ça commence bien.

Mais quelle meilleure façon de faire connaissance qu'en discutant le bout de gras autour d'un problème, n'est-ce pas ?

Alors voici ce qui m'amène ici : j'utilise actuellement un PIC16F1765 que je programme avec xc8, et avec lequel je veux mesurer la fréquence d'un signal sinusoidal (variant de 1 MHz à 10 MHz).

La méthode employée est assez classique : j'utilise le timer0 pour mesurer le temps qui s'écoule et, durant chaque seconde, j'utilise le timer3 en mode compteur pour compter le nombre d'impulsions sur une PIN d'entrée (T3CKI).

La raison pour laquelle j'utilise le timer3 plutôt que le timer1 est que j'utilise un crystal de 20 MHz pour la clock principale (ce qui monopolise les PINs d'entrée du timer1).

Le programme fonctionne selon mes attentes, mais jusqu'à un certain point seulement.
Concrètement, j'ai le résultat attendu entre 1 et 5 MHz (bon nombre d'impulsions comptées). Mais si j'augmente la fréquence du signal au delà de 5 MHz, le comptage d'impulsions reste le même qu'à 5 MHz, comme s'il était bloqué sur une valeur butoire.

Il ne m'a pas échappé que 5 MHz n'est rien d'autre que la fréquence de mon quartz (20 MHz) divisée par 4 (fosc/4), autrement dit le cycle d'instruction.

J'ai cependant bien configuré le timer3 en mode asynchrone pour que le comptage ne soit justement pas limité par la clock d'instruction.

Dans la datasheet on trouve les valeurs limites pour les périodes des clocks externes du timer1/3/5 (voir paramètres 45 à 47 de la table 36-12 en page 499).
On y lit qu'en mode asynchrone la période minimale du signal est de 60 ns, autrement dit 16.6MHz.
De ce point de vue là la fréquence de mon signal à mesurer entre donc dans les spécifications.

En résumé, malgré l'utilisation du mode asynchrone, le comptage semble être artificiellement limité à la clock d'instruction.

Y aurait-il un élément qui m'aurait échappé ?

Merci d'avance pour vos réponses !

Ci-dessous le code source:

Code : Tout sélectionner

// CONFIG1
// Use 20 MHz crystal oscillator
#pragma config FOSC = HS        // Oscillator Selection Bits (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover Mode (Internal/External Switchover Mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit cannot be cleared once it is set by software)
#pragma config ZCD = OFF        // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR)
#pragma config PLLEN = OFF      // Phase Lock Loop enable (4x PLL is enabled when software sets the SPLLEN bit)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#include <xc.h>
#include <stdint.h>

#include "pic16f1765.h"

#define OSCILLATOR_CLOCK_FREQ        20000000UL
#define INSTRUCTION_FREQ             (OSCILLATOR_CLOCK_FREQ / 4UL)
#define TIMER0_OVERFLOW_EVERY        256UL
#define MEASUREMENT_DURATION_SECONDS 1UL
#define PRESCALER_VALUE              256UL
#define NB_TIMER0_LOOPS              (MEASUREMENT_DURATION_SECONDS * INSTRUCTION_FREQ) / (TIMER0_OVERFLOW_EVERY * PRESCALER_VALUE)
// With 20 MHz crystal, NB_TIMER0_LOOPS = 76.29394531

unsigned short volatile timer0LoopCounter;
unsigned short volatile timer3OverflowCounter;
unsigned long volatile  nbPulsesSeen;
unsigned char volatile  newMeasurementHasBeenDone;

static void __interrupt irqHandler(void)
{
    if (PIR4bits.TMR3IF == 1)
    {
        // Timer 3 overflow       
        PIR4bits.TMR3IF = 0; // Clear Timer 3 overflow bit
       
        ++timer3OverflowCounter;
    }
    if (INTCONbits.T0IF == 1)
    {
        // Timer0 overflow
       
        INTCONbits.T0IF = 0; // Clear Timer0 overflow bit
       
        timer0LoopCounter--;

        if (timer0LoopCounter==0)
        {
           
            // We are at the end of the measurement period
            LATCbits.LATC0 = !LATCbits.LATC0;     
           
            // Disable timer3 (while we fetch the value)
            T3CONbits.TMR3ON = 0;
           
            // Compute number of pulses seen on PIN RC5 during the measurement duration
            nbPulsesSeen = (((unsigned long)timer3OverflowCounter) << 16) + (unsigned long)TMR3;
                               
            // Set the flag that tells that a new measurement has been made
            newMeasurementHasBeenDone = 1;
           
            // Re-initialize timer0 loop counter
            timer0LoopCounter = NB_TIMER0_LOOPS;
           
            // Clear number of timer3 overflows
            timer3OverflowCounter = 0;       
           
            // Re-enable timer 3
            T3CONbits.TMR3ON = 1;           
        }           
    }

}

void test()
{

    while (1)
    {
        if (newMeasurementHasBeenDone)
        {
            // nbPulsesSeen is a 24-bit value, scale it to 10 bits (shift it right of 14 bits)
            unsigned int tmp = nbPulsesSeen >> 14;
           
            // output value on DAC
            DAC1REFH = tmp >> 8;
            DAC1REFL = tmp & 0xFF;
            DACLDbits.DAC1LD = 1;           

            newMeasurementHasBeenDone = 0;
        }
    }
}

void Setup()
{
    // No interrupts
    INTCON = 0b00000000;
 
    // LED setup on RC0 (pin #10)
    TRISCbits.TRISC0 = 0; // Set PIN RCO as output
    LATCbits.LATC0   = 0; // Set RC0 output low

    // LED setup on RC1 (pin #9)
    TRISCbits.TRISC1 = 0; // Set PIN RC1 as output
    LATCbits.LATC1   = 0; // Set RC1 output low
   
    // Clock : External Crystal, 20 MHz
    // + Turn off Internal Clock
    OSCCONbits.SPLLEN =   0; // 4x PLL Disabled
    OSCCONbits.IRCF   = 0x0; // LF Oscillator (unused)
    OSCCONbits.SCS    =   0; // Clock determined by FOSC<2:0> in Config Words
           
    // Setup DAC (DAC1CON0)
    DAC1CON0bits.EN      = 1; // Enable DAC
    DAC1CON0bits.FM      = 0; // Reference is right justified
    DAC1CON0bits.OE1     = 1; // Output on pin DAC1OUT1 is enabled
    DAC1CON0bits.PSS     = 0; // Positive Source is VDD (+5V)
    DAC1CON0bits.NSS0    = 0; // Negative Source is VSS (Ground)
    // Clear initial DAC output value
    DAC1REFH = 0;
    DAC1REFL = 0;     

    // Configure timer0
    OPTION_REGbits.TMR0CS =     0; // Set Timer0 in timing mode (source=instruction clock)   
    OPTION_REGbits.PS     = 0b111; // 1:256 pre-scaler
    OPTION_REGbits.PSA    =     0; // Assign pre-scaler to timer 0

    // Configure timer3
    T3GCONbits.T3GE       =     0; // Disable Gate Control
    T3CONbits.CS          =  0b10; // Timer1 Clock Source = external clock source
    T3CONbits.CKPS        =     0; // No Pre-scaler
    T3CONbits.SYNC        =     1; // Do NOT synchronize on system clock
   
    timer0LoopCounter     = NB_TIMER0_LOOPS; // Initialize timer0 loop counter
    timer3OverflowCounter = 0;           // Initialize timer3 overflow counter
     
    // Start timer 0
    TMR0                  =     0; // Reset timer0 counter value
    INTCONbits.TMR0IE     =     1; // Enable Timer0 Overflow interrupt
    INTCONbits.GIE        =     1; // Enable all interrupts     

    // Start timer3
    TMR3                  =     0; // Reset timer3 counter value
    INTCONbits.PEIE       =     1; // Enable peripheral interrupts
    T3CONbits.TMR3ON      =     1; // Timer3 Enabled
}

void main() {
    Setup();
   
    test();
}

Utilisation du timer1/3/5 en mode asynchrone
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 1164
Enregistré en : juillet 2016
Localisation : Terre

#2 Message par Temps-x » mer. 6 mars 2019 19:58

Bonsoir unistereo, et tout le forum,

Soit le bienvenue sur le forum, et j'espère que tu y passeras des bons moment comme nous,

Bon unistereo, je fais pas du xc8, mais ASM comme notre ami Gérard :langue:

J'ai déjà écrit un programme pour fréquencemètre ou tu peux retrouvé le début ICI

Si je peux me permettre, ta méthode est la bonne, mais elle est trop encombrante, regarde mon explication ICI

Tu peux compter de 1Hz à 50Mhz, d'après Microchip, tu peux aussi aller voir sur le cite de paulfjujo ICI

==> A++
Modifié en dernier par Temps-x le jeu. 7 mars 2019 01:39, modifié 2 fois.
Quand la souris nargue le chat, c'est que son trou n'est pas loin.

Utilisation du timer1/3/5 en mode asynchrone
unistereo
Membre
Membre
Messages : 5
Enregistré en : mars 2019

#3 Message par unistereo » mer. 6 mars 2019 20:59

Bonsoir Temps-x,

Merci beaucoup d'avoir pris le temps de me répondre.

Oui c'est programmé en C mais je comprends l'assembleur aussi, pas de souci !

J'ai bien regardé le code source du fréquence-mètre que tu donnes en lien (joli code assembleur, au passage).

En fait nos méthodes sont relativement identiques dans le sens où c'est aussi le timer1 qui est utilisé en mode asynchrone pour compter les impulsions (j'utilise le timer3 qui est une réplique du timer1).

La principale différence entre nos deux programmes est que de mon côté j'utilise le timer0 (avec interruptions) pour mesurer le temps qui s'écoule alors que de ton côté tu utilises des boucles d'attente actives (avec durées d'exécution fixes) pour effectuer ce même travail.

Mais donc, pour la partie comptage des impulsions proprement dite, j'ai envie de dire que nos méthodes sont plus proches que différentes.

Je me suis notamment attardé dans la portion de code qui configure le timer1 et je ne constate pas de différence notable entre nos deux façons de le configurer (dans la mesure où l'on puisse comparer les registres T1CON d'un PIC16F628 et PIC16F1765).

Tout cela pour dire que, j'ai le sentiment que si je transposais ton programme au PIC16F1765, je tomberai exactement sur le même problème que je rencontre, en considérant que la méthode de comptage est pour ainsi dire la même. Mais je peux me tromper bien évidemment.

Par contre, il se trouve que j'ai aussi des PIC16F628 sous la main. Une option serait que je transpose mon programme C sur ce PIC et regarde si j'observe le même phénomène ou pas. Ca devrait être plus facile dans ce sens là en ce qui me concerne. Je crois que je vais essayer cela, et viendrai faire un compte rendu.

Je te remercie encore pour ces pistes d'investigations !

Utilisation du timer1/3/5 en mode asynchrone
Temps-x
Avatar de l’utilisateur
Expert
Expert
Messages : 1164
Enregistré en : juillet 2016
Localisation : Terre

#4 Message par Temps-x » jeu. 7 mars 2019 02:19

Bonjour unistereo, et tout le forum,

Pour info le pic utilisé est un Pic16F628A, mais je peux recompiler le programme pour un Pic16F628 pour
que tu puisses voir le résultat.

unistereo a écrit :Source du message J'ai bien regardé le code source du fréquence-mètre que tu donnes en lien


Depuis j'ai optimisé le code, en plus du fréquencemètre, il possède un PWM réglable de 0% à 100%, suffit d'appuyer sur un bouton
pour basculer du fréquencemètre au PWM qui est de 10000Hz, qui est bien utile pour faire des essais.

unistereo a écrit :Source du message j'ai envie de dire que nos méthodes sont plus proches que différentes.


Ton timer risque de ne pas tourner à bonne vitesse pour des fréquences haute, ce qui expliquerais les erreurs.

Sur mon fréquencemètre je n'ai pas de problème, il mesure bien la vitesse de mon Quartz qui est de approximativement très proche
de 4Mhz, idem pour des fréquences plus élevé comme 20Mhz.

A voir si le xc8 gère la microseconde, ou nanoseconde, qui est indispensable pour ce projet, comme je suis allergique au C
je ne peux pas t'aider, mais il y a des spécialistes du C ici.

Juste un conseille, essai déjà avec des temporisations très précise, on te servant d'un seule timer

==> A++
Quand la souris nargue le chat, c'est que son trou n'est pas loin.

Utilisation du timer1/3/5 en mode asynchrone
unistereo
Membre
Membre
Messages : 5
Enregistré en : mars 2019

#5 Message par unistereo » ven. 8 mars 2019 16:12

Bonjour,

J’ai converti mon programme au PIC16F628A (en fait c’est celui que j’avais en stock). L’adaptation a été rapide, les différences sont que j’utilise l’oscillateur interne sur 4 MHz plutôt que le quartz, et que j’utilse le timer1 plutôt que le timer3 (qui n’existe pas sur ce chip).

Et le résultat est ... similaire à mon problème d’origine !

Si ce n’est qu’au lieu de plafonner à 5 MHz je plafonne maintenant à ... 1 MHz. Ce qui correspond de nouveau à Fosc/4. Fascinant, non ?

Bin, je continue l’investigation ...

Utilisation du timer1/3/5 en mode asynchrone
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 1293
Âge : 68
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#6 Message par paulfjujo » ven. 8 mars 2019 17:46

bonsoir


voir si il n'y aurait pas une ERRATA datasheet
sur le sens du bit
T3CONbits.SYNC = 1; // Do NOT synchronize on system clock
en logique negative ?
as-tu essayer en le mettant à 0 ?

voir aussi avec la GATE ...
Aides toi, le ciel ou Fantastpic t'aideras

Utilisation du timer1/3/5 en mode asynchrone
unistereo
Membre
Membre
Messages : 5
Enregistré en : mars 2019

#7 Message par unistereo » lun. 11 mars 2019 14:55

Bonjour,

Bon, j'ai trouvé !

J'ai relu 40 fois toutes les docs que j'avais, jusqu'à m'en user les yeux, et j'ai finalement fini par trouver ce qui coincait.

Je vous préviens, c'est très bête.

Alors juste pour rappeler comment se configure la bête, pour utiliser le timer1(/3/5) avec interruptions, il faut (dans le désordre):
  • activer le timer1 (T1CON.ON = 1)
  • activer les interruptions du timer1 (PIE1.TMR1IE = 1)
  • autoriser les interruptions périphériques (INTCON.PEIE = 1)
  • activer le flag global d'interruptions (INTCON.GIE = 1)

Eh ben dans cette liste il me manquait le deuxième point, l'activation des interruptions spécifiquement pour le timer1.

Ce qui m'a induit en erreur pendant longtemps, c'est que dans le code de mon handler d'interruption (qui gère à la fois les interruptions du timer0 et du timer1), je rentrais bien dans le premier bloc "if":

Code : Tout sélectionner

static void __interrupt irqHandler(void)
{
    if (PIR1bits.TMR1IF == 1)
    {
        // Timer 1 overflow       

        ........ more code ..........
    }
    if (INTCONbits.T0IF == 1)
    {     
        // Timer0 overflow
       
        ........ more code ..........
    }   
}


Le premier bloc "if" lit le flag d'overflow du timer1. En principe, si le flag est à 1, c'est parce que le timer1 a débordé et que l''interruption du timer1 vient d'être levée, n'est-ce pas ?

Eh bien, pas forcément !

En fait, il se trouvait que j'arrivais dans mon handler par les interruptions du timer0 uniquement (alors que j'aurais du y entrer également via les interruptions du timer1).
Le flag de débordement du timer1 avait été positionné (parce qu'il avait effectivement débordé) mais aucune interruption n'avait été levée à ce moment là !

Donc en fait, ce qui passait est que je ratais tous les débordement de mon timer1...ce qui fait que mon comptage devenait inexact dès que la fréquence de mon signal d'entrée augmentait au delà d'un certain point... CQFD.

Voilà voilà. Donc c'est assez bête, une vraie erreur de débutant. Rien que pour cela je mérite de devoir utiliser un PIC16F84 jusqu'à la fin de mes jours :cry:

Et pour épiloguer j'arrive donc maintenant à correctement mesurer le nombre d'impulsions de mon signal d'entrée. Testé jusque 10 MHz qui est la limite de mon générateur de signal. Donc je suis content ;)

Merci en tout cas pour vos réponses, cela m'a donné la force de persévérer dans cette quête.

NB: bien que mon problème d'origine concernait le timer3, j'ai transposé les explications au timer1 pour faciliter la lecture.

Utilisation du timer1/3/5 en mode asynchrone
unistereo
Membre
Membre
Messages : 5
Enregistré en : mars 2019

#8 Message par unistereo » lun. 11 mars 2019 15:08

paulfjujo a écrit :voir si il n'y aurait pas une ERRATA datasheet


Merci pour cette suggestion je suis effectivement allé voir l'ERRATA, parce qu'il paraît que pour certains PICs c'est un passage obligé !

L'errata du PIC16F1765 est étonnamment assez succinct.

Visiblement, il ne souffre pas trop d'erreurs de jeunesse. Soit ça, soit personne ne s'en est encore servi :lol:

Merci en tout cas, je prendrai maintenant l'habitude de consulter ce document en plus de la datasheet...

Utilisation du timer1/3/5 en mode asynchrone
Jérémy
Administrateur du site
Administrateur du site
Messages : 2311
Âge : 40
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#9 Message par Jérémy » lun. 11 mars 2019 15:10

Bonjour à tous ,

Merci unistereo de ce retour d'informations très intéressantes , qui en sauveras peut être plus d'un ! Ta pugnacité a payer et tu as raison d'être content et fier de toi .
unistereo a écrit :Source du message Merci en tout cas pour vos réponses, cela m'a donné la force de persévérer dans cette quête.

Le forum Fantas-Pic est la pour ça . des fois en écrivant un message de demande d'aide et en vérifiant mes sources , je trouve par moi même le réponse sans avoir la posée la question. C'est m'est arrivé pas mal de fois.

:bravo:
C'est en faisant des erreurs, que l'on apprend le mieux !!!


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité