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 , ç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();
}