Bonjour à tous !
Je suis nouveau sur ce forum et débutant en électronique, alors merci d'avance pour votre indulgence !
Pour me lancer dans la programmation des microcontrôleurs, je me suis procuré un PIC16f887 et un MPLAB ICD2. Ce choix n'est le fruit ni d'un endoctrinement ni d'une réflexion, c'est de la récup' ! Je code en C et j'utilise le compilo HI-TECH Lite.
Bref, comme je suis batteur dans mes heures perdues, j'ai choisi comme premier projet de réaliser un métronome. Classique, me direz-vous, et vous aurez raison ! Voici le petit programme de développement que je me suis fixé :
1/ Dans un premier temps, je veux pouvoir régler "en dur" une pulsation et afficher cette pulsation sur une diode
2/ Ajouter un réglage de la pulsation avec une résistance ajustable et un affichage de la pulsation sur 3x7 segments par exemple
3/ Je veux ajouter une fonction 'tapping' avec un bouton poussoir qui permet de taper une pulsation et d'en déterminer la valeur (fonction inverse en quelque sorte)
4/ réaliser une communication avec mon PC et un petit logiciel pour contrôler tout ça en usb (j'ai récupéré une petit carte DLP - USB232M)
Voilà le programme ! Évidemment je coince sur le 1 !
Voici mon problème : j'ai choisi de faire le comptage des pulsations avec le Timer1 (16bit). J'ai gardé la valeur par défaut de Fosc à 4 MHz, le Timer1 utilise Fosc/4, et j'ai gardé le prescaler à 1. Au début de mon programme, je calcule combien de fois il va falloir remplir mes deux registres TMR1H et TMR1L, et quelle sera le point de départ du dernier remplissage, pour allumer ma diode au tempo choisi. Par exemple pour une pulsation X en bpm : (60bpm=1bps=1Hz),
Ainsi on fait Timer1NbCycles cycles complets plus un cycle avec comme point de départ Timer1LastCycleStart. A la fin de ces Timer1NbCycles+1 cycles, j'utilise le Timer0 pour générer un allumage de la diode qui ressemble un peu à une impulsion.Code:Timer1NbCycles =(int)(4.0e6/4.0/1.0*60.0/(float)X/65536.0); Timer1LastCycleStart=65536-((int)(4.0e6/4.0*60.0/(float)X)%(65536));
Tout cela semblait très bien fonctionner jusqu'à ce que je prenne successivement ma montre, mon téléphone et l'horloge parlante pour me rendre compte que lorsque je commande 60 bpm (i.e. 1 pulsation = 1s) mon métronome bat en réalité à 55 bpm, ce qui n'est évidemment pas du tout acceptable pour mon application.
Je vous mets le code complet :
Est-il possible que cette erreur soit liée à la pulsation réelle de Fosc qui ne serait pas exactement à 4MHz ? Y a-t-il quelque chose d'incorrect dans mon code ?Code:#include <htc.h> unsigned short cnt = 0 ; unsigned int targetBeat = 0; unsigned int Timer1LastCycleStart = 0b0000000000000000; unsigned short Timer1NbCycles = 0 ; //GESTION DES INTERRUPTIONS void interrupt interruptions(void) { // Interruption du Timer1 if (TMR1IF) { if (cnt==Timer1NbCycles){ TMR1H = Timer1LastCycleStart>>8 ; // On met Timer1 à la valeur initiale calculée TMR1L = Timer1LastCycleStart-TMR1H<<8 ; } if (cnt==Timer1NbCycles+1){ RD2 = 1 ; cnt = 0 ; TMR0 = 0 ; } cnt++; TMR1IF = 0 ; // Réinitialisation du flag d'interruption du timer1 } // Interruption du Timer0 if (T0IF){ if(RD2){ RD2 = 0 ; // Exctinction de la diode } T0IF = 0 ; // Réinitialisation du flag d'interruption du timer0 } } //PROCEDURE D'INITALISATION void init(void) { // Paramètres de l'oscillateur interne IRCF2 = 1 ; // Sélection de la fréquence en sortie du post-scaler de l'oscillateur interne IRCF1 = 1 ; IRCF0 = 0 ; SCS = 1 ; // Sélection de l'oscillateur interne comme horloge TUN4 = 0 ; // Fine-tuning de la fréquence de l'oscillo interne TUN3 = 0 ; //(on garde la valeur par défaut) TUN2 = 0 ; TUN1 = 0 ; TUN0 = 0 ; // Activation des interruptions GIE = 1 ; // Activation des interruptions générales (registre INTCON) PEIE = 1 ; // Activation des interruptions de périphériques externes (registre INTCON) // Diode en sortie sur RD2 TRISD2 = 0 ; RD2 = 0 ; // Initialisation du timer0; T0CS = 0 ; // Oscillateur externe (1) / Interne Fosc/4 (0) PSA = 0 ; // Assignation du prescaler à Timer0 plutôt qu'au Watchdog PS2 = 1 ; // Prescaler à 16 (011) PS1 = 0 ; PS0 = 1 ; T0IE = 1 ; // Activation des interruptions sur Timer0 TMR0 = 0 ; // RAZ du Timer0 T0IF = 0 ; // Flag d'interruption du Timer0 // Initialisation du timer1; TMR1CS = 0 ; // Oscillateur externe (1) / Interne Fosc/4 (0) T1OSCEN = 0 ; // Oscillateur 32768 Hz activé (1) / désactivé (0) T1CKPS1 = 0 ; // Prescaler à 1 (00) / 2 (01) / 4 (10) / 8 (11) T1CKPS0 = 0 ; T1SYNC = 0 ; // Synchronisation activée (0) / désactivée (1) TMR1IE = 1 ; // Activation des interruptions sur Timer1 TMR1ON = 0 ; // Timer1 éteint TMR1H = 0 ; // RAZ du Timer1 TMR1L = 0 ; TMR1IF = 0 ; // Flag d'interruption du Timer1 } void Timer1Param(int beat) { Timer1NbCycles =(int)(4.0e6/4.0*60.0/(float)beat/65536.0); Timer1LastCycleStart=65536-((int)(4.0e6/4.0*60.0/(float)beat)%(65536)); } void Timer1Start(void) { TMR1H = 0b00000000 ; TMR1L = 0b00000000 ; TMR1ON = 1 ; TMR1IF = 0 ; // Flag d'interruption du Timer } // PROGRAMME PRINCIPAL void main() { // Initialisation init(); targetBeat = 60; Timer1Param(targetBeat); RD2 = 1 ; Timer1Start(); // Boucle principale while(1) { } }
Merci de votre lecture et de votre intérêt !
KorkXx.
-----