Temporisation

Pour réaliser des routines de temporisation, il existe plusieurs méthodes :

1ère méthode : une boucle do ... while

La particularité de cette méthode est sa simplicité.

La temporisation est réalisée grâce à routine wait_ms(...) contenant une boucle do {...} while. La boucle compte un nombre d'instructions "n" fois, le paramètre "n" de cette boucle est déterminé à l'aide de l'outil stopwatch de MPLAB-IDE

On place dans un premier temps 2 breakpoints dans le programme principal (le programme est celui du clignotant)

On fait apparaître la fenêtre stopwatch.

Au premier arrrêt du breakpoint on appuie sur le bouton Zero ce qui remet le compteur à 0 et on fait un stepover pour executer entièrement la routine wait_ms (1000).

Au 2ème arrêt du breakpoint on relève la valeur dans la fenêtre stopwatch ; elle affiche 1,005013 s.

On remarque que la boucle a exécuté environ 500.000 instructions machines.

Si on n'est pas satisfait du résultat, le réglage se fait ensuite par tatonnement en jouant par exemple sur la valeur t2 = 90

2ème méthode : utilisation du module TIMER0

Cette méthode fait appel au module TIMER0 intégré dans le PIC, le fonctionnement est décrit au paragraphe 5 du data sheet du composant PIC16F877.

Après écriture dans le registre TIMER0, d'une valeur X, ce registre s'incrémente suivant une fréquence réglable. Il suffit de détecter le passage à zéro du registre pour obtenir un délai bien précis.

Le fonctionnement de ce TIMER0 est décrit dans la figure ci-dessous :

Le rapport du prédiviseur (prescaler) doit être mis dans le registre OPTION.

for(;;)
{
	LED=0;
    wait_ms(5000);
 
	LED=1;
	wait_ms(1000);
}
//fin du main
}

/*** Tempo ***/
// millisec=1 correspond à 1ms pour Q=20Mz 
void wait_ms(uns16 millisec)
{
    uns16 t1;
    char next = 0;
	// d'une fréquence de f0 = 5 Mhz (20 / 4) on voudrait 1000 Hz
	// ce qui ferait en final une tempo de 1 ms
    // il faut donc diviser f0 par 5000
	// dans un premier temps on divise cette fréquence f0 grâce au prédiviseur (prescaler)
	// on choisit la valeur 8 ce qui conduit à une nouvelle fréquence f1 = 5 Mhz / 8 = 625.000 Hz 
	//
	OPTION = 2; 
    // 
    // or 625 = 125*5
    // si TIMER0 compte 125 il suffit d'appeler 5 fois ce module
    //
	do {
    t1=5; 
    	do  {
        TMR0 = 130;  		// 130 = 255-125
        					// le TIMER0 s'incrémente (et pas l'inverse !)
        while (TMR0 != 0);  // on attend que TIMER0 arrive à $FF
            
    	} while (--t1!=0 );
    } while (--millisec!=0);
}

3ème méthode : utilisation du module TIMER0 avec interruption

Le module TIMER0 génère une interruption lorsqu'il arrive à zéro. Compte tenu de la valeur du prédiviseur (au maximum 256) et de la valeur du registre TIMER0 (au maximum 256), le délai d'arrivée de l'interruption est de 0,2µs * 256 * 256 = 13 ms. Si on veut des temps de l'ordre de la seconde, il sera nécessaire de compter un nombre d'interruptions.

Pour réaliser un clignotant de période 1 s (1/2) le calcul nous indique qu'il faut 40 interruptions.

Le logigramme est le suivant :

Le registre des interruptions du composant PIC16F877 s'appelle INTCON :

Pour autoriser les interruptions il faut simplement mettre GIE = 1 et TMROIE = 1

A chaque interruption le flag (TMROIF) correspondant au TIMER0 passe à un, il faut donc penser à effacer ce flag.

On remarque que le programme d'interruption est précédé de la directive #pragma origin 4, en effet le vecteur d'interruption se trouve à l'adresse 0004h..

#pragma origin 4
/*** Timer0 ***/
// le programme d'interruption se déclenche chaque fois que le TIMER0 arrive à terme

interrupt IT_timer0(void)
{
// VARIABLES
	static uns16 compteurIT, delay1, delay2;
		
	int_save_registers
 	//char sv_FSR = FSR;
		
 	compteurIT = compteurIT + 1; // compte le nombre d'interruptions
 	delay1 = 40;
 	delay2 = 80;
 	
 	if (compteurIT < delay1 ){
		LED = 1;
	}
	if (compteurIT > delay1  && compteurIT < delay2){
		LED =0;
	}
	if (compteurIT > delay2){
		compteurIT = 0;
	}		
	T0IF = 0;	// on efface le Flag pour autoriser d'autres interruptions
 		
	//FSR = sv_FSR; 
	int_restore_registers
	
}

/****************************************************/
// DECLARATION PROCEDURES

/****************************************************/
void main(void)
{
// VARIABLES
 	  	  
/****************************************************/
// TIMER0
	OPTION = 0b.0000.0111; 	// prédiviseur du quartz par 256
	
/****************************************************/
// INTERRUPTION
    INTCON = 0b.1010.0000;  // on autorise les interruptions du TIMER0
    		  				// on autorise toutes les interruptions
        
/****************************************************/
// INHIBITION FONCTIONS INUTILES    
 	ADCON1 = 0x06; 			// Port A utilisé en I/O digital
           
/****************************************************/	
// PORTA 
	PORTA = 0b.0000.0000;
	TRISA = 0b.0000.0000; 	// 0 = Output, 1 = Input  		
	
   
TMR0 = 12;  		// on met 244 dans le TIMER0 
// 0,2µs * 256 * 244 * 40 = 0,5 s 

for(;;)
{
	nop();   
}	
    
//fin du main
}