- 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 ---
Modérateur : Jérémy
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
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
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 calculsCode : 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
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
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... 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 !
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 !
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
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 .. 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);
}
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 ?
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
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
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 ?
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 40 invités