La routine de mesure  est le coeur du fréquencemètre. A chaque boucle du programme elle est appelée 2 fois:
- pour l’auto calibrage,
- pour la mesure réelle.

Description de la routine de mesure
La fréquence à mesurer est appliquée sur RA4/T0CKI. La routine est chargée de relever à chaque cycle le compteur TMR0. La représentation d’une fréquence  maximum de 50 MHz nécessite en binaire, 25 bits, il faut donc utiliser 4 compteurs  de 8 bits soit 32 bits. Comme TMR0   est limité à 8 bits, elle détecte le débordement de TMR0 en comparant sa valeur avec la valeur stockée au cycle précédent TMR0_old. Quand TMR0 < TMR0_old, elle reporte la retenue aux niveaux supérieurs. La durée d’un cycle de la routine de mesure est de 25 us avec un PIC 16F84 à 4 MHz. J’ai choisi cette durée qui est sous-multiple de 275 us, durée de l’auto calibrage, et de 500 ms durée de la mesure réelle.
Paramètres:
gateLow = nombre de cycles bas,
gateHigh = nombre de cycles haut,
Durée de la mesure = gateHigh x gateLow x 25us
Compteur Binary Frequency Counter = BFC3 (32 bits), BFC2, BFC1, BFC0 (LSB)
TMR0_old = valeur de TMR0 du cycle précédent, initialisée à zéro.

Auto calibrage
Il permet de régler le prescaler pour la mesure réelle. L’auto calibrage consiste à effectuer une mesure pendant 275us avec le prescaler = 256. A l’issue de cette mesure, nous obtenons dans le compteur BFC0 une approximation de la gamme de fréquence en MHz.
1 MHz x 275us / 256 = 1,07 => BFC0 = 1
2 MHz x 275us / 256 = 2,14 => BFC0 = 2
3 MHz x 275us / 256 = 3,22 => BFC0 = 3
…
10 MHz x 275us / 256 = 10,74 => BFC0 = 10

20 MHz x 275us / 256 = 21,48 => BFC0 = 21

50 MHz x 275us / 256 = 53,71 => BFC0 = 53
Remarque: compte-tenu de la durée de mesure de 275us et le la valeur du prescaler de 256, les fréquences <  1 x 256 / 275 soit 0,930908 MHz donneront BFC0 = 0.
Vous pouvez vérifier le résultat de l’auto calibrage sur l’afficheur. Dans le programme source rechercher la ligne ;#define    AUTORANGE_TEST. Cette ligne est inactivée en commentaire. Rendez cette ligne active. Ré assemblez et vérifiez en connectant au fréquencemètre un VFO par exemple.

Calcul du pré diviseur (prescaler PS)
Le calcul est effectué simplement en examinant le bit de poids fort de BFC0 de la façon suivante:
bit 7 = 1 | 128 à 255 MHz et au dessus inutilisé
bit 6 = 1 | 064 à 128 MHz inutilisé
bit 5 = 1 | 032 à 064 MHz | PS = 5 | 64:1
bit 4 = 1 | 016 à 032 MHz | PS = 4 | 32:1
bit 3 = 1 | 008 à 016 MHz | PS = 3 | 16:1
bit 2 = 1 | 004 à 008 MHz | PS = 2 | 8: 1
bit 1 = 1 | 002 à 004 MHz | PS = 1 | 4:1
bit 0 = 1 | 000 à 002 MHz | PS = 1 | 4:1
Remarque: je n’ai pas utilisé la valeur PS=0. En effet, lors de mes essais avec cette valeur, j’obtenais une mesure erronée que je ne m’explique pas. Si un lecteur à la solution je suis preneur!

Vérifions la mesure maximum possible pour chaque gamme de fréquence, pour une durée de mesure de 500 ms:
64 MHz = 64 000 000 x 0,5 / 64 = 500 000 =   07 A1 20 (16)
32 MHz = 32 000 000 x 0,5 / 32 = 500 000 =   07 A1 20 (16)
16 MHz = 16 000 000 x 0,5 / 16 = 500 000 =   07 A1 20 (16)
08 MHz = 08 000 000 x 0,5 / 08 = 500 000 =   07 A1 20 (16)
04 MHz = 04 000 000 x 0,5 / 04 = 500 000 =   07 A1 20 (16)

Mesure réelle
Après l’auto calibrage, la mesure réelle est faite pendant 500 ms. Le résultat est ensuite multiplié une première fois par 2 (simple décalage à gauche avec report du bit de retenu) pour obtenir une valeur rapportée à une seconde. Ce résultat et encore multiplié par 2, autant de fois que l’indique le prescaler pour obtenir la valeur définitive de la fréquence en Hz. A cette valeur est éventuellement ajoutée ou ôtée IF selon l’option MODE du setup. La valeur binaire obtenue et ensuite transformée en décimal codé binaire dans BCD9 (MSB) à BCD0 (LSB) puis affichée.

Limites et précision
Avec une durée de mesure de 500 ms, la plus petite fréquence mesurable serait théoriquement de 2 Hz. Toutefois avec PS minimum = 4, la fréquence minimum mesurable = 1 x 4 / 0.5 = 8 Hz.
Précision:
- gamme 04 MHz = 008 Hz,
- gamme 08 MHz = 016 Hz,
- gamme 16 MHz = 032 Hz,
- gamme 32 MHz = 064 Hz,
- gamme 64 MHz = 128 Hz.

Modification de la durée du cycle de base de la routine de mesure
Avec une fréquence d’horloge de 10 MHz la routine ne doit pas être modifiée. Vous pouvez modifier les paramètres gateLow et gateHigh pour obtenir une durée proche de 256 us pour l’auto calibrage et une durée exacte de 500 ms pour la mesure réelle. Ainsi avec un quartz de 10 MHz, si le cycle de base = 10 us au lieu de 25 us, vous pouvez choisir 26 x 10 us = 260 us (> 256 us) pour l’auto calibrage et 200 x 250 x 10 us = 500 000 us =  500 ms pour la mesure réelle.

Si cela n’est pas suffisant il faut adapter la routine. Pour cela il faut distinguer les instructions nécessaires et suffisantes de celles qui sont là pour faire perdre du temps (nop en général). Voici la formule du cycle de base de notre routine:
cycle de base = 4p + (10+a)np + (3+b)p(n-1) + 2p + (3+c)(p-1) + 2 + 3
où
n = gateLow,
p = gateHigh,
a = temps perdu,
b = temps perdu,
c = temps perdu,
Les valeurs fixes 4, 10, 2, 3 sont la durée des instructions nécessaires avec une horloge de 4 MHz.

Avec ces valeurs pour obtenir un cycle de base de 25 us, poser n = 1 et p = 1, il vient:
cycle de base = 25 us = 4 + (10 + a) + 0 + 2 + 0 + 2 + 3 => a = 4,
poser n = 2 et p = 1, il vient
2 cycles de base = 50 us = 4 + (10 + 4)2 + (3 + b)1 + 2 + 0 + 2 + 3 => b = 8,
poser n = 1 et p = 2, il vient
2 cycles de base = 50 us = 4×2 + (10 + 4)2 + 0 + 2×2 + (3+ c) + 2 + 3 => c = 2, d’où
cycle de base = 4p + (10+4)np + (3+8)p(n-1) + 2p + (3+2)(p-1) + 2 + 3.
C’est la formule qui est utilisée dans ce programme.
a est obtenu avec 4 instructions nop, b avec 8 nop, c avec un goto supplémentaire.

Supposons par exemple une fréquence d’ horloge qui diviserait par 4 la durée des instructions et un  cycle de base = 8 us, durée choisie car sous-multiple de 256 et 500000 qui peut être obtenu en faisant gateLow = 250 et gateHigh = 250 (chaque compteur est limité à 255).
Cycle de base = 8 us = p + (2.5 + a)np + (0.75 + b)p(n-1) + 0.5p + (0.75+c)(p-1) + 0.5 + 0.75,
avec n = 1 p = 1, il vient
cycle de base = 8us = 1 + (2.5 + a) + 0 + 0.5 + 0 + 0.5 + 0.75 => a = 2.75,
avec n = 2 et p = 1, il vient
2 cycles de base = 16 us = 1 +(2.5 + 2.75)2 + (0.75 + b) + 0.5 + 0 + 0.5 + 0.75 = b = 2,
avec n = 1 et p = 2, il vient
2 cycles de base = 16 us = 2 +(2.5 + 2.75)2 + 0 + 0.5×2 + (0.75+c) + 0.5 + 0.75 => c = 0.5, d’où
cycle de base = 8us = p + (2.5 + 2.75)np + (0.75 + 2)p(n-1) + 0.5p + (0.75+0.5)(p-1) + 0.5 + 0.75.
Avec ces valeurs pour l’auto calibrage = 256 us = 32 x 8 us, n = 32 et p = 1,  il vient
32 cycles de base = 1 + (2.5 + 2.75)32 + (0.75 + 2)31 + 0.5 + 0 + 0.5 + 0.75 = 256 us C.Q.F.D.
La mesure réelle = 500 ms = 62500 x 8 us, n = 250 et p = 250,  il vient
62500 cycles de base = 250 + (2.5 + 2.75)62500 + (0.75 + 2)250×249 + 0.5×250 + (0.75+0.5)249 + 0.5 + 0.75 = 500 000 us C.Q.F.D.
a pourrait être obtenu avec 11 nop, b avec 8 nop, c en laissant le même goto supplémentaire.

Dans le Debugger de MPLAB, il y a un excellent outil qui s’appelle StopWatch qui permet de connaître la durée exacte de notre routine. Indiquer au préalable la valeur de la fréquence horloge en choisissant Setting dans le menu du Debugger.

Ci-dessous la routine de mesure qui finalement contient peu d’instructions.

;********************************************************************************
; Parameters : gate time high = p, gate time low = n
; Gate time = 4p + (10+4)np + (3+8)p(n-1) + 2p + (3+2)(p-1) + 2 + 3
; One step = 25 us with XTAL = 4 MHz
; 275 us = 1 x 12 x 25 us => p = 1, n = 12
; 500 ms = 100 x 200 x 0.025 ms => p = 100, n = 200
;********************************************************************************
Measure
    BANK1
    movwf    OPTION_REG     ;
    BANK0
    clrf    BFC0-1         ; clear 16 bits counter
    clrf    BFC0-2         ; clear 24 bits counter
    clrf    BFC0-3         ; clear 32 bits counter

    bcf     PORTA,0x03
    movf    gateHigh,w
    movwf   countHigh
    clrf    TMR0_old
    clrf    TMR0
    COUNT_START    ; start count
M05 movfw   gateLow         ; |
    movwf   countLow        ; | = 4p
    goto    M20             ; |
M10 ; c
    goto M05                ; = 2(p-1)
    ; b = 8 nop
M15 nop                     ; |
    nop                     ; |
    nop                     ; |
    nop                     ; |  = 8p(n-1)
    nop                     ; |
    nop                     ; |
    nop                     ; |
    nop                     ; |

M20 movf    TMR0,w         ; TMR0 rollover ?    ; |
    subwf   TMR0_old,f     ; TMR0_old - TMR0    ; |
    btfss   STATUS,Z       ; 0 = no change      ; |
    goto    M25                                 ; |
    nop                                         ; |
    nop                                         ; |
    nop                                         ; |
    goto    M30                                 ; |
M25 btfsc   STATUS,C    ; TMR0 < TMR0_old ?     ; | = (10+4)np
    incf    BFC0-1,f    ; 16 bits counter       ; |
    btfsc   STATUS,Z                            ; |
    incf    BFC0-2,f    ; 24 bits counter       ; |
M30 movwf   TMR0_old                            ; |
    ; a = 4 nop
    nop                                         ; |
    nop                                         ; |
    nop                                         ; |
    nop                                         ; |

    decfsz  countLow,f          ; = 2p
    goto    M15                 ; = 3p(n-1)
    decfsz  countHigh,f         ; = 2
    goto    M10                 ; = 3(p-1)
    COUNT_STOP                  ; = 3
    ; last value
    movf    TMR0,w       ; test for TMR0 rollover
    movwf   BFC0         ; save 8 bits counter
    subwf   TMR0_old,f
    btfsc   STATUS,Z     ; rollover ?
    goto    M_35         ; no
    btfsc   STATUS,C
    incf    BFC0-1,f     ; 16 bits counter
    btfsc   STATUS,Z
    incf    BFC0-2,f     ; 24 bits counter
M_35
    retlw   0x00

Télécharger le fichier Kicad du schèma .
Télécharger les fichiers source et hexa du fréquencemètre .

Liens

Fréquencemètre à microcontrôleur PIC
Fréquencemètre à microcontrôleur PIC – Description
Fréquencemètre à microcontrôleur PIC – Structure du programme
Fréquencemètre à microcontrôleur PIC – Mesure
Fréquencemètre à microcontrôleur PIC – Commande de l’afficheur LCD
Fréquencemètre à microcontrôleur PIC – Réalisation