/*************************************************************
 * Christophe Le Lann <totofwebcreation@gmail.com>
 * http://www.totofweb.ma.cx
 *
 * Ce programme fait clignoter les pinc du port B à des
 * fréquences différentes en utilisant l'interruption sur
 * Timer 0
 *************************************************************/

/****************************************
 * Configuration du compilateur
 ****************************************/

// Quartz de 20MHz (utilisé pour les délais)
#pragma CLOCK_FREQ 20000000

/****************************************
 * Variables globales
 ****************************************/

char mavar;

/****************************************
 * Fonctions
 ****************************************/
void clignoter() {
	mavar++;
	if (mavar >= 20) {
		PORTB++;						// Incrémentation de PORTB
		mavar = 0;
	}
	/*
	 * Explication : Si on considère PORTB comme une variable binaire, on se représente alors l'état de chaque pin du port B.
	 * PORTB va donc prendre comme valeurs à intervalle de 262ms :
	 *   00000000b
	 *   00000001b
	 *   00000010b
	 *   00000011b
	 *   00000100b
	 *   00000101b
	 *   00000110b
	 *   00000111b
	 *   00001000b
	 *   .... (pour en savoir plus renseignez-vous sur le binaire)
	 * On voit donc que RB0 (le plus à droite) va clignoter à intervalle de 250ms, RB1 à intervalle de 500ms, RB2 à intervalle de 1s, ...
	 */
}

/****************************************
 * Interruptions
 ****************************************/

void interrupt() {						// appelé 76 fois par seconde
	if (INTCON & 00000100b) {			// Interruption sur TIMER0, voir page 22 de la datasheet du 16F877. l'opérateur & sert à utiliser la table de vérité AND sur les deux variables 8bits (voir BigOnOff)
		clignoter();					// appelé (((20M/4)/256)/256)/20 = 3.8 fois par secondes (toutes les 262ms)
		TMR0 = 0;						// Remise à 0 du TIMER0 pour compter jusqu'à la prochaine interruption
		clear_bit(INTCON,2);			// Efface le flag d'interruption
	}
}

/****************************************
 * Programme principal
 ****************************************/

void main() {
	OPTION_REG=00000111b;				// 1/256e, voir datasheet du 16F877
	enable_interrupt(GIE);				// Les interruptions sont activées
	set_bit(INTCON,5);					// Activation des interruptions sur TIMER0 (voir page 22 de la datasheet du 16F877)

	/*
	 * Le pic est à 20MHz, une opération prend 4 cycles d'horloges et un compteur propre à timer0 s'incrémente à chache opération.
	 * Il va donc s'incrémenter 5000000 fois par seconde (20M/4).
	 * Nous spécifions le prescaler à 1/256, c'est à dire que ce compteur ne s'incrémentera plus que toutes les 256 opérations.
	 * L'interruption sera donc appelée 19530 fois par secondes (20M/4)/256
	 * Ce compteur est un compteur 8bits, il compte donc jusqu'à 2^8 = 256. Là, il revient à 0 et ce débordement déclenche une interruption.
	 * L'interruption sera donc appelée 76 fois par secondes ((20M/4)/256)/256
	 */

	TRISB = 00000000b;					// Configuration du port B en mode sortie
	PORTB = 00000000b;					// Mise à 0V de tous les pins du port B

	while (1);							// Boucle infinie à ne rien faire sauf attendre les interruptions
}
