Timer,Interruption ou Boucle? Pic18f4550

Fermé
mik3five - 23 juin 2010 à 14:47
mik3fly Messages postés 6 Date d'inscription mercredi 23 juin 2010 Statut Membre Dernière intervention 9 septembre 2011 - 23 juin 2010 à 17:49
Bonjour,

Je dispose d'un pic18f4550, de mplab v8.46 et d'un pickit2 (avec un quartz de 20mhz)
J'ai 4 Transducteur a ultrasons placé sur les port AN0;AN1;AN2;AN3
Avec 4 boutons CAP1;CAP2;CAP3:CAP4 qui permettent d'afficher le résultat de la conversion en 10 bit sur le PORTB(adresl) et le PORTC(adresh)
Cependant maintenant, j'aimerai automatisé le passage d'un capteur à un autre.
Par exemple, j'aimerai acquérir le résultat des conversion de chaque capteur, toute les 50ms;
Je débute en C, ainsi qu'avec les pics; Je ne sais pas comment utilisé les Timer, d'ailleurs, je me demande si une simple boucle qui incrémente jusqu'à 4 pourrait faire l'affaire? une boucle qui s'incrémenterait toute les 50ms, et qui changerai ma variable choix(ADCON0);

enfin bref voilà, je vous remercie pour toute les idées ou critiques qui me feront avancer !

Voici mon code
#include <p18f4550.h>


#pragma config FOSC = HS			
#pragma const config FCMENB = OFF	
#pragma const config IESOB = OFF	
#pragma config PWRT = OFF			
#pragma const config BOR = BOHW 	
#pragma const config BORV = 20		
#pragma config WDT = OFF			
#pragma config DEBUG = OFF			
#pragma config LVP = OFF			
#pragma config PBADEN = OFF



#define CAP1 PORTDbits.RD0
#define CAP2 PORTDbits.RD1
#define CAP3 PORTDbits.RD5
#define CAP4 PORTDbits.RD7
#define LED1 PORTDbits.RD2
#define LED2 PORTDbits.RD3
#define LED3 PORTDbits.RD4
#define LED4 PORTDbits.RD6
#define quantum 4.8828e-3 //5/1024 -> 0,0048828 mv



int choix;
int result;
int Vcap;
float Vnum;


void adc_conv(void);
void adc_init(void);
void calc_tens(void);

void main(void)
{
	adc_init();
	adc_conv();
	calc_tens();
}

///////////////////////////////////////////////////////////////////////////////////////
//////////////////// Convertion AD pour 4 Transducteur a Ultrasons ////////////////////
////////////////////////// LV-MaxSonar®-EZ0 : 0.50cm a 700cm //////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

void adc_conv(void)

{	
choix=0b00000000;

	if(CAP1==1) {choix=0b00000101;LED1=1;} //Capteur 1 sur AN1
	else{LED1=0;}
	if(CAP2==1) {choix=0b00001001;LED2=1;} //Capteur 2 sur AN2
	else{LED2=0;}
	if(CAP3==1) {choix=0b00001101;LED3=1;} //Capteur 3 sur AN3
	else{LED3=0;}
	if(CAP4==1) {choix=0b00000001;LED4=1;} //Capteur 0 sur AN0
	else{LED4=0;}

	
	
	ADCON0=choix;				// Sélection du can; 
	ADCON1=0b00001110;			// 
	ADCON2=0b10101100;
	ADCON0bits.ADON=1;
	ADCON0bits.GO_DONE=1; 		// début convertion
	while(ADCON0bits.GO_DONE);	// attente convertion
	ADCON0bits.GO_DONE=0;		// fin convertion
	LATB=ADRESL;
	LATC=ADRESH;
	ADCON0=0x00;				// can éteint 	

}

///////////////////////////////////////////////////////////////////////////////////////
//////////////////// Calcul AD; 9,8mv/2.54cm soit 3.86mv/1cm  /////////////////////////
///////////////////// Vcap = Vcc/512; Résolution sur 9 Bits ///////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

void calc_tens(void)
{
	Vcap=((ADRESH*256)+ADRESL);
	Vnum = ((float)Vcap) * quantum;
}

void adc_init(void)
{
	LATB=0x00; 
	LATC=0x00;
	TRISD=0b10000011; //RD0,RD1,RD5,RD7 en entrée
	TRISB=0b00000000; //RB en sortie
	TRISC=0b00000000; //RC en sortie
}

4 réponses

chuka Messages postés 965 Date d'inscription samedi 11 octobre 2008 Statut Membre Dernière intervention 29 juillet 2010 378
Modifié par chuka le 23/06/2010 à 14:58
Salut,
l'utilisation d'un timer est pas mal pour cela:
tu fais l'init de ton timer (se referrer à la datasheet pour calibrer l'IT timer à 50ms) et dans l'IT timer tu incrémentes une variable (dans l'exemple TopTension) et dans le main:
void main(void)  
{  
   timer_init();  
   adc_init();  
   while(1){  
      if (TopTension){  
         adc_conv();  
         calc_tens();  
          _DINT();  
          TopTension--;  
         _EINT();  
       }  
    }  
}  

Ce n'est pas parce que certaines choses semblent inexplicables, qu'il faut faire semblant de les expliquer!
1
mik3fly Messages postés 6 Date d'inscription mercredi 23 juin 2010 Statut Membre Dernière intervention 9 septembre 2011 1
23 juin 2010 à 17:49
Voici mon code au complet, pour mémoire
Il y'a 4 Transducteurs a ultrasons, qui permettent de connaitre une distance, entre un objet et le transducteur
La valeur analogique des capteurs est sauvegardé dans Vnum et sur le PORTB et le PORTC, toute les 50ms, le capteur suivant est analysé!

#include <p18f4550.h>


#pragma config FOSC = HS			
#pragma const config FCMENB = OFF	
#pragma const config IESOB = OFF	
#pragma config PWRT = OFF			
#pragma const config BOR = BOHW 	
#pragma const config BORV = 20		
#pragma config WDT = OFF			
#pragma config DEBUG = OFF			
#pragma config LVP = OFF			
#pragma config PBADEN = OFF

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////// Définitions des PORTS CAP et DEL ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

#define CAP1 PORTDbits.RD0
#define CAP2 PORTDbits.RD1
#define CAP3 PORTDbits.RD5
#define CAP4 PORTDbits.RD7
#define LED1 PORTDbits.RD2
#define LED2 PORTDbits.RD3
#define LED3 PORTDbits.RD4
#define LED4 PORTDbits.RD6
#define quantum 4.8828e-3 //5/1024 -> 0,0048828 mv
#define uchar unsigned char  

///////////////////////////////////////////////////////////////////////////////////////
////////////////////// Variables et Prototypes des fonctions //////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

int choix;
int result;
int Vcap;
int TopTension;
float Vnum;

void timer_init(void);
void adc_conv(uchar choix,uchar index); 
void adc_init(void);
void calc_tens(void);
void choix_cap(void);
void _DINT(void);
void _EINT(void);

#pragma code highVector=0x008
void atInterrupthigh(void)
{
_asm GOTO choix_cap _endasm
}
#pragma code


void main(void)    
{    
   uchar choix[]={0x01,0x05,0x09,0x0D};  
   uchar index=0;  
   timer_init();    
   adc_init();    
   while(1){    
      if (TopTension){    
         adc_conv(choix[index],index);    
         calc_tens();    
         if ((++index)>sizeof(choix))		//evite les debordements  
           index=0;  
          _DINT();    
          TopTension--;    
         _EINT();    
       }    
    }    
}    


///////////////////////////////////////////////////////////////////////////////////////
//////////////////// Convertion AD pour 4 Transducteur a Ultrasons ////////////////////
////////////////////////// LV-MaxSonar®-EZ0 : 0.50cm a 700cm //////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

void adc_conv(uchar choix,uchar index)  

{   
 LATD&=0xC3; 				//mise à zero des led
 LATD|=0x04<<index;			//mise à 1 de la led
 ADCON0=choix;    			// Sélection du can;   
 ADCON1=0b00001110;   		//   
 ADCON2=0b10101100;  
 ADCON0bits.ADON=1;  
 ADCON0bits.GO_DONE=1;   	// début convertion  
 while(ADCON0bits.GO_DONE); // attente convertion  
 ADCON0bits.GO_DONE=0;  	// fin convertion  
 LATB=ADRESL;  
 LATC=ADRESH;  
 ADCON0=0x00;    			// can éteint    

}  


///////////////////////////////////////////////////////////////////////////////////////
//////////////////// Calcul AD; 9,8mv/2.54cm soit 3.86mv/1cm  /////////////////////////
///////////////////// Vcap = Vcc/512; Résolution sur 9 Bits ///////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

void calc_tens(void)
{
	Vcap=((ADRESH*256)+ADRESL);
	Vnum = ((float)Vcap) * quantum;
}


///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// INITIALISATION µC  //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

void adc_init(void)
{
	LATB=0x00; 			//PORTB : 0
	LATC=0x00;			//PORTC : 0
	TRISD=0b10000011; 	//RD0,RD1,RD5,RD7 en entrée
	TRISB=0b00000000; 	//RB en sortie
	TRISC=0b00000000; 	//RC en sortie
}

void timer_init(void)
{
	T0CON=0b10000001; 		//Timer en fonctionnement. Prescaler 1:4
	INTCONbits.GIE=1;  		//Autorisations des interruptions
	INTCONbits.PEIE=1; 		//Autorisations des interruptions périphérique
	INTCONbits.TMR0IE=1; 	// Autorisations d'interruption pour le débordement du TIMER0
	INTCON2bits.TMR0IP=1; 	//Interruption du TIMER haute priorité.

}

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// INTERRUPTION 50MS CAPx+1  ///////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

#pragma interrupt choix_cap  
void choix_cap (void)
{
 
	TopTension++;
	INTCONbits.TMR0IF=0;//mise à zero du flag d'IT 
}

void _DINT()
{
	INTCONbits.GIE=0; // Desactivations des interruptions
}

void _EINT()
{
	INTCONbits.GIE=1; // Autorisations des interruptions
}
1
mmh.. à quoi servent les instruction _DINT(); et _EINT();?

Pour les 50 ms je pense avoir trouvé, je possède un quartz 20mhz, donc 1/20mhz=50ns

Si j'utilise un prescaler de 1:16 ainsi qu'un timer de 16bit, ça nous donne , 50ns*16*65536= 0,0524288 Seconde.. Soit 52ms!! ce qui est parfait.
Cependant, sur les schéma de la datasheet, j'aperçois, Fosc/4.. suis-je sur la bonne piste??

(sinon cela me ferai 1/5mhz =200ns, 200ns*4*65536 = 0.052...s soit 52ms)
Donc T0CON=0b10000011 (ou T0CON=0b10000001)

Si j'ai bien compris, le timer va s'incrémenter tout seule, jusqu'au débordement du registre TRM0, TMR0IF passe a 1; et ensuite on passe dans l'IT ??

La variable TopTension dans ton exemple, elle correspond a ma variable choix?? Je comprend pas, comment l'utilisé enfaite.

edit

voici mon timer_init
void timer_init(void)
{
	T0CON=0b10000001; //Timer en fonctionnement. Prescaler 1:4
	INTCONbits.GIE=1;  //Autorisations des interruptions
	INTCONbits.PEIE=1; //Autorisations des interruptions périphérique
	INTCONbits.TMR0IE=1; // Autorisations d'interruption pour le débordement du TIMER0
	INTCON2bits.TMR0IP=1; //Interruption du TIMER haute priorité.
}
0
chuka Messages postés 965 Date d'inscription samedi 11 octobre 2008 Statut Membre Dernière intervention 29 juillet 2010 378
Modifié par chuka le 23/06/2010 à 16:27
Salut,
Je pense qu'en effet, si ton horloge est à 20mHz, alors tu dois avoir un prescaler de base sur Fosc... donc sinon cela me ferai 1/5mhz =200ns, 200ns*4*65536 = 0.052...s soit 52ms doit etre la soluce...
Tu dois pouvoir choisir le mode de comptage (Up,Down,Up-Down...) regarde dans le registre si cela est le cas...sinon je pense que par defaut, cela doit etre en mode up.

Si j'ai bien compris, le timer va s'incrémenter tout seule, jusqu'au débordement du registre TRM0, TMR0IF passe a 1; et ensuite on passe dans l'IT ??

Tu as parfaitement compris!!
Tu dois juste définir le vecteur d'IT (c'est en fait la fonction qui va être appelé quand tu as ton débordement...). Je suis pas sur de la declaration du vecteur d'IT....mais cela ressemble à cela!!
#pragma nterruptlow Timer_0
void Timer_0(void)
{
TopTension++;
INTCONbits.TMR0IF=0;//mise à zero du flag d'IT
}

_DINT(); et _EINT(); sont des fonction que tu dois creer pour disable IT et Enable IT...en effet ta variable TopTension sera modifier sous IT...donc quand tu la decremente...il faut arreter les IT...c'est une bonne pratique de codage!!;)
@+
0
chuka Messages postés 965 Date d'inscription samedi 11 octobre 2008 Statut Membre Dernière intervention 29 juillet 2010 378
Modifié par chuka le 23/06/2010 à 16:45
#define uchar unsigned char  
void main(void)    
{    
   uchar choix[]={0x01,0x05,0x09,0x0D};  
   uchar index=0;  
   timer_init();    
   adc_init();    
   while(1){    
      if (TopTension){    
         adc_conv(choix[index],index);    
         calc_tens();    
         if ((++index)>sizeof(choix))//evite les debordements  
           index=0;  
          _DINT();    
          TopTension--;    
         _EINT();    
       }    
    }    
}    
void adc_conv(uchar choix,uchar index)  

{   
 LATD&=0xC3; //mise à zero des led
 LATD|=0x04<<index;//mise à 1 de la led
 ADCON0=choix;    // Sélection du can;   
 ADCON1=0b00001110;   //   
 ADCON2=0b10101100;  
 ADCON0bits.ADON=1;  
 ADCON0bits.GO_DONE=1;   // début convertion  
 while(ADCON0bits.GO_DONE); // attente convertion  
 ADCON0bits.GO_DONE=0;  // fin convertion  
 LATB=ADRESL;  
 LATC=ADRESH;  
 ADCON0=0x00;    // can éteint    

}  
0
mik3fly Messages postés 6 Date d'inscription mercredi 23 juin 2010 Statut Membre Dernière intervention 9 septembre 2011 1
Modifié par mik3fly le 23/06/2010 à 17:20
merci pour ton aide!! Je vais continuer avec ce que tu me propose!! et essayer plusieurs autres possibilité !!


pour _DINT()
{
INTCONbits.GIE=0;
}

et EINT()
{
INTCONbits.GIE=1;
}

rien de plus simple non???

(après tous ça, je m'attaque au filtre numérique^^)
0