Il y a une raison particulière pour laquelle tu n'utilsies pas MPLABX ?
je ne vois nulle part tes déclarations en volatile.
-----
Il y a une raison particulière pour laquelle tu n'utilsies pas MPLABX ?
je ne vois nulle part tes déclarations en volatile.
Oui, j'ai toujours utilisé ce logiciel.
Parce que je ne les ai pas mises dans le code que je vous ai envoyé, j'ai juste mis les interruptions ^^
J'ai réglé le problème du c018.O.Code:volatile unsigned int cnt, tour; //sous prog d'int void Interrupt_B0(void); void Interrupt_Timer(void); // on déclare que lors d'une interruption #pragma code highVector=0x08 void atInterrupthigh(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_B0 _endasm } #pragma code // retour à la zone de code #pragma code lowVector=0x18 void atInterruptlow(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_Timer _endasm } #pragma code // retour à la zone de code // ************************ // **** Interruptions **** // ************************ #pragma interrupt Interrupt_B0 #pragma interrupt Interrupt_Timer void Interrupt_B0(void) { if(INTCONbits.INT0IF==1){ // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour } // fin if } void Interrupt_Timer(void) { if (INTCONbits.TMR0IF) { cnt++; INTCONbits.TMR0IF = 0; } }
Maintenant quand je compile, j'ai l'impression que tour s'incrémente comme il faut, mais le cnt ne s'incrémente jamais. On dirait que le programme ne rentre jamais dans l'interruption du Timer
Fais voir le reste du programme alors...
et passe à MPLABX (temps d'adaptation <1 journée), temps gagné par semaine >2h
C'est vite rentabilisé
UNIQUE limitation (mais rien ne t'empeche de garder les deux installés):
Le pickit2 n'est (apparemment ?) pas reconnu : Donc plus d'analyseur logique possible
D'accord, voilà tout le code:
Code:/********************************************************************************************************* * Tachymètre (compte-tour) numérique à base de capteur à effet Hall * * Quartz 20Mhz PIC 18F1320 * * * * Formule de calcul du timer0 : * * Temps=(256-valeur Décimale chargée TMR0) * 4 * (prescaler OPTION_REG) * 1/Oscillateur en Hz * * Ce qui donne: * * T=(256-0)*4*64*(1/20000000)= 0,0032768 >> pour avoir 0,999424 seconde à multiplier par cnt=305 * * 0,999424 étant pour ce quartz la valeur la plus proche de 1 seconde avec le timer0 * * * * Le capteur Hall connecté sur RB0 déclenche une interruption à chaque passage de l'aimant * *********************************************************************************************************/ #include <p18f452.h> // d?claration SFR pour ICD2 #include <delays.h> // d?claration prototype fonctions delay #define FOREVER while(1) // D?finir des nouveaux types donn?es typedef unsigned char BYTE; typedef unsigned int WORD; // **** configuration du circuit ************* // configuration avec quartz #pragma config OSC = HS, OSCS = OFF #pragma config PWRT = OFF, BOR = OFF #pragma config WDT = OFF #pragma config CCP2MUX = OFF #pragma config STVR = ON #pragma config LVP = OFF #pragma config DEBUG = ON #pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF, CPB = OFF, CPD = OFF #pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF #pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF #pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTRB = OFF // d?finitions LCD #define LCD_D4 PORTBbits.RB4 // data afficheur bit ? bits #define LCD_D5 PORTBbits.RB1 // data afficheur bit ? bits #define LCD_D6 PORTBbits.RB2 // data afficheur bit ? bits #define LCD_D7 PORTBbits.RB3 // data afficheur bit ? bits #define LCD_D4_DIR TRISBbits.TRISB4 // data direction afficheur bit ? bits #define LCD_D5_DIR TRISBbits.TRISB1 // data direction afficheur bit ? bits #define LCD_D6_DIR TRISBbits.TRISB2 // data direction afficheur bit ? bits #define LCD_D7_DIR TRISBbits.TRISB3 // data direction afficheur bit ? bits #define LCD_E PORTAbits.RA1 // cde afficheur E //#define LCD_RW PORTAbits.RA2 // cde afficheur RW #define LCD_RS PORTAbits.RA3 // cde afficheur RS #define LCD_E_DIR TRISAbits.TRISA1 // cde direction afficheur E //#define LCD_RW_DIR TRISAbits.TRISA2 // cde direction afficheur RW #define LCD_RS_DIR TRISAbits.TRISA3 // cde direction afficheur RS //***** variables globales ******************** unsigned char u=0; // caractere incremente pour defilement table de caracteres //***** prototypes de fonctions ******************** unsigned int temp,compteur,i; unsigned char rotation_brute; unsigned short int seconde,sequence; void Affiche_Compteur (void); void w_cde_nibble( unsigned char ); // ?crit le quartet fort du char x en mode cde void w_cde_octet( unsigned char ) ;// ?crit le quartet fort du char x en mode cde puis le quartet faible void w_data_octet( unsigned char ) ;// ?crit le quartet fort du char x en mode data puis le quartet faible volatile unsigned int cnt, tour; //sous prog d'int void Interrupt_B0(void); void Interrupt_Timer(void); // on déclare que lors d'une interruption #pragma code highVector=0x08 void atInterrupthigh(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_B0 _endasm } #pragma code // retour à la zone de code #pragma code lowVector=0x18 void atInterruptlow(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_Timer _endasm } #pragma code // retour à la zone de code // ************************ // **** Interruptions **** // ************************ #pragma interrupt Interrupt_B0 #pragma interrupt Interrupt_Timer void Interrupt_B0(void) { if(INTCONbits.INT0IF==1){ // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour } // fin if } void Interrupt_Timer(void) { if (INTCONbits.TMR0IF==1) { cnt++; INTCONbits.TMR0IF = 0; } } //fin interruption //************* Programme principal *******************/ void main(void) { //***** init variables **************************** INTCON=0b10010000; // activer detection interruption front montant RB0 avec INTE et GIE T0CON = 0b00000101; // Config T0CON pour avoir prescaler 64 et le timer sur 16bits. ADCON0=0; // ADC désactivé TRISA=0; // PORTA configuré en sortie TRISB=0b00000001; // PORTB configuré en sortie sauf port0 compteur=0; temp=0; seconde=0; tour=0; cnt=0; //***** init Ports **************************** // LCD ADCON1=0x0E; // RA1,2,3 en logique (port A analogique par d?faut) LATA=0xF1; // RA1,2,3 ? 0 force par le LATCH (pour pas de glitch sur E !) PORTA=0xF1; // RA1,2,3 ? 0 force par le port (pour pas de glitch sur E !) par securit? ! bof ! LCD_E_DIR=0; // ports en sortie // LCD_RW_DIR=0; // ports en sortie LCD_RS_DIR=0; // ports en sortie LCD_D4_DIR=0; // ports en sortie LCD_D5_DIR=0; // ports en sortie LCD_D6_DIR=0; // ports en sortie LCD_D7_DIR=0; // ports en sortie //***** init LCD **************************** w_cde_nibble( 0x30 ); // 3 control Delay10KTCYx(150); // delay = 15mS w_cde_nibble( 0x30 ); // 3 control Delay10KTCYx(50); // delay = 5mS w_cde_nibble( 0x30 ); // 3 control Delay10TCYx(50); // delay = 100?S w_cde_nibble( 0x20 ); // 2 mode 4 bits w_cde_octet( 0x28 ) ;// fonction set attention si 2F il ecrit en bas a droite ? l'envers avec 4 caracteres de masques (affiche a partir du 5eme car ecrit !) w_cde_octet( 0x0F ) ;// display on w_cde_octet( 0x06 ) ;// mode d'entree w_cde_octet( 0x01 ) ;// clear display (facultatif) w_cde_octet( 0x80 ) ;// DDRAM 0000 (facultatif) w_cde_octet( 0x02 ) ;// home (facultatif) Delay1KTCYx(250); // delay = 5mS INDISPENSABLE pour CDE HOME ! w_cde_octet( 0x83 ) ;// 4eme case de la 1ère ligne w_data_octet( 0x54 ) ;// T w_data_octet( 0x41 ) ;// A w_data_octet( 0x43 ) ;// C w_data_octet( 0x48 ) ;// H w_data_octet( 0x59 ) ;// Y w_data_octet( 0x4D ) ;// M w_data_octet( 0x45 ) ;// E w_data_octet( 0x54 ) ;// T w_data_octet( 0x52 ) ;// R w_data_octet( 0x45 ) ;// E w_cde_octet( 0xC0 ) ;// passage seconde ligne w_cde_octet( 0xC8 ) ;// passage milieu seconde ligne w_data_octet( 0x54 ) ;// T w_data_octet( 0x52 ) ;// R w_data_octet( 0x2F ) ;// / w_data_octet( 0x4D ) ;// M w_data_octet( 0x4E ) ;// N //***** init Interrupt **************************** TMR0L=0; TMR0H=0; T0CONbits.TMR0ON = 1; // Timer 0 marche (debut du comptage) INTCONbits.TMR0IE = 1; // Autorisation source d'interruption INTCONbits.GIE = 1; // Autorisation globale des interruptions //***** boucle forever **************************** FOREVER // boucle forever { Affiche_Compteur(); // Fonction d'affichage sur LCD } } //***** ecriture des fonctions **************************** void Affiche_Compteur (void) // fonction d'affichage de nombre sur plusieurs digits { unsigned int temp; unsigned char rotation_brute; if(cnt==305){ // lorsque l'on compte 1 seconde (voir commentaire entête) compteur= tour*60; // Multiplier le nombre de tour/seconde par 60 (pour tour/min) i=tour; cnt=0; // RAZ variable cnt tour=0; INTCONbits.INT0IE = 1; // Activer RB0/INT interruption seconde++; } // Fin if rotation_brute = (compteur/1000)+48; temp = compteur % 1000; w_cde_octet( 0xC0 ) ; // passage seconde ligne w_cde_octet( 0xC3 ) ; // passage à la 4eme case de la seconde ligne w_data_octet( rotation_brute ) ; // Afficher les milliers rotation_brute = (temp/100)+48; temp = temp % 100; w_data_octet( rotation_brute ) ;// // Afficher les centaines rotation_brute = (temp/10)+48; w_data_octet( rotation_brute ) ;// // Afficher les dizaines rotation_brute = (temp % 10)+48; w_data_octet( rotation_brute ) ;// // Afficher les unités } void w_cde_nibble( unsigned char x) // écrit le quartet fort du char x en mode cde { LCD_RS=0; // mode cde LCD_E=1; // monte enable if (x&0x80) LCD_D7=1; else LCD_D7=0; // écriture des bits if (x&0x40) LCD_D6=1; else LCD_D6=0; // écriture des bits if (x&0x20) LCD_D5=1; else LCD_D5=0; // écriture des bits if (x&0x10) LCD_D4=1; else LCD_D4=0; // écriture des bits LCD_E=0; // descends enable Delay10TCYx(50); // delay = 100µS } void w_cde_octet( unsigned char x) // écrit le quartet fort du char x en mode cde puis le quartet faible { LCD_RS=0; // mode cde LCD_E=1; // monte enable if (x&0x80) LCD_D7=1; else LCD_D7=0; // écriture des bits if (x&0x40) LCD_D6=1; else LCD_D6=0; // écriture des bits if (x&0x20) LCD_D5=1; else LCD_D5=0; // écriture des bits if (x&0x10) LCD_D4=1; else LCD_D4=0; // écriture des bits LCD_E=0; // descends enable Delay10TCYx(5); // delay = 10µS LCD_E=1; // monte enable if (x&0x08) LCD_D7=1; else LCD_D7=0; // écriture des bits if (x&0x04) LCD_D6=1; else LCD_D6=0; // écriture des bits if (x&0x02) LCD_D5=1; else LCD_D5=0; // écriture des bits if (x&0x01) LCD_D4=1; else LCD_D4=0; // écriture des bits LCD_E=0; // descends enable Delay10TCYx(50); // delay = 100µS } void w_data_octet( unsigned char x ) // écrit le quartet fort du char x en mode data puis le quartet faible { LCD_RS=1; // mode data LCD_E=1; // monte enable if (x&0x80) LCD_D7=1; else LCD_D7=0; // écriture des bits if (x&0x40) LCD_D6=1; else LCD_D6=0; // écriture des bits if (x&0x20) LCD_D5=1; else LCD_D5=0; // écriture des bits if (x&0x10) LCD_D4=1; else LCD_D4=0; // écriture des bits LCD_E=0; // descends enable Delay10TCYx(5); // delay = 10µS LCD_E=1; // monte enable if (x&0x08) LCD_D7=1; else LCD_D7=0; // écriture des bits if (x&0x04) LCD_D6=1; else LCD_D6=0; // écriture des bits if (x&0x02) LCD_D5=1; else LCD_D5=0; // écriture des bits if (x&0x01) LCD_D4=1; else LCD_D4=0; // écriture des bits LCD_E=0; // descends enable Delay10TCYx(50); // delay = 100µS }
relit la datasheet et en particulier la figure en 9-1 Interrupt logic
pour comprendre pourqoui le timer0 ne reponds pas..( evolution de cnt)
J'ai changé les priorités d'interruptions, en fait le programme ne va que dans celle qui est à l'adresse 0x08, et jamais dans 0x18 et je ne vois pas comment faire pour que les 2 soient prises en compte.
Car je dois faire en même temps:
1 interruption pour le timer qui incrémente "cnt"
1 interruption sur le port B0 qui incrémente "tour"
Il faudrait qu'elles fonctionnent en parallèle, en même temps pour le bon fonctionnement du système..
ça n'existe pas ! a moins d'avoir un systeme multi processeurs !Il faudrait qu'elles fonctionnent en parallèle, en même temps pour le bon fonctionnement du système..
dans l'interrupt High level tu mets les 2 interrupts à traiter
RB0 et Timer0
Code:if ((...TMR0IE==1) && (INTCONbits.TMR0IF ==1)) { cnt++; INTCONbits.TMR0IF = 0; } { // syntaxe à corriger !!! if (( bit enable IT RB0==1) && (INTCONbits.INT0IF==1)) { // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour NTCONbits.INT0IF=0; }
Merci!ça n'existe pas ! a moins d'avoir un systeme multi processeurs !
dans l'interrupt High level tu mets les 2 interrupts à traiter
RB0 et Timer0
Code:if ((...TMR0IE==1) && (INTCONbits.TMR0IF ==1)) { cnt++; INTCONbits.TMR0IF = 0; } { // syntaxe à corriger !!! if (( bit enable IT RB0==1) && (INTCONbits.INT0IF==1)) { // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour NTCONbits.INT0IF=0; }
Mais j'ai l'impression qu'on atteint pas les 305 au bout d'une seconde. Parce que la valeur de "tour" n'est pas bonne quand cnt est à 305.
Soit ça vient de la détection des fronts sur RB0 qui est mauvaise, soir le timer ne déborde pas aux 0,0032768s voulues (T=(256-0)*4*64*(1/20000000)= 0,0032768)
Interruption:
Main:Code:volatile unsigned int cnt, tour; //sous prog d'int void Interrupt_B0(void); // on déclare que lors d'une interruption #pragma code highVector=0x08 void atInterrupthigh(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_B0 _endasm } #pragma code // retour à la zone de code // ************************ // **** Interruptions **** // ************************ #pragma interrupt Interrupt_B0 void Interrupt_B0(void) { if (INTCONbits.INT0IF==1) { // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour INTCONbits.INT0IF=0; } if (INTCONbits.TMR0IF==1) { cnt++; INTCONbits.TMR0IF = 0; if (cnt=305) { compteur= tour*60; // Multiplier le nombre de tour/seconde par 60 (pour tour/min) i=tour; cnt=0; // RAZ variable cnt tour=0; INTCONbits.INT0IE = 1; // Activer RB0/INT interruption seconde++; INTCONbits.TMR0IF = 0; } } } //fin interruption
Fonction affichage:Code:void main(void) { //***** init variables **************************** INTCON=0b10010000; // activer detection interruption front montant RB0 avec INTE et GIE T0CON = 0b00000101; // Config T0CON pour avoir prescaler 64 et le timer sur 16bits. ADCON0=0; // ADC désactivé TRISA=0; // PORTA configuré en sortie TRISB=0b00000001; // PORTB configuré en sortie sauf port0 compteur=0; temp=0; seconde=0; tour=0; cnt=0; //***** init Ports **************************** // LCD ... ... //***** init LCD **************************** ... ... //***** init Interrupt **************************** TMR0L=0; TMR0H=0; T0CONbits.TMR0ON = 1; // Timer 0 marche (debut du comptage) INTCONbits.TMR0IE = 1; // Autorisation source d'interruption INTCONbits.GIE = 1; // Autorisation globale des interruptions //***** boucle forever **************************** FOREVER // boucle forever { Affiche_Compteur(); // Fonction d'affichage sur LCD } }
Code:void Affiche_Compteur (void) // fonction d'affichage de nombre sur plusieurs digits { unsigned int temp; unsigned char rotation_brute; rotation_brute = (compteur/1000)+48; temp = compteur % 1000; w_cde_octet( 0xC0 ) ; // passage seconde ligne w_cde_octet( 0xC3 ) ; // passage à la 4eme case de la seconde ligne w_data_octet( rotation_brute ) ; // Afficher les milliers rotation_brute = (temp/100)+48; temp = temp % 100; w_data_octet( rotation_brute ) ;// // Afficher les centaines rotation_brute = (temp/10)+48; w_data_octet( rotation_brute ) ;// // Afficher les dizaines rotation_brute = (temp % 10)+48; w_data_octet( rotation_brute ) ;// // Afficher les unités }
Ce qui est bizarre, c'est que quand je mets 1Hz, je dois donc voir 60tr/mn, et c'est le cas!
Mais quand je mets 10Hz sur le port RB0, je dois donc voir 600tr/mn, mais je vois 480tr/mn, idem si je mets 100Hz -> 4980tr/mn.
pas bien,le test !
Code:if (cnt=305) { compteur= tour*60; // Multiplier le nombre de tour/seconde par 60 (pour tour/min) i=tour; cnt=0; // RAZ variable cnt tour=0; INTCONbits.INT0IE = 1; // Activer RB0/INT interruption seconde++; INTCONbits.TMR0IF = 0; }
si compteur, seconde sont utilisés ailleurs, les déclarer aussi en volatileCode:if (cnt==305)
Valider les interruption via GIE=1; qu'apres l'init complete des variables et du LCD..
juste avant la boucle sans fin.
calcul tempo timer0 pour 1 seconde ???
soir le timer ne déborde pas aux 0,0032768s voulues (T=(256-0)*4*64*(1/20000000)= 0,0032768)
à quoi correspond la valeur 305 ?
à 20Mhz
init timer0 à 0x0000
init timer0 sur 16 bits !
prescaler=1/64
il faut deja 838mS pour faire un tour !
s'il faut attendre 305 tours ?
avec init à 26472 soit TMRH=0x67 et TMRL=0x68
et prescaler=128 => 1000,03mS
J'ai changé ça je m'en suis rendu compte!
J'ai un prescaler de 4 avec mon Timer, donc j'utilise cnt==19!
Ca marche nikel la modification quand je suis en mode Debugger, en revanche quand je passe en programmer ça ne fait pas la même chose...
soit 1 interrupt toutes les 52.43mS
Dans la mesure ou tu geres 2 sources d'interruption imbriquees
il vaut mieux utiliser le prescaler du Timer0
comme je te l'ai preconisé,
car tu n'as dans ce cas, qu'une seule interruption par seconde au lieu de 19 !avec init à 26472 soit TMRH=0x67 et TMRL=0x68
et prescaler=128 => 1000,03mS
qui viennent , eventuellement, pertuber celle de RB0...
Alors verdict avec ces réglages:
Lorsque j'ai 10Hz par exemple, il m'affiche 1020tr/mn en debugger, et 5580tr/mn en programmer... (au lieu de 600)
Et bizarrement en programmer, quand je me met en plus haute fréquence, ça me donne les résultats attendus.
Exemple: pour 100Hz, j'ai bien les 6000tr/mn (6060 exactement, mais à ce stade on va pas être tatillon ^^), et pour 150Hz, j'ai bien 9000 aussi...
Tandis que pour 10Hz, j'ai 3180 et pour 15Hz, j'ai 3360 ...
J'ai faits des test avec un PIC18F26K22 at 16MHz
et le timer0 calé sur 1 seconde
resultat sur terminal , SANS le multiplicateur par 60 pour lire en Hz !
SANS DEBUGER
avec 2Hz
11:38:31.140> Seconde=00156 Compteur=00002
11:38:31.640> Seconde=00156 Compteur=00002
11:38:32.203> Seconde=00157 Compteur=00002
11:38:32.703> Seconde=00157 Compteur=00002
11:38:33.203> Seconde=00158 Compteur=00002
avec 50Hz
11:39:31.625> Seconde=00216 Compteur=00050
11:39:32.125> Seconde=00216 Compteur=00050
11:39:32.687> Seconde=00217 Compteur=00050
11:39:33.187> Seconde=00217 Compteur=00050
11:39:33.687> Seconde=00218 Compteur=00050
avec 1000Hz
11:40:25.750> Seconde=00269 Compteur=01002
11:40:26.296> Seconde=00270 Compteur=01002
11:40:26.859> Seconde=00270 Compteur=01002
11:40:27.421> Seconde=00271 Compteur=01001
11:40:28.046> Seconde=00271 Compteur=01001
11:40:28.609> Seconde=00272 Compteur=01002
AVEC DEBUGER ON
1:51:11.312> Seconde=00008 Compteur=00997
11:51:11.875> Seconde=00009 Compteur=00997
11:51:12.437> Seconde=00009 Compteur=00997
11:51:13.000> Seconde=00010 Compteur=00997
11:51:13.562> Seconde=00010 Compteur=00997
11:51:14.125> Seconde=00011 Compteur=00998
On voit que le debugger , utilisant des ressources du MCU, altere le resultat..
C'est NORMAL...
Code://declarations volatile unsigned int tour; volatile unsigned int compteur,seconde; //.. etc .. dans interrupt high level ... etc .... if ((INTCONbits.INT0IE==1)&&(INTCONbits.INT0IF==1)) { // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour INTCONbits.INT0IF=0; } if((INTCONbits.TMR0IE == 1)&&(INTCONbits.TMR0IF==1)) { INTCONbits.TMR0IF = 0; TMR0H=0x85; // 34286 0x85EE at 16Mhz ou 0x6768 at 20Mhz TMR0L=0xEE; compteur= tour; // *60; // Multiplier le nombre de tour/seconde par 60 (pour tour/min) tour=0; seconde++; } ... etc ..Code:void main() { OSCCON=0x70; // 16Mhz .. etc.. PORTB = 0; LATB=0; ANSELB=0; TRISB = 0xFF ; INTCON2bits.RBPU = 0; // enable PORTB internal pullups WPUBbits.WPUB0 = 1; // enable pull up on RB0 ... etc.. compteur=0; seconde=0; tour=0; INTCON=0; Init_UART1(); Put_RS('*'); CRLF(); Put_RS('#'); CRLF(); Put_RS(CLS); // clear Vbray terminal Screen Tempo(100000L); T0CON=0; T0CONbits.T0PS2=1;// prescaler = 1/128 T0CONbits.T0PS1=1; T0CONbits.T0PS0=0; TMR0H=0x85; // 34286 at 16Mhz TMR0L=0xEE; //TMR0H=0x67; // at 20Mhz prescaler=128 26472 => 1000,03 mS //TMR0L=0x68; T0CONbits.TMR0ON = 1; // Timer 0 marche (debut du comptage) RCONbits.IPEN=0; INTCON2bits.INTEDG0=1; // front montant RB0 INTCON2bits.TMR0IP=1; // high level INTCON2bits.RBIP=0; INTCONbits.PEIE = 1; RCSTA1bits.CREN= 1 ; PIE1bits.RC1IE = 1; INTCONbits.INT0IF=0; INTCONbits.INT0IE=1; // autorise RB0 interrupt INTCONbits.TMR0IE = 1; // Autorise TMR0 interrupt INTCONbits.PEIE = 1; // autorisation des IT des périphériques INTCONbits.GIE = 1; // active global interrupt CRLF(); while(1) { k=fprintf(_H_USART,"Seconde=%05u Compteur=%05u \r\n",seconde,compteur); Tempo(150000); } }
Il y a quelques variantes de code du au type de PIC different
Le timer0 etant sur une seconde, il n'y a pas besoin de comptabiliser le nb d'interruption
pour y arriver.
nota: j'ai en plus l'interruption UART1 activée.. No problemo
Dernière modification par paulfjujo ; 22/05/2014 à 12h03.
Code://***** prototypes de fonctions ******************** unsigned int temp,i; unsigned char rotation_brute; unsigned short int sequence; void Affiche_Compteur (void); void w_cde_nibble( unsigned char ); // ?crit le quartet fort du char x en mode cde void w_cde_octet( unsigned char ) ;// ?crit le quartet fort du char x en mode cde puis le quartet faible void w_data_octet( unsigned char ) ;// ?crit le quartet fort du char x en mode data puis le quartet faible volatile unsigned int tour; volatile unsigned int compteur,seconde; //sous prog d'int void Interrupt_B0(void); // on déclare que lors d'une interruption #pragma code highVector=0x08 void atInterrupthigh(void) { // on doit éxecuter le code de la fonction MyHighInterrupt _asm GOTO Interrupt_B0 _endasm } #pragma code // retour à la zone de code // ************************ // **** Interruptions **** // ************************ #pragma interrupt Interrupt_B0 void Interrupt_B0(void) { if ((INTCONbits.INT0IE==1) && (INTCONbits.INT0IF==1)) { // Si une interruption du port B0 est détectée tour++; // incrémenter la variable de tour INTCONbits.INT0IF=0; } if ((INTCONbits.TMR0IE==1) && (INTCONbits.TMR0IF ==1)) { compteur = (tour); // *60; // Multiplier le nombre de tour/seconde par 60 (pour tour/min) TMR0H=0x67; TMR0L=0x68; tour=0; INTCONbits.INT0IE = 1; // Activer RB0/INT interruption seconde++; INTCONbits.TMR0IF = 0; } } //fin interruptionJ'ai bien suivi vos conseils donc pour le programme comme vous pouvez voir, mais je suis désolé je maintiens ma position, je ne sais pas pourquoi en programmer il me donne des résultats faussés dès que je passe en dessous des 100Hz.Code:void main(void) { //***** init variables **************************** TRISA=0; // PORTA configuré en sortie TRISB=0b00000001; // PORTB configuré en sortie sauf port0 compteur=0; temp=0; seconde=0; tour=0; //***** init Ports **************************** // LCD ... ... ... //***** init LCD **************************** ... ... ... //***** init Interrupt **************************** T0CON = 0b00000110; // Config T0CON pour avoir prescaler 128 et le timer sur 16bits. TMR0H=0x67; TMR0L=0x68; T0CONbits.TMR0ON = 1; // Timer 0 marche (debut du comptage) RCONbits.IPEN=0; INTCON2bits.INTEDG0=1; // front montant RB0 INTCON2bits.TMR0IP=1; // high level INTCON2bits.RBIP=0; INTCONbits.PEIE = 1; INTCONbits.INT0IF=0; INTCONbits.INT0IE=1; // autorise RB0 interrupt INTCONbits.TMR0IE = 1; // Autorise TMR0 interrupt INTCONbits.PEIE = 1; // autorisation des IT des périphériques INTCONbits.GIE = 1; // active global interrupt //***** boucle forever **************************** FOREVER // boucle forever { Affiche_Compteur(); // Fonction d'affichage sur LCD } }
30Hz -> affiche 62Hz
40Hz -> affiche 68Hz
60Hz -> affiche 78Hz
80Hz -> affiche 87Hz
100Hz -> affiche 103Hz
700Hz -> affiche 703Hz
Tu es sur de ton affichage.?
teste en dur avec une valeur compteur fixée et definie ..
pourquoi ne pas utiliser
itoa Convert a 16-bit signed integer to a string.
Peux-tu aussi montrer la bouille du signal d'entree à F=30Hz et a 1000HzCode:// declarer un buffer : char txt[16]; void Affiche_resultat() { int i,k; itoa(compteur,txt); k=strlen(txt); w_cde_octet( 0xC3 ) ; // seconde ligne 4em position for (i=0;i<k;i++) { w_data_octet( txt[i] ); } }
C'est bien un signal carré 0V à 5V qui entre en direct sur RB0...
moi , j'ai une R de 2,7K entre RB0 et 0V, pour bien fixer le 0V
La je peux plus l'envoyer aujourd'hui je suis pas au boulot.Tu es sur de ton affichage.?
teste en dur avec une valeur compteur fixée et definie ..
pourquoi ne pas utiliser
itoa Convert a 16-bit signed integer to a string.
Peux-tu aussi montrer la bouille du signal d'entree à F=30Hz et a 1000HzCode:// declarer un buffer : char txt[16]; void Affiche_resultat() { int i,k; itoa(compteur,txt); k=strlen(txt); w_cde_octet( 0xC3 ) ; // seconde ligne 4em position for (i=0;i<k;i++) { w_data_octet( txt[i] ); } }
C'est bien un signal carré 0V à 5V qui entre en direct sur RB0...
moi , j'ai une R de 2,7K entre RB0 et 0V, pour bien fixer le 0V
Mais oui j'avais déjà testé avec une valeur définie pour vérifier l'affichage, ça marchait très bien pourtant.
Qu'est ce qu'un iota? Je n'ai jamais vu cela et je ne comprends pas le code alors :/
Pour ce qui est du signal je fais rentrer un signal carré de 0 à 5V directement sur RB0 sans résistance.
MPLAB® C18 C Compiler LibrariesQu'est ce qu'un iota? pas qu'un peu ! itoa
2005 Microchip Technology Inc.
DS51297F-page 121
4.3 DATA CONVERSION FUNCTIONS
Quand je donne une valeur brut à "compteur", elle s'affiche correctement sur le LDC. Ca ne vient donc pas de l'affichage.
Alors avec le itoa, cela ne résout pas le problème, lorsque je suis en programmer ça m'affiche les mêmes valeurs lorsque je passe sous les 100Hz.
Ca rajoute même un autre problème: si je passe de 4 chiffres à 3 chiffres sur l'afficheur, le 4ème chiffre reste affiché, il n'est pas effacé.
bonjour
mode release pour la compilation?en programmer
mode debug pour la compilation ?en Debugger
La plupart du temps on a plutot des probleme avec des frequences rapides ...
20Hz c'est relativement tres lent !
N'y aurait-il pas un probleme de Watchdog
visible que pour les basses frequences , vu que la periode est longue...
Post ta configuration complete
#pragma config ... etc...
est-ce que ton programme tourne tout le temps dans la boucle FOREVER..
A verifier en affichant un compteur sur une autre ligne du LCD
Cette fonction ne cadre pas le resultat..: si je passe de 4 chiffres à 3 chiffres sur l'afficheur, le 4ème chiffre reste affiché, il n'est pas effacé
en voici une autre qui assure aussi le positionnement à ligne colonne du LCD
les chiffres non significatif en amont sont remplaces par des blans..
(nota: on pourrait aussi mettre des zeros)
Code:#define LCD_LINE1 0x80 // 0x00 + bit D7=1 #define LCD_LINE2 0xC0 // 0x40 + bit D7=1 #define LCD_LINE3 0x94 // 0x14 + bit D7=1 #define LCD_LINE4 0xD4 // 0x54 + bit D7=1 // entier cadre sur 5 digits completé par des blancs a gauche void Write_Word_2_LCD(unsigned int M,int line,int col) { unsigned int i,k; switch (line) { case 1: { w_cde_octet((LCD_LINE1+col,1); break; }; case 2: { w_cde_octet((LCD_LINE2+col,1); break; }; case 3: { w_cde_octet((LCD_LINE3+col,1); break; }; case 4: { w_cde_octet((LCD_LINE4+col,1); break; }; } itoa(M,txt); k=strlen(txt); for (i=k;i<4;i++) { w_data_octet(' ' ); } for (i=0;i<k;i++) { w_data_octet(txt[i] ); } } et dans le main() .... //variable à declarer ! unsigned int Cpt; Cpt=0; FOREVER // boucle forever { Write_Word_2_LCD(Cpt,LCD_LINE_3,3); Write_Word_2_LCD(compteur,LCD_LINE_4,3); Cpt++; } }
Dernière modification par paulfjujo ; 23/05/2014 à 11h16.
Est-il possible d'incrémenter ma valeur "tour" lors d'un front montant ET descendant?
oui, mais cela va changer quoi ?
il suffit d'inverser à chaque fois , dans l'interrupt , le bit designant le type de front
de detection montant ou descendant.
tu auras donc le double de la frequence.
Mais je ne vois pas en quoi cela changerait ton probleme ...Code:// dans l'interrupt RB0 INTCON2bits.INTEDG0=INTCON2bits.INTEDG0 ^ 1; // avec un XOR
RB0 peut compter jusqu'à 1HZ ( 1 coup par seconde)
donne les elements demandés , si tu veux continuer à avoir de l'aide...
Rappel:
montre la bouille du signal 20Hz à l'entree RB0 (oscilloscope)
au cas ou tu aurait 2 fronts montant si le signal carré est fortement differencié...(deformé).
La plupart du temps on a plutot des probleme avec des frequences rapides ...
20Hz c'est relativement tres lent !
N'y aurait-il pas un probleme de Watchdog
visible que pour les basses frequences , vu que la periode est longue...
Post ta configuration complete
#pragma config ... etc...
est-ce que ton programme tourne tout le temps dans la boucle FOREVER..
A verifier en affichant un compteur sur une autre ligne du LCD
Dernière modification par paulfjujo ; 23/05/2014 à 14h09.
J'ai testé le programme directement sur le moteur, et plus par un GBF et ça marche correctement!
Je vous remercie pour votre aide qui m'a été précieuse!
J'aurais une dernière question par rapport à cela: est-il possible d'enregistrer les valeurs du compte tour sur une application de l'ordi?
Je m'explique: il va bien falloir rouler avec la moto. Est-ce que je peux enregistrer toutes les valeurs du compte sur un intervalle de temps voulu? On avait pour idée d'acheter un mini PC pour réaliser cela.
Suppression de l'image hébergée hors du site Cram 64.
Bonjour, je viens de supprimer l'image du post précédent, suis cette procédure :
http://forums.futura-sciences.com/el...-sabonner.html
pour la modération, Cram 64.