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

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2589
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#31 Message par paulfjujo » lun. 26 oct. 2015 20:35

Proposition precedente testée en reel
sur ma platine Pickit 44 Pin Demo board equipée d'un 16F887 (mais sans quartz)
J'ai activé l'UART pour avoir une sortie sur ecran
J'injecte un signal connu sur RB0 via "ma petite boite à quartz" ..

J'ai quand meme sorti les calculs en flottants du traitement 'interrupt.. leur place est plutot dans le main program.
une tempo de 500mS dans la boucle ne gene en rien .

il suffit de desactiver le #define MyDemoboard pour eviter tout le code relatif à l'UART ..
et retrouver ton code à peine modifié.
n'ayant que les 8 leds du port D .. rien sur PORTC
et c'est tellement plus "parlant" avec sortie sur ecran.
avec FOSC=8MHZ .. j'ai 1µS au au lieu de 0,4


Code : Tout sélectionner



#define MyDemoBoard
#define Version "26/10/2015"
//Hardware :
// carte Microchip PICkit2 44 pin demo board
// PIC16F887
// 8 leds sur PORTD
// switch sur RB0
// module bluetooth
//     RC6 -->--RXD HC06
//     RC7 --<--TXD HC06

#define POWER_SUPPLY_5V
#define FOSC 8  // MHz
#define BAUD 9600  // UART1    vers module BT HC06


  //-- commandes terminal VT220
#define CLS 12     // effacement de page sur Terminal VBRAY
#define CR 13
#define VT 10
#define LF 10
#define TAB 9
#define Bell 7
#define Byte unsigned char

#ifdef MyDemoBoard
//  pinout settings
sbit LD7 at RD7_bit;
sbit LD6 at RD6_bit;
sbit LD5 at RD5_bit;
sbit LD4 at RD4_bit;
sbit LD3 at RD3_bit;
sbit LD2 at RD2_bit;
sbit LD1 at RD1_bit;
sbit LD0 at RD0_bit;

sbit SW1 at RB0_bit ;

 //           12345678901234567890
const char chaine0[]="16F877 Card 44 pin: Test Freq measure on RB0 \r\n ";
const char chaine1[]="FOSC interne 8MHZ  Port COM 96000 \r\n";
//const char chaine2[]="PROJET MikroC :16F887_test_Freqmeter_RBO_TMR0.mcppi\r\n";
const char *RS_Str[]={chaine0,chaine1};//,chaine2};

char TEXTE[80];
char CRam1[20];
char *txt;
char *p1;
//char c1;
unsigned int i,j,k;
//unsigned char cpt1, cpt2 ,cpt3 ;
////unsigned long T1;
unsigned long Freq;
#endif

//initialisation et declaration des variables utilisés
int test=1;// variable pour savoir si premier ou second front montant pour mesure de la periode
unsigned int dep=0;
long temps=0;
float periode=0;
float f1;
unsigned int  frequence;

//---------------------------------ROUTINE D INTERRUPTION--------------------------------
//#pragma origin 0x4  // <- ??
void interrupt(void)   // a chaque interruption sur rbo/int calcul debut et fin de periode
{
        // --- RB0 interrupt ---
          if((INTF_bit==1) && (INTE_bit==1))
           {
                 if(test==1)
                 {
                     TMR0=0;
                     test=2;
                     INTF_bit=0;
                 }
                 if(test==2)
                 {
// si temps est un int .. limite à +32767  -32768  .. debordement si dep>127
//avec  un unsigned int .. 0 à 65535 .. déja mieux
// ou avec un entier long .. tranquille !
                     temps=(long) TMR0+ (long)dep * 256;
                     test=1;
                     INTF_bit=0;
                     T0IF_bit=0;
                     dep=0;
                     
                  
}
             }
        // timer0 interrupt
           if(( T0IF_bit==1) && (T0IE_bit==1))
             {
                     dep=dep+1;
                     T0IF_bit=0;
             }
}

 #ifdef MyDemoBoard
 // --- Copie le texte depuis FLASH ROM vers RAM
void strConstRamCpy(unsigned char *dest, const code char *source)
 {
  while (*source)*dest++ = *source++ ;
  *dest = 0 ;    // terminateur
}

void CRLF()
{
 UART1_Write(CR);
 UART1_Write(LF);
}

void UART1_Write_CText(const char *txt)
 {
   while (*txt)
      UART1_Write(*txt++);
}

#endif


//-------------------------------Fonction principale------------------------------
// affichage de la frequence mesuré , sur port c et portd
void main()
{
      #ifdef MyDemoBoard
      //Oscillateur_Interne car pas de Quartz !
       OSCCON=0b01110001 ; // 8MHz (111) & SCS=1  (sinon 4 MHz par defaut)
       Delay_ms(1000);
       TRISC=0x80;     // car RC7 =entree UART !
       #else
       TRISC=0x00;
       #endif
       
       TRISD
=0;
       TRISB.B0=1; // rbo en entree su microcontrolleur

       ANSEL = 0;
       ANSELH = 0;
       PORTD=0;
       PORTC=0;
       test=1;

       OPTION_REG = 0xC0;  //bit7-> RBPU=1 (off), bit6 -> INTEDG=1 (front montant)
                         //bit5-> T0CS=0 (fosc/4), bit4-> TOSE=0
                         //bit3-> PSA=0 (prescaler timer0), bit<3:0> 000 -> timer0 rate 1:2
                         // => OPTION_REG=0b11000000=0xC0
                         // temps entre deux cycles avec ces parametres =0.4 microsecondes  at 20MHz
  //------------------------------
  #ifdef MyDemoBoard
    Freq = Clock_kHz();
    LongWordToStr(Freq, txt) ;
    if (Freq < 8001) 
    
{
      UART1_Init(9600);  // Fosc=8MHz
      }
        else
        
{
           UART1_Init(19200);  // Q=20Mhz
    }
    txt=&TEXTE[0];    // init pointeur
    UART1_Write(CLS);  // efface ecran terminal VBRAY
    CRLF();
    Delay_ms(1000);
    UART1_Write_CText("16F877 Card 44 pin: Test Freq measure on RB0 \r\n ");
    UART1_Write_CText("FOSC interne 8MHZ  Port COM 96000 \r\n");
    UART1_Write_CText("Start Version : "Version"\r\n");
  #endif
  // -----------------------
  
    PEIE_bit
=1;
    INTE_bit=1;
    INTF_bit=0;
    T0IE_bit=1;
    T0IF_bit=0;
    GIE_bit=1;

       for(;;)
       {
      #ifdef MyDemoBoard
       txt=&TEXTE[0];
       UART1_Write_CText("Mesure de Raw Freq= ");
       periode=(float) temps ;
       f1=1000000.0/periode;
       frequence=(unsigned int)f1; // pour affichage sur leds  en Hz  ex: 249
       WordToStr(frequence,txt);
       UART1_Write_Text(txt);
       UART1_Write(TAB);
        UART1_Write_CText("Periode= ");
        FloatToStr(periode,txt);
       UART1_Write_Text(txt);
       UART1_Write(TAB);
        UART1_Write_CText("Frequence= ");
        FloatToStr(f1,txt);
         UART1_Write_Text(txt);
       CRLF();
       Delay_ms(1000);  // on ralenti tout çà pour mieux visualiser surr l'ecran
       // PORTC = frequence >> 8;  // port non disponible !!
       PORTD = frequence & 0x00FF;
       #else
           periode=(float)temps *4.0 ;
           f1=10000000.0/periode;
           frequence=(unsigned int)f1;
           
           PORTD 
= frequence & 0x00FF;         // On envoie les 8 bits de points faibles sur le port D
           PORTC = frequence >> 8;    //pour faire apparaitre les 8 bits de poids fort restant sur le PORTC
      #endif
   
       
}
}



resultat sur ecran

resultat terminal VBRAY

20:18:53.265> 16F877 Card 44 pin: Test Freq measure on RB0
20:18:53.328> FOSC interne 8MHZ Port COM 96000
20:18:53.328> Start Version : 26/10/2015
20:18:53.390> Mesure de Raw Freq= 65535 Periode= 0 Frequence= 6.805639e38
20:18:54.640> Mesure de Raw Freq= 4 Periode= 205316.9 Frequence= 4.870517
20:18:55.828> Mesure de Raw Freq= 4 Periode= 205316.9 Frequence= 4.870517
20:18:57.015> Mesure de Raw Freq= 4 Periode= 205316.9 Frequence= 4.870517
20:18:58.265> Mesure de Raw Freq= 4 Periode= 205316.9 Frequence= 4.870517
20:18:59.453> Mesure de Raw Freq= 4 Periode= 205316.9 Frequence= 4.870517
20:19:00.640> Mesure de Raw Freq= 9 Periode= 102660.9 Frequence= 9.740797
20:19:01.828> Mesure de Raw Freq= 9 Periode= 102660.9 Frequence= 9.740797
20:19:03.078> Mesure de Raw Freq= 9 Periode= 102660.9 Frequence= 9.740797
20:19:04.265> Mesure de Raw Freq= 19 Periode= 51204.99 Frequence= 19.52934
20:19:05.453> Mesure de Raw Freq= 19 Periode= 51204.99 Frequence= 19.52934
20:19:06.703> Mesure de Raw Freq= 19 Periode= 51204.99 Frequence= 19.52934
20:19:07.890> Mesure de Raw Freq= 10 Periode= 99332.99 Frequence= 10.06714
20:19:09.078> Mesure de Raw Freq= 39 Periode= 25604.99 Frequence= 39.05487
20:19:10.328> Mesure de Raw Freq= 39 Periode= 25604.99 Frequence= 39.05487
20:19:11.515> Mesure de Raw Freq= 39 Periode= 25604.99 Frequence= 39.05487
20:19:12.703> Mesure de Raw Freq= 39 Periode= 25604.99 Frequence= 39.05487
20:19:13.953> Mesure de Raw Freq= 78 Periode= 12804.99 Frequence= 78.09448
20:19:15.140> Mesure de Raw Freq= 78 Periode= 12804.99 Frequence= 78.09448
20:19:16.328> Mesure de Raw Freq= 78 Periode= 12804.99 Frequence= 78.09448
20:19:17.578> Mesure de Raw Freq= 162 Periode= 6148.999 Frequence= 162.628
20:19:18.765> Mesure de Raw Freq= 162 Periode= 6148.999 Frequence= 162.628
20:19:20.015> Mesure de Raw Freq= 162 Periode= 6148.999 Frequence= 162.628
20:19:21.203> Mesure de Raw Freq= 162 Periode= 6148.999 Frequence= 162.628
20:19:22.390> Mesure de Raw Freq= 324 Periode= 3076.999 Frequence= 324.9918
20:19:23.640> Mesure de Raw Freq= 324 Periode= 3076.999 Frequence= 324.9918
20:19:24.890> Mesure de Raw Freq= 324 Periode= 3076.999 Frequence= 324.9918
20:19:26.078> Mesure de Raw Freq= 324 Periode= 3076.999 Frequence= 324.9918
20:19:27.328> Mesure de Raw Freq= 648 Periode= 1540.999 Frequence= 648.9292
20:19:28.578> Mesure de Raw Freq= 648 Periode= 1540.999 Frequence= 648.9292
20:19:29.828> Mesure de Raw Freq= 648 Periode= 1540.999 Frequence= 648.9292
20:19:31.078> Mesure de Raw Freq= 648 Periode= 1540.999 Frequence= 648.9292
Aide toi, le ciel ou FantasPic t'aidera

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
adrienc45
Débutant
Débutant
Messages : 27
Enregistré en : octobre 2015

#32 Message par adrienc45 » mar. 27 oct. 2015 19:45

paulfjujo a écrit :
adrienc45 a écrit :.... methode consistant a mesurer le nombre d incrementations de TMR0 et ses depassements ,
la valeur de la periode min est limite par le pas d incrementation du TMR0 et la valeur max de periode
limité par la taille des variables que j utilise non ?


OUI !


Je rapelle qu ' une precision sur la mesure de frequence au hertz pres m est largement satisfaisant .


OK , mais tu veux mesurer en dessous de 10Hz ...


nota: on ne touche pas au GIE_bit dans les interruptions..
c'est automatique
une amelioration (combinée à une bonne habitude ) constituerait à tester aussi le bit
Enable interrupt vu que tu en as deja 2 .
et dans un programme ( plus important) les interrupts ne sont pas forcement validees en meme temps.

toujours à propose de la taille des variables et le melange dans les calculs

Code : Tout sélectionner

//initialisation et declaration des variables utilisés
int test=1;// variable pour savoir si premier ou second front montant pour mesure de la periode
int dep=0;
//int temps=0;
long temps=0;
float periode=0;
float f1;
unsigend int  frequence;
int fr=0;

//-------------------------------Fonction principale------------------------------
// affichage de la frequence mesuré , sur port c et portd
void main()
{
     
    
       TRISD
=0;
       TRISC=0;
       TRISB.B0=1; // rbo en entree su microcontrolleur

        ANSEL = 0;
        ANSELH = 0;


       OPTION_REG = 0xC0;  //bit7-> RBPU=1 (off), bit6 -> INTEDG=1 (front montant)
                         //bit5-> T0CS=0 (fosc/4), bit4-> TOSE=0
                         //bit3-> PSA=0 (prescaler timer0), bit<3:0> 000 -> timer0 rate 1:2
                         // => OPTION_REG=0b11000000=0xC0
                         // temps entre deux cycles avec ces parametres =0.4 microsecondes

 
       PEIE_bit
=1;
       INTE_bit=1;
       INTF_bit=0;
       T0IE_bit=1;
       T0IF_bit=0;
        GIE_bit=1;
       
       for
(;;)
       {
              PORTD = frequence & 0x00FF;         // On envoie les 8 bits de points faibles sur le port D
              PORTC = frequence >> 8;    // On fait un décalage des 8 bits de poids faibles pour faire apparaitre 
                                                    //les 8 bits de poids fort restant sur le PORTC
       }

}

//---------------------------------ROUTINE D INTERRUPTION--------------------------------
#pragma origin 0x4  // <- ??
void interrupt(void)   // a chaque interruption sur rbo/int calcul debut et fin de periode
{
                   if((INTF_bit==1) && (INTE_bit==1))
                  {
                                if(test==1)
                                {
                                          TMR0=0;
                                          test=2;
                                          INTF_bit=0;
                                }
                                if(test==2)
                                {
                                         
// si temps est un int .. limite à +32767  -32768  ..risque de  debordement si dep>126
//avec  un unsigned int .. 0 à 65535 .. déja mieux
// ou avec un entier long .. tranquille pour ensuite descendre en frequence  !
                                              temps=(long) TMR0+ (long)dep * 256;
                                          periode=(float) temps  *4.0 ;
                                          f1=10000000.0/periode;  // pour eventuel affichage  decimal ex: 49,53Hz
                                          frequence=(unsigned int)f1; // pour affichage sur leds  en Hz  ex: 49
                                           test=1;
                                           dep=0;
                                          INTF_bit=0;
                                          

                                
}
                  }
                  if(( T0IF_bit==1) && (T0IE_bit==1))
                  {             
                                dep
=dep+1;
                                T0IF_bit=0;
                  }

}


Bonsoir

je vais donc pouvoir utiliser ce code proposé et corrigé au final ?

en sortie j aurais plus mes leds mais juste un return de ma valeur que j affiche actuellement sur des leds ..( le fait d aller chercher la valeur de fréquence mesurée continuellement par l interruption sera le cœur d un de mes sous programmes )

en le simulant sur proteus sa as l air de fonctionner correctement mais manque de précision

par exemple si on applique un signal 400 Hz --> le programme mesure 443 Hz
///////////////////////////////200 Hz --> le programme mesure 212 Hz
///////////////////////////////100 Hz --> le programme mesure 102 Hz
///////////////////////////////50 Hz --> le programme mesure 50 Hz

ou alors proteus qui déconne ? ( je vois que mon cpu est au moins a 75 % que je simule donc peut être des erreurs due a des latences ? )

possible de le corriger pour arriver a une précision au hertz près sur au moins la plage de mesure 0/500 hz ?
cela est due au temps que prend les interruptions de dépassement de tmr0 a s exécuter ce qui modifie la période réelle mesurée ?

sinon au final même si j utilise des long au lieu des float pour être sure , y as pas de ralentissement notable du programme en comparaison de si j utilisais que des float ( y as quand même double de taille des donnés a traiter donc c est pour cela que je pose la question même si ça parait peut être idiot a l échelle du temps ) ??

dernière question : l interruption ne ralentit pas notablement mon programme principal même si celle ci as lieu a moment régulier a l entrée du microcontrôleur ? ( car le signal applique quand a lui arrive tout le temps depuis l allumage jus qu ' a l éteinte du circuit qui contient le microcontrôleur )


je tenais a vous remercier encore car j ai appris pas mal de choses ici , surtout le fait d assimiler le fonctionnement des interruptions " a peu prés " ( je dis bien car loin d être expert en la matière )

en attendant vos reponses , bon appetit Merci ! +1

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2589
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#33 Message par paulfjujo » mer. 28 oct. 2015 12:04

bonjour

par exemple si on applique un signal 400 Hz --> le programme mesure 443 Hz
///////////////////////////////200 Hz --> le programme mesure 212 Hz
///////////////////////////////100 Hz --> le programme mesure 102 Hz
///////////////////////////////50 Hz --> le programme mesure 50 Hz

ou alors proteus qui déconne ? ( je vois que mon cpu est au moins a 75 % que je simule donc peut être des erreurs due a des latences ? )

possible de le corriger pour arriver a une précision au hertz près sur au moins la plage de mesure 0/500 hz ?
cela est due au temps que prend les interruptions de dépassement de tmr0 a s exécuter ce qui modifie la période réelle mesurée ?

sinon au final même si j utilise des long au lieu des float pour être sure , y as pas de ralentissement notable du programme en comparaison de si j utilisais que des float ( y as quand même double de taille des donnés a traiter donc c est pour cela que je pose la question même si ça parait peut être idiot a l échelle du temps ) ??


Plus la frequence augmente et moins la mesure est precise,
puisque avec ce mode de mesure Periode, on introduit un offset permanent qui est
La Latence de sauvegarde et restitution de contexte Avant et apres l'interrupt qui devient non negligeable par rapport
aux nombre de counts accumules dans Tmr0
Ecart temporel A l'instant T du front RB0 .. et la mise à zero timer0 effective
meme si le parrallellisme de traitement compensse partiellement cet effet .



Action premiere:
On peut deplacer les calculs en flottants, dispencieux en instructions,
dans le main program... :oops: c'est d'ailleur une erreur de mapart de l'avoir proposé dans l'interrupt !

Code : Tout sélectionner

// --- RB0 interrupt ---
      if((INTF_bit==1) && (INTE_bit==1))
      {
          if(test==1)
            {
              TMR0=0;
                 test=2;
                 INTF_bit=0;
                
            
}
            if(test==2)
            {
                 temps=(long) TMR0+ (long)dep * 256;
                test=1;
                INTF_bit=0;
                T0IF_bit=0;
                dep=0;
            }
       }
      // timer0 interrupt
       if(( T0IF_bit==1) && (T0IE_bit==1))
       {
                dep=dep+1;
                T0IF_bit=0;
        }

// main programme
do
{
          periode=(float)temps *4.0 ;
           f1=10000000.0/periode;
           frequence=(unsigned int)f1;
           PORTD = frequence & 0x00FF;         // On envoie les 8 bits de points faibles sur le port D
           PORTC = frequence >> 8;    //pour faire apparaitre les 8 bits de poids fort restant sur le PORTC
           GIE_bit=1;
     
}while(1);
 


Pour les frequences hautes, il faut passer en mode Frequence metre .
ou utiliser le mode CCP .. tres similaire ,mais qui gere automatiquent le compteur associé.
voir 6.9 ECCP Capture/Compare Time Base Datasheet 16F887
et de plus, sur les pic evolués genre 18F26K22, permet le comptage sur 1 à 16 fronts cumulés du signal.
L'usage du timer1 , 16 bits permet un prescaler 1/1 => à 20MHz => 0,2µS (au lieu de 0,4)
et debordement 256x fois moins frequent !
Aide toi, le ciel ou FantasPic t'aidera

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
adrienc45
Débutant
Débutant
Messages : 27
Enregistré en : octobre 2015

#34 Message par adrienc45 » mer. 28 oct. 2015 12:22

qu appelles tu fréquences hautes ?

merci de ta réponse

j avais pensé aussi sortir le calcul de l interruption
comme ça sans la routine on met que la capture du tmr0 et du dep
et dans la main , quand on en as besoin , on va chercher cette capture et le dep et on fait tout le reste du calcul , sa évite un nombres considérables d opérations inutiles effectivement

moi j utilise un pic 16f887 , je sais pas si on peut le considéré comme évolué , mais il suffit a mon application , c est déjà ça

donc si je veux conserver cette méthode la , que puis je faire pour réduire l incertitude en sortie , cité dans mon précédent message ?

autre question :

quand dans le code on écrit :

Code : Tout sélectionner

frequence=(unsigned int)f1


sachant que l on as déclare

Code : Tout sélectionner

float f1

Code : Tout sélectionner

unsigend int  frequence


cela as pour but de transformer f1 qui est un float , en un unsigned int pour qu on puisse ensuite mettre la valeur dans fréquence ? c est bien çà ?


en attendant , bon appétit a tous ! ;)

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2589
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#35 Message par paulfjujo » mer. 28 oct. 2015 20:42

bonsoir,

cela as pour but de transformer f1 qui est un float , en un unsigned int pour qu on puisse ensuite mettre la valeur dans fréquence ? c est bien çà ?


OUI !

version avec usage de CCP1
l'entree frequence est alors la pin RC2
TMR1 est capturé entre 2 fronts montant ( voir plus !)
Vu le domaine de frequnece relativement bas, cet exemple repose sur FOSC=8MHz (modifiable ! à 20Mhz)
un prescaler de 4 est utilisé sur timer1 ..
La frequence minimale mesurable est ~9Hz , maxi >625 à +-1Hz pres .. ensuite se degrade vite..
à cause de la diminution de resolution : 3hz par count à 1250Hz !

J'ai essayé de jouer sur les debordement du timer1 pour les frequence le splus basses .. :oops: sans succes.!
mais le resultat global est quand meme plus precis

On est face à un probleme de dynamique de reglage ..
une astuce à utiliser serait de faire une mesure de frequence classique sur 1 sec , et suivant la veleur
mesurée, basculer ensuite sur un nombre de "Edges capturées ( 1,2,4,16 ) adequates pour refaire une mesure de periode
dans les meilleurs conditions de comptage timer1.
(pour les tres basses frequences).

nota: utilisant le FOSC interne du PIC, il se peut qu'une partie d'erreur soit due à la frequence
legerement differente de 8 MHz
action sur OSCTUNE ?
C'est surement plus precis avec un quartz à +- 50ppm


28/10/2015
resultat terminal VBRAY

Consigne 1250 Hz Delta temps= 401 f1= 1246.882 Frequence= 1246 ADC0= 384
consigne 625,9 Hz Delta temps= 803 f1= 622.6649 Frequence= 622 ADC0= 384
consigne 312,5 Hz Delta temps= 1605 f1= 311.5264 Frequence= 311 ADC0= 384
consigne 156,27Hz Delta temps= 3210 f1= 155.7632 Frequence= 155 ADC0= 385
conigne 78,1245Hz Delta temps= 6422 f1= 77.85736 Frequence= 77 ADC0= 384
consigne 19,543 Hz Delta temps= 25691 f1= 19.46206 Frequence= 19 ADC0= 385
consigne 9,766 Hz Delta temps= 51377 f1= 9.73198 Frequence= 9 ADC0= 384



le source
(enlever toute la partie UART et ADC !)
c'est juste pour montrer que le MCU peut faire plusieurs chose à la fois
Ce code est naturellement perfectible , à vos clavier et critiques ..

Code : Tout sélectionner




#define MyDemoBoard
#define Version "27/10/2015"
//Hardware :
// PICKIT2 pour alimenter la carte
// carte Microchip PICkit2 44 pin demo board avec PIC16F887
// 8 leds sur PORTD <--valeur EA0>>2
// switch sur RB0 ou entree Frequ à mesurer
// module bluetooth
//     RC6 -->--RXD HC06
//     RC7 --<--TXD HC06

#define POWER_SUPPLY_5V
#define FOSC 8  // MHz
#define BAUD 9600  // UART1    vers module BT HC06
 //ac:proto_freq

  //-- commandes terminal VT220
#define CLS 12     // effacement de page sur Terminal VBRAY
#define CR 13
#define VT 10
#define LF 10
#define TAB 9
#define Bell 7
#define Byte unsigned char

#ifdef MyDemoBoard
//  pinout settings
sbit LD7 at RD7_bit;
sbit LD6 at RD6_bit;
sbit LD5 at RD5_bit;
sbit LD4 at RD4_bit;
sbit LD3 at RD3_bit;
sbit LD2 at RD2_bit;
sbit LD1 at RD1_bit;
sbit LD0 at RD0_bit;

sbit SW1 at RB0_bit ;

 //           12345678901234567890
const char chaine0[]=" 16F887_Freq_CCP1_RC2_Timer1_ADC0_UART.mcppi\r\n";
const char chaine1[]=" Mesure de Frequence via CCP RC2 \r\n";
const char chaine2[]=" Oscillateur interne 8Mhz  Port COM 96000 \r\n";

const char *RS_Str[]={chaine0,chaine1,chaine2};

char TEXTE[32];
char CRam1[20];
char *txt;
char *p1;

/* Attention à l'espace RAM
#define MAXLEN 41
53 1511 IRP bit must be set manually for indirect access to 'buffer' variable 16F887_Freq_IT_RB0_TMR0_ADC0_UART.c
*/
 #define MAXLEN 31

unsigned char buffer[MAXLEN+1];
unsigned int Index1,i1;
unsigned int UART1_DataReady;
char c1;

//char c1;
unsigned int i,j,k;
//unsigned char cpt1, cpt2 ,cpt3 ;
////unsigned long T1;
unsigned long Freq;
#endif

//initialisation et declaration des variables utilisés
unsigned int tOld, tNew;
unsigned int nb_overflow;
int edge = 0;
int capture = 0;
unsigned long temps=0L;
float periode=0;
float f1;
unsigned int  frequence;
unsigned int EA0;

//---------------------------------ROUTINE D INTERRUPTION--------------------------------
//#pragma origin 0x4  // <- ??
void interrupt(void)   // a chaque interruption sur rbo/int calcul debut et fin de periode
{
//UART1
   if((RCIF_bit==1) && (RCIE_bit==1))
   {
     c1 = RCREG;
     if(OERR_bit)
     {
        CREN_bit = 0;
        CREN_bit = 1;
        OERR_bit = 0;
     }
     if(FERR_bit)   c1 = RCREG;

     if ((c1==CR)|| (i1>=MAXLEN))
      {
        UART1_DataReady=1;
        if (i1 >= MAXLEN )  UART1_DataReady=2;
        //interdit IT Reception UART
        RCIE_bit=0;
        buffer[i1]=0;
        Index1=i1;
        i1=0;
        c1=0;
     }
     else
     
{
       buffer[i1]=c1;
       Index1=i1;
       i1++;
      }
   }
  if((CCP1IF_bit)  && (CCP1IE_bit))
  {
      if(edge==0)
      {
        tOld = (256*CCPR1H) + CCPR1L;
        edge = 1;
      }
       else
      
{
            tNew =(256*CCPR1H )+ CCPR1L; 
            capture 
= 1;
            edge = 0;

       }
     PIR1.CCP1IF = 0;
  }
  // TMR1 IT
 //   if((TMR1IF_bit) && TMR1IE_bit)
 //      { nb_overflow++;
 //        TMR1IF_bit=0;
//      }

}

 #ifdef MyDemoBoard
 // --- Copie le texte depuis FLASH ROM vers RAM
void strConstRamCpy(unsigned char *dest, const code char *source)
 {
  while (*source)*dest++ = *source++ ;
  *dest = 0 ;    // terminateur
}

void CRLF()
{
  UART1_Write(CR);
 UART1_Write(LF);
}

void UART1_Write_CText(const char *txt)
 {
   while (*txt)
      UART1_Write(*txt++);
}

void RAZ_Uart()
{
for (i1=0;i1<MAXLEN;i1++) buffer[i1]=0;
i1=0;
Index1=0;
c1=0;
UART1_DataReady=0;
RCIE_bit=1;
}

#endif


//-------------------------------Fonction principale------------------------------
// affichage de la frequence mesuré , sur port c et portd
void main()
{
      #ifdef MyDemoBoard
      //Oscillateur_Interne car pas de Quartz !
       OSCCON=0b01110001 ; // 8MHz (111) & SCS=1  (sinon 4 MHz par defaut)
       Delay_ms(1000);
       TRISC=0x80;     // car RC7 =entree UART !
       #else
       TRISC=0x00;
       #endif
       
       TRISD
=0;
       TRISB.B0=1; // rbo en entree su microcontrolleur
       TRISA.B0=1; // RA0 analog input
       TRISC.F2 = 1; // RC2 en entree  pour capture CCP
       
       ANSEL 
= 0x01;
       ANSELH = 0;
       PORTD=0;
       PORTC=0;

       txt=&TEXTE[0];

  #ifdef MyDemoBoard
    Freq = Clock_kHz();
    LongWordToStr(Freq, txt) ;
    if (Freq < 8001) 
    
{
      UART1_Init(9600);  // Fosc=8MHz
      }
        else
        
{
           UART1_Init(19200);  // Q=20Mhz
    }
    txt=&TEXTE[0];    // init pointeur
    c1 = RCREG;
    UART1_Write(CLS);  // efface ecran terminal VBRAY
    Delay_ms(1000); 
    CRLF
();
    // presentation
    for (i=0;i<3;i++) UART1_Write_CText(RS_Str[i]);

    LongWordToStr(Freq, CRam1);
    UART1_Write_CText(" Freq FOSC= ");
    UART1_Write_Text(CRam1);
    CRLF();
    UART1_Write_CText(" Start Version : "Version"\r\n");
    // preparatio reception UART
   

   
#endif

    ADC_Init();
    
    tOld
=0;
    tNew=0;
    capture = 0;
    edge = 0;
    nb_overflow=0;
    
  
// configure CCP mode
    CCP1CON = 0x05;
    CCP2CON=0;
    CCP1CON=0;
    P1M1_bit=0;  // P1A assigned as capture input ( RC2)
    P1M0_bit=0;
    DC1B1_bit=0;
    DC1B0_bit=0;
    //  0b0101;  // every 1 rising edge
    CCP1M3_bit=0;
    CCP1M2_bit=1;
    CCP1M1_bit=0;
    CCP1M0_bit=1;

  // configure Timer1
    T1CON =0;


    //  10=> prescaler =1/4
    T1CKPS1_bit=1;
    T1CKPS0_bit=0;
    TMR1CS_bit=0;   // internal FOSC/4

    TMR1IE_bit=0;
    TMR1ON_bit=1;
    
   
#ifdef MyDemoBoard
    RAZ_Uart();
    #endif

    INTCON.PEIE=1;
    PIR1.CCP1IF = 0; //clear CCP flag
    PIE1.CCP1IE = 1; // enable interrupt capture


   GIE_bit=1;
   do
   
{

    if(capture==1)
    {
      PIE1.CCP1IE = 0;
      capture=0;
      temps =~ tOld + tNew +1;
     // if (TMR1IF_bit)  temps=temps+ 65536L ;
      periode=(float) temps ;
      // 500 000 because  8MHz -> 0,5µS * prescaler=4 => 2µS 
      //  F=1/T   soit   1000 000 / Periode* 2     pu 500 000/ Periode
      f1=500000.0/periode;
      frequence=(unsigned int)f1; // pour affichage sur leds  en Hz  ex: 249
    
     
#ifdef MyDemoBoard
        txt=&TEXTE[0];
        UART1_Write_CText("Delta temps= ");
        LongToStr(temps,txt);
        UART1_Write_Text(txt);
        UART1_Write(TAB);
        UART1_Write_CText("f1= ");
        FloatToStr(f1,txt);
        UART1_Write_Text(txt);
        UART1_Write(TAB);
        UART1_Write_CText("Frequence= ");
        WordToStr(frequence,txt);
        UART1_Write_Text(txt);
          UART1_Write(TAB);
        UART1_Write_CText("ADC0= ");
        EA0=ADC_Read(0);
        WordToStr(EA0,txt);
        UART1_Write_Text(txt);
       CRLF(); 
       PORTD
= EA0>>2;
       Delay_ms(1000);  // on ralenti tout çà pour mieux visualiser surr l'ecran
       // PORTC = frequence >> 8;  // port non disponible !!
       #else
           // 20 Mhz => 4/20=> 0.2µS  * prescaler =4 => 0.8µS0;9=1/12,5
           // à verifier !
           periode=(float)temps ;
           f1=12500000.0/periode;
           frequence=(unsigned int)f1;
           PORTD = frequence & 0x00FF;         // On envoie les 8 bits de points faibles sur le port D
           PORTC = frequence >> 8;    //pour faire apparaitre les 8 bits de poids fort restant sur le PORTC
      #endif
      capture=0;
      PIE1.CCP1IE = 1; // enable interrupt

    }
    #ifdef MyDemoBoard

     if(UART1_DataReady>0)
     {
       if(UART1_DataReady>1)
       {
           UART1_Write_CText("Attention buffer Full! \r\n ");
             UART1_Write_Text(buffer);
           CRLF();
       }
       else
       
{
           UART1_Write_CText("Recu : ");
           UART1_Write_Text(buffer);
           CRLF();
           UART1_DataReady=0;
       }
       RAZ_Uart() ;
     }
     #endif

   }while(1);
    
 
}
 
Aide toi, le ciel ou FantasPic t'aidera

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
adrienc45
Débutant
Débutant
Messages : 27
Enregistré en : octobre 2015

#36 Message par adrienc45 » mer. 28 oct. 2015 21:15

merci

vu que dans le code on dit que les temps entre deux incrementations du TMR0 est de 0.4 microsecondes
on dit aussi dans le meme temps que le prescaler est a 1/2 ( temps entre deux incrementations du TMR0 est deux fois plus grand que le temps entre deux incrementations de l horloge )
donc par deduction sachant que une incrementation du tmr0 prends 4 cycles horloge
on en deduit que l on as forcement suppose que notre quartz etait un externe de 20 Mhz ? non ?

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
adrienc45
Débutant
Débutant
Messages : 27
Enregistré en : octobre 2015

#37 Message par adrienc45 » jeu. 29 oct. 2015 12:42

dernière question après je devrais en voir fini pour cette affaire exit

normalement lorsque l on rentre dans une routine d interruption en assembleur , on doit sauvegarder les registres STATUS et TEMP ? puis les restaurer ainsi que de faire un retfie avant de sortir de la routine ?

en langage C pourquoi il n y as rien de tout ça ?


NOTA : je reponds a une des remarques que m' as fait paulfjujo au sujet de l ' une de mes instructions dans le rogramme que j avais posté ci dessus .

Code : Tout sélectionner

//#pragma origin 0x4  // <- ?? 


Je dois enlever cette phrase du mode commentaire pour que cela fonctionne chez moi .
Cette insturction stipule que la routine d interruption , sur les pic , commence a l adresse 0x0004 , et donc lorsque celle ci intervient , le pointeur du programme doit se positionner a cette adresse pour executer la routine .( tiré de la doc microchip je n invente rien )

alors pourquoi l avoir mis volontairement en commentaire pour inhiber son utilisation ?

En attendant , bonne journe a tous 8-)

Calcul période signal créneau (amplitude 0-5v) avec pic 16f887
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 2589
Âge : 73
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#38 Message par paulfjujo » jeu. 29 oct. 2015 17:48

en langage C pourquoi il n y as rien de tout ça ?

le fait de declarer void interrupt , fait que le compilateur se charge de tout cela.
voir extrait fichier isting ci joint.
On voit bien la partie "Sauvegarde du contexte " au debut de l'IT
et la partie "Restitution du contexte " en fin d'IT.

verifie dans ton propre resultat fichir *.lst, apres compilation ..
et aussi dans
Tools --> Options --> output settings --> Optimisation level -- ?
pour ma part j'ai le niveau 4 (four)

Je dois enlever cette phrase du mode commentaire pour que cela fonctionne chez moi .
Cette insturction stipule que la routine d interruption , sur les pic , commence a l adresse 0x0004 , et donc lorsque celle ci intervient , le pointeur du programme doit se positionner a cette adresse pour executer la routine .( tiré de la doc microchip je n invente rien )
alors pourquoi l avoir mis volontairement en commentaire pour inhiber son utilisation ?


Ce n'est pas utile ..
la preuve dans le listing ..
l'interrupt est bien placée en 0x0004 !

et ce n'est pas normal si tu doives specifier cette adresse ..
Dans toutes mes applis en mikroC, je n'ai jamais specifié d'adresse IT. sur les series 16F
ou il n'y a qu"un seul vecteur d'adresse interruption.

Code : Tout sélectionner


  LST file generated by mikroListExporter 
- v.2.0 
; Date/Time: 28/10/2015 20:48:24
;----------------------------------------------

;
Address Opcode     ASM
0x0000    0x158A          BSF        PCLATH
, 3
0x0001    0x2941          GOTO       2369
_interrupt
:

---
 sauve le contexte  !

0x0004    0x00FF          MOVWF      R15
0x0005    0x0E03          SWAPF      STATUS
, 0
0x0006    0x0183          CLRF       STATUS
0x0007    0x1683          BSF        STATUS
, 5
0x0008    0x00E4          MOVWF      ___saveSTATUS
0x0009    0x080A          MOVF       PCLATH
, 0
0x000A    0x00E3          MOVWF      ___savePCLATH
0x000B    0x018A          CLRF       PCLATH
0x000C    0x0870          MOVF       R0
, 0
0x000D    0x1283          BCF        STATUS
, 5
0x000E    0x00A2          MOVWF      34
0x000F    0x0804          MOVF       FSR
, 0
0x0010    0x00A3          MOVWF      35
0x0011    0x1E8C          BTFSS      PIR1
, 5
0x0012    0x2861          GOTO       L_interrupt2
0x0013    0x1683          BSF        STATUS
, 5
0x0014    0x1E8C          BTFSS      PIE1
, 5
0x0015    0x2861          GOTO       L_interrupt2
L__interrupt39
:

// traitement  UART
// enlevé pour plus de clarté


// CCP interrupt 
L_interrupt2:
0x0061    0x1283          BCF        STATUS, 5
0x0062    0x1D0C          BTFSS      PIR1
, 2
0x0063    0x2892          GOTO       L_interrupt12
0x0064    0x1683          BSF        STATUS
, 5
0x0065    0x1D0C          BTFSS      PIE1
, 2
0x0066    0x2892          GOTO       L_interrupt12
L__interrupt37
:
0x0067    0x3000          MOVLW      0
0x0068    0x1283          BCF        STATUS
, 5
0x0069    0x0631          XORWF      _edge
+1, 0
0x006A    0x1D03          BTFSS      STATUS
, 2
0x006B    0x286E          GOTO       L__interrupt44
0x006C    0x3000          MOVLW      0
0x006D    0x0630          XORWF      _edge
, 0
L__interrupt44
:
0x006E    0x1D03          BTFSS      STATUS, 2
0x006F    0x2880          GOTO       L_interrupt13
0x0070    0x0816          MOVF       CCPR1H
, 0
0x0071    0x1683          BSF        STATUS
, 5
0x0072    0x00C6          MOVWF      _tOld
+1
0x0073    0x01C5          CLRF       _tOld
0x0074    0x1283          BCF        STATUS
, 5
0x0075    0x0815          MOVF       CCPR1
, 0
0x0076    0x1683          BSF        STATUS
, 5
0x0077    0x07C5          ADDWF      _tOld
, 1
0x0078    0x1803          BTFSC      STATUS
, 0
0x0079    0x0AC6          INCF       _tOld
+1, 1
0x007A    0x3001          MOVLW      1
0x007B    0x1283          BCF        STATUS
, 5
0x007C    0x00B0          MOVWF      _edge
0x007D    0x3000          MOVLW      0
0x007E    0x00B1          MOVWF      _edge
+1
0x007F    0x2891          GOTO       L_interrupt14
L_interrupt13
:
0x0080    0x0816          MOVF       CCPR1H, 0
0x0081    0x1683          BSF        STATUS
, 5
0x0082    0x00C4          MOVWF      _tNew
+1
0x0083    0x01C3          CLRF       _tNew
0x0084    0x1283          BCF        STATUS
, 5
0x0085    0x0815          MOVF       CCPR1
, 0
0x0086    0x1683          BSF        STATUS
, 5
0x0087    0x07C3          ADDWF      _tNew
, 1
0x0088    0x1803          BTFSC      STATUS
, 0
0x0089    0x0AC4          INCF       _tNew
+1, 1
0x008A    0x3001          MOVLW      1
0x008B    0x1283          BCF        STATUS
, 5
0x008C    0x00AE          MOVWF      _capture
0x008D    0x3000          MOVLW      0
0x008E    0x00AF          MOVWF      _capture
+1
0x008F    0x01B0          CLRF       _edge
0x0090    0x01B1          CLRF       _edge
+1
L_interrupt14
:
0x0091    0x110C          BCF        PIR1, 2
L_interrupt12
:
L_end_interrupt:

//----    restore le contexte ---------

L__interrupt41:
0x0092    0x1283          BCF        STATUS, 5
0x0093    0x0822          MOVF       34
, 0
0x0094    0x00F0          MOVWF      R0
0x0095    0x0823          MOVF       35
, 0
0x0096    0x0084          MOVWF      FSR
0x0097    0x1683          BSF        STATUS
, 5
0x0098    0x0863          MOVF       ___savePCLATH
, 0
0x0099    0x008A          MOVWF      PCLATH
0x009A    0x0E64          SWAPF      ___saveSTATUS
, 0
0x009B    0x0083          MOVWF      STATUS
0x009C    0x0EFF          SWAPF      R15
, 1
0x009D    0x0E7F          SWAPF      R15
, 0
0x009E    0x0009          RETFIE
; end of _interrupt



mais tu as raison, si tu programmes en assembleur !
en assembleur on doit TOUT GERER...

de meme avec MikroC et les PIC18F ou il existe 2 types d'interruptions ,
on specifie quel vecteur on utilise

Code : Tout sélectionner


void InterruptVectorHigh
() iv 0x0008 ics ICS_AUTO
{
 if ( (RCIE_bit) && ( RCIF_bit))
   { .. etc ..
 
 ou
 void InterruptVectorLow
() iv 0x0018 ics ICS_AUTO  
{
   if (TMR2IF_bit) 
   
{   ..etc ...




sous MPLAB C18 on spectifie l'adresse vecteur IT

Code : Tout sélectionner

//--------  Serial interrupt
#pragma code lowVector=0x0018
 void interrupt_at_low_vector (void)
 {
 _asm
 goto Serial_ISR
 _endasm
 
}
#pragma code    



As-tu testé cette version utilisant CCP1 ?
et quels resultats ?
Aide toi, le ciel ou FantasPic t'aidera


Retourner vers « Langage C »

Qui est en ligne

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