/*
    Programme de démonstration d'un PIC 18F2455 utilisant un quartz comme
    oscillateur externe. Voir le lien suivant pour les explications et
    le schéma utilisé : <http://www.jacquet80.eu/pic/>

    Copyright (C) 2008 Christophe Jacquet <http://www.jacquet80.eu/>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <p18f2455.h>
#include <delays.h>

// Configuration de l'horloge.
// Ce programme suppose qu'un quartz de 20 MHz est branché sur OSC1/2.

// 1) Nous voulons utiliser le quartz. Nous choisissons donc :
//    mode oscillateur extérieur HS, PLL activée, HS utilisé pour l'USB.
#pragma config FOSC = HSPLL_HS

// 2) En entrée de la PLL, il FAUT TOUJOURS du 4 MHz.
//    Le quartz étant à 20 MHz, il faut diviser par 5 la fréquence d'entrée.
//    Cette opération effectuée par le prescaler.
#pragma config PLLDIV = 5

// 3) En sortie de la PLL, le postscaler divise la fréquence par 6.
//    (C'est un choix arbitraire, nous pourrions prendre autre chose...)
//    Donc la fréquence Fosc de l'oscillateur est Fosc = 96/6 = 16 MHz.
//    Un cycle durant 4 temps, cela fait 4 millions de cycles par seconde.
//    (4 millions d'instructions par seconde pour les instructions qui
//    durent 1 cycle.)
#pragma config CPUDIV = OSC4_PLL6

// Désactivons le reset sur la pin 1. Sinon, il faudrait une résistance de
// pull-up sur la pin 1, sans quoi le PIC subit des redémarrages aléatoires.
#pragma config MCLRE = OFF

// Désactivons le watchdog, sans quoi le PIC redémarrera au bout d'un
// certain temps si le watchdog n'est pas réinitialisé.
#pragma config WDT = OFF

// Désactivons la programmation en faible tension pour éviter tout problème.
#pragma config LVP = OFF


void main() {
	unsigned char count;

	// initialisation
	ADCON1 = 0x0F;  // config. toutes les broches de PORTA en mode numérique
	TRISA = 0;      // configure le port A en tant que SORTIE
	PORTA = 0;      // initialement, toutes sorties à 0

	// boucle parcourue à raison d'une itération par seconde :
	//  - PORTA0 allumé une seconde sur deux
	//  - PORTA1 allumé pendant une seconde toutes les 10 secondes
	for(;;) {
		PORTAbits.RA0 = count & 1;

		count++;
		if(count == 10) {
			PORTAbits.RA1 = 1;
			count = 0;
		} else PORTAbits.RA1 = 0;

		// Les quelques instructions qui précèdent (de l'ordre de la dizaine
		// d'instructions machine), s'exécutent "très vite" (moins de 10 µs).
		// Négligeons donc cela, et insérons un délai d'une seconde.
		// La bibliothèque "delays" fournit une fonction pouvant attendre un
		// multiple de 10 000 cycles, Delay10KTCYx.
		// Comme vu plus haut, il faut 4 000 000 cycles pour faire une seconde
		// avec notre configuration d'horloge, soit 400 * 10 000.
		// Attention, Delay10KTCYx prend un "unsigned char", et 400 > 255,
		// donc il faut "couper en deux".
		Delay10KTCYx(200);
		Delay10KTCYx(200);
	}

	// Nous observons bien 30 allumages sur PORTA0, et 6 sur PORTA1, par
	// minute, ce qui montre que nos calculs de temps et fréquences sont bons.
}

