//-----------------------------------------------------------------------------------//
// Nom du projet 		:	Coursera_Microcontroleur
// Nom du fichier 		:   main_3_8.c
// Date de création 	:   18.06.2014
// Date de modification : 	04.07.2014
// 
// Auteur 				: 	Philou (Ph. Bovey) 
//
// Description 			:   Sur des variables dont 3 seront définis, ensuite de 
//                          manière aléatoire, on "affichera" par le nb de clignotement
//							d'une led  
//
// Remarques			: 
// 	    chemin pour trouver le headerfile 
//		C:\Program Files\Microchip\MPLAB C30\support\dsPIC33F\h
//
//	    lien utile : 
//      1) pseudo-Aléatoire 
//		http://fr.openclassrooms.com/informatique/cours/l-aleatoire-en-c-et-c-se-servir-de-rand-1
//		2) taille de différents en C 
//		http://www.commentcamarche.net/contents/121-langage-c-les-types-de-donnees	
//
//----------------------------------------------------------------------------------//
//--- librairie à inclure ---// 
#if defined(__dsPIC33F__)
#include "p33Fxxxx.h"
#endif

//--- autres librairires ---// 
#include "antirebond.h"
#include <string.h>
#include <stdlib.h>

//--- Fusibles ---//	
_FOSCSEL(FNOSC_PRI); 								// utilisation du quartz de 8MHz externe 
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF  & POSCMD_XT); 	// pin OS2 garder pour l'horlohe 
													// oscillateur XT	
_FWDT(FWDTEN_OFF); 									// ne pas activer le watchdog

//--- definition ---//
#define TAILLE_TB	8								// valeur 
#define ALLUME_XX	0xFF 

#define SWITCH 		PORTDbits.RD6					// entrée
#define LED_3		LATAbits.LATA0					// sortie => LED3   
#define LEDS 		LATA							// sortie 

//--- déclaration de prototypes ---// 
char recherche_nb_1(int val_in); 					// recherche le nb de 1 (binaire) dans une variable 

int remplissage_hazard(char cmpt);  				// retourne une valeur pseudo alétoire entre 0 et 255 

void init_oscillateur(void); 						// configuration oscillateur 
void init_in_out(void);								// configuration entree - sortie  
void init_timer1(void); 							// configuration Timer1   
void activ_cligno_leds(char cmpt);					// fait clignoter une led en fonction d'une variable  
 
void affichage_position(char position); 
 
//--- déclaration de variables gloables ---//
Etat_switch pt_switch_s3; 

char cmpt_led = 0;
char active_led = 0;   
int grand_compteur;
 
//--- programme principale ---//
int main(void)
{
	//--- déclaration de variables ---// 
	char nb_1, cmpt_main;
	char cmpt_alea = 0;  
	
	int mot_binaire = 0b0000100001001100; 
	int mot_hexa = 0x3C41; 
	int mot_decimal = 1025;
	int mot_aleatoire;

	//--- initialisation ---//
	init_oscillateur(); 				// oscillateur
	init_timer1(); 						// Timer 1 
	init_in_out(); 						// IN/OUT     
	LED_3 = 0;							// Led atteinte 
	cmpt_main = 0; 						 
	
	//--- séquence d'initialisation ---//
	nb_1 = recherche_nb_1(mot_binaire); 
	activ_cligno_leds(nb_1); 
	cmpt_main++; 

	//--- boucle sans fin ---//
	while(1)
	{
		//--- si touche pressee --> changement de valeur a rechercher un '1' ---//  
		if(switch_presser(&pt_switch_s3))
		{
			switch (cmpt_main)
			{
				case 1: 
					nb_1 = recherche_nb_1(mot_hexa); 
					activ_cligno_leds(nb_1); 
					cmpt_main++;
				break; 

				case 2:
					nb_1 = recherche_nb_1(mot_decimal); 
					activ_cligno_leds(nb_1); 
					cmpt_main++;  
				break;

				case 3:
					mot_aleatoire = remplissage_hazard(cmpt_alea); 
					nb_1 = recherche_nb_1(mot_aleatoire); 
					activ_cligno_leds(nb_1);   
				break;

				default:
					LEDS = 0xFF;  
				break;  
			} 
			reset_info_touche_presser(&pt_switch_s3); 			
		}
		
		//--- incrémentation d'un compteur pour déterminer une valeur aléatoire ---// 
		cmpt_alea++; 
		if(cmpt_alea >= 255) 
			cmpt_alea = 0; 
     
	}   
}

//----------------------------------------------------------------------------------//
//--- nom 				: init_in_out
//--- entrée - sortie 	: - / - 
//--- description 		: initialisation IN/OUT ANAL/NUM --> 
//--- remarque 			: doc = section 10 
//----------------------------------------------------------------------------------//
void init_in_out(void)
{	
	//--- configuration entrée analogique ---// 

	//--- configuration entrée numérique ---//
	TRISDbits.TRISD6 = 1; 						//--> SWI3 
 	
	//--- configuration sortie numérique ---//
	TRISA = 0x00; 								// 8 bits sur le port A
	  
}

//----------------------------------------------------------------------------------//
//--- nom 				: init_oscillateur
//--- entrée - sortie 	: - / - 
//--- description 		: configuration oscillateur | clock à choix  
//-- remarque 			: doc = section 7
//----------------------------------------------------------------------------------//
void init_oscillateur(void)
{
	//--- configuration de l'oscillateur interne à 8Mhz ---//
	// utilisation formules du datasheet du DSPic33FJ256GP710A --> page 146
	// quartz utilisé sur le carte = 8MHz = Fin
	// Fcy = Fosc / 2 ; Fosc = Fin(M/(N1 N2))
	// Fin = 8Mhz --> Fosc = 16Mhz --> Fcy = 8Mhz 
	OSCCONbits.COSC 	= 3;			// sélection de l'oscillateur XT 
	OSCCONbits.CLKLOCK	= 0;			// l'horloge et la PLL peuvent être modifié 	
	
	CLKDIVbits.ROI	= 0; 				// pas d'effet si il y a interruption 
	CLKDIVbits.DOZE	= 0; 				// pas de réduction sur l'horloge Fcy /1
	CLKDIVbits.DOZEN	= 0; 		
	CLKDIVbits.PLLPRE 	= 0; 			// N1 = 2	
    CLKDIVbits.PLLPOST 	= 0; 			// N2 = 2 	
	
	PLLFBDbits.PLLDIV 	= 6;			// M = 8  

	__builtin_write_OSCCONH(0x03); 		// fonction appelant du code assembleur 
										// configuration du registre NOSC (OSCCON) --> 
										// 011 = Primary Oscillator with PLL (XTPLL, HSPLL, ECPLL)
	__builtin_write_OSCCONL(0x01);		// Active la commutation de la clock
	while(OSCCONbits.COSC != 0b011); 	//
}

//----------------------------------------------------------------------------------//
//--- nom 				: init_timer1
//--- entrée - sortie 	: - / - 
//--- description 		: initialisation timer 1 pour avoir une horloge de 50ms
//--- remarque 			: doc = section 11 
//----------------------------------------------------------------------------------//
void init_timer1(void)
{
	//--- registre de configuration du Timer1 ---//
	T1CONbits.TON = 0; 			// désactiver le timer pour la configuration 
	T1CONbits.TCS = 0; 			// clock interne
	T1CONbits.TSYNC = 0; 		// synchroniser la clock externe 	
	T1CONbits.TCKPS = 3; 		// prédivseur régler à 256 --> 8Mhz/256 = 31250Hz --> 32us 
	
	TMR1 = 0; 					// mise à zéro du registre lié au timer 

	PR1 = 15625; 				// période du timer --> 500ms/32us = 15625

	//--- registres des configurations des interruptions liées au Timer1 ---//
	IPC0bits.T1IP = 7; 			// choix de la priorité --> ici la plus élevée 7 = 111
	IFS0bits.T1IF = 0; 			// remise à zéro de l'interruption 
	IEC0bits.T1IE = 1; 			// activation de l'interruption lié au Timer1 

	T1CONbits.TON = 1; 	    	// désactiver le timer1 au démarrage
}

//----------------------------------------------------------------------------------//
//--- nom 				: _T1Interrupt
//--- entrée - sortie 	: - / - 
//--- description 		: interruption liée au  
//----------------------------------------------------------------------------------//
void __attribute__((interrupt,no_auto_psv)) _T1Interrupt( void )
{
	//---  ---//
	IFS0bits.T1IF = 0; 			// remise à zéor du flag d'interruption
	
	//--- incrémentation compteur pour led ---//
	if (active_led != 0) 
		cmpt_led++; 	 
		
	//--- lecture de la touche S3 ---//
	antirebond(&pt_switch_s3, SWITCH);

	//--- incrémentation compteur ---//
	grand_compteur++; 		
	if (grand_compteur >= 65535) 
		grand_compteur = 0; 
	
	TMR1 = 0; 				// mise à jour du registre de comptage 
	T1CONbits.TON = 1;		// activer à nouveau le Timer */ 
}


//----------------------------------------------------------------------------------//
//--- nom 				: remplissage_hazard
//--- entrée - sortie 	: cmpt / recup_alea / -  
//--- description 		: permet d'obtenir une valeur aléatoire entre 0 et 255
//--- remarque 			: voir le lien 1) 
//----------------------------------------------------------------------------------//
int remplissage_hazard(char cmpt)
{
	//--- déclaration de varibales interne ---// 
	int recup_alea; 
	int limit_inf = 0; 
	int limit_sup = 256; 

	//--- recherche d'une valeur pseudo aléatoire entre 2 valeurs ---//
	srand((grand_compteur/(int)cmpt)*recup_alea);
	recup_alea = rand() % (limit_sup - limit_inf) + limit_inf;

	//--- retoune alétoire fournie ---// 
	return recup_alea;  
}

//----------------------------------------------------------------------------------//
//--- nom 				: recherche_nb_1
//--- entrée - sortie 	: val_in / nb_1 / -  
//--- description 		: avec une valeur comme paramètre d'entrée, on retourne une 
//						  le nombre de 1 (binaire) qu'il y a dans une varibale de 
//                        type entier.   
//--- remarque 			:   
//----------------------------------------------------------------------------------//
char recherche_nb_1(int val_in)
{
	//--- déclaration de variable ---// 
	char compteur = 0;
	int modulo = 2; 
	int reste; 

	while(val_in > 0)
	{
		//--- test le reste ---// 
		if((val_in%modulo) == 1)
			compteur++; 

		//--- MAJ variable d'entrée ---// 
		val_in /= modulo;   
	}
	return compteur;  
} 

//----------------------------------------------------------------------------------//
//--- nom 				: activ_cligno_leds
//--- entrée - sortie 	: cmpt / -  / -  
//--- description 		: à l'aide de compteur sur la fonction d'interruption sur 
//						  le Timer1 et le nombre de 1, on fait clignoter une led  
//--- remarque 			:   
//----------------------------------------------------------------------------------//
void activ_cligno_leds(char cmpt)
{
	//--- déclaration de variables ---//
	char cmpt_max; 

	//--- activation du compteur pour les leds ---// 
	active_led = 1;
	cmpt_led = 0;   

	//--- pour avoir les deux états de clignotement ---//
	cmpt_max = cmpt*2; 

	while(cmpt_led < cmpt_max)
	{
		if((cmpt_led % 2) == 0) 
			LED_3 = 0; 
		else if ((cmpt_led % 2) != 0)
			LED_3 = 1;
	}

	//--- fin du clignotement avec toutes les leds allumées ---// 
	LEDS = 0xFF;
	
	//--- remise à zéro du compteur + arrêt du compteur ---//
	active_led = 0; 
}					