Programació en C del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Mastermind electrònic

Programa del grup 2

En aquest cas està previst que juguin dos jugadors i el sistema guarda la puntuació de cada un. En el moment de començar tenim quatre opcions segons el botó que es premi. El cinquè polsador activa i desactiva el so. El polsador de la part superior ens torna, en qualsevol moment, al menú principal.

Polsador Jugador Correcció
1 1 Manual
2 2 Manual
3 1 Automàtica
4 2 Automàtica
5 Activar o desactivar so
0 Torna al menú inicial

La matriu de LED es fa servir de manera que les quatre columnes de l'esquerra mostren les combinacions de colors i les quatre de la dreta mostren la correcció de la tirada corresponent. El jugador disposa de vuit intents per intentar encertar la combinació. Durant la partida, els polsadors tenen les següents finalitats:

Activitat Polsador Funció
Tirada 1 Vermell
2 Groc
3 Verd
4 Cian
5 Magenta
Correcció 1 Apagat (el color no és a la sèrie)
2 Blanc (el color no és a la posició correcta)
3 Blau (el color és a la posició correcta)

El programa és el següent:

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
#include "pic16f690.h"				// Carrega el fitxer d'adreces i paràmetres del PIC 16F690
#include <xc.h>					// Carrega el fitxer de funcions necessari per al compilador XC8
#include <stdio.h>				// Per als nombres aleatoris
#include <stdlib.h>				// Per a les variables binàries
#include <math.h>
#define _XTAL_FREQ 4000000			// La freqüència del rellotge és 4 MHz
#define Pols0	RA3			// Li assigna un nom a l'adreça del polsador superior
char Sortida[6];				// Valors a enviar al MAX7221 (48 bits)
char Actiu;					// Variable que diu quin color està actiu
						// Actiu = 0		Apagat
						// Actiu = 1		Vermell
						// Actiu = 2		Verd
						// Actiu = 3		Blau
char Polsad;					// Polsador que s'ha premut
unsigned char tanca,col,fila,mode,tinicial,bi,gi,ri, music,xtra;	// iniciem les variables generals
unsigned char blue, green, red, bc, rc, gc,d1,d2,u1,u2;
char nom1[14] = {'J', 'U', 'G','A','D','O','R',' ','1',' ',':',' ','0','0'};
char nom2[14] = {'J', 'U', 'G','A','D','O','R',' ','2',' ',':',' ','0','0'};
void Envia3max(char Val[6]);			// Envia un joc de valors als tres MAX7221 desactivant interrupcions
void Envia_max(char Valor[6]);			// Envia un joc de valors als tres MAX7221
void Ini3max(void);				// Inicialitza els tres MAX7221
void Apaga(void);				// Apaga tots els LED
void EnviaL(char Caracter);			// Envia un caràcter
void Esborra(void);				// Esborra la pantalla i posa el cursor a l'inici
void Cursor(char Filera, char Columna);		// Posiciona el cursor
						// (filera 1 a 2 i columna 1 a 32, segons pantalla)
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B, char v);
						// Funció que serveix per produir un so amb el brunzidor
char Polsador(void);				// Funció de lectura dels polsadors
char Mode(void);				// Funció que conté el joc en sí
void Final(void);				// Funció que mostra el final de la partida
char Decompose(char, char);			// Funció que diu si la variable passada a binaria tindria un 1
						// en la posició indicada
void Auto(char extra);				// Funció que corregeix la tirada
char Compare(char v1[3], char v2[3]);		// Funció que compara dos vectors de tres posicions
void main (void) {
	OPTION_REG = 0b10000101;		// Configuració de Timer0
						// Com a temporitzador basat en rellotge
						// 101 - Factor d'escala de 64
						// I resistències de pull-up desactivades (valor per defecte)
	TRISC = 0b00100000;			// Tot el port C és de sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0xFF;				// Tot el port A és d'entrada
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	PORTC = 0;				// Inicialitza a 0 el port C
	PORTB = 0;				// Inicialitza a 0 el port B
	ADCON1 = 0b00010000;			// Posa el conversor a 1/8 de la freqüència
	ADCON0 = 0b00001001;			// Activa el conversor A/D connectat a AN2
	Ini3max();				// Inicialitza els tres MAX7221
	Actiu = 1;				// Activa el color vermell
	TMR0 = 139;				// Presselecció de 139, que són 117 iteracions
						// Correspon a una interrupció cada 7,5 ms
	INTCON = 0b10100000;			// Activem GIE i T0IE
	TXSTAbits.BRGH = 1;			// Configuració de velocitat
	BAUDCTLbits.BRG16 = 0;			// Paràmetre de velocitat de 8 bits
	SPBRG = 25;				// Velocitat de 9600 baud
	TXSTAbits.SYNC = 0;			// Comunicació asíncrona
	TXSTAbits.TX9 = 0;			// Comunicació de 8 bits
	RCSTAbits.SPEN = 1;			// Activa comunicació sèrie
	TXSTAbits.TXEN = 1;			// Activa comunicació
	CCP1CON = 0b00001100;			// Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
						// DC1B = 11 (bits 5-4) els dos bits de menys pes són 0
						// CCP1M = 11xx en mode senzill els bit 0 i 1 no afecten
						// Ho posa com a configuració del PWM
	CCPR1L = 49;				// Valor que correspon a un cicle del 35 % a 440 Hz
						// Registre que ens dona l'amplada de tON
	PIR1bits.TMR2IF = 0;			// Desactiva el bit d'interrupció del Timer 2
	T2CON = 0b00000011;			// Configura el Timer 2
						// bits T2KCPS (bits 1-0) a 11 prescalat de 16
						// bit 2 (TMR2ON) a 0, Timer aturat
						// Postscaler TOUTPS (bits 6-3) no afecten al PWM
	__delay_ms(200);
	Apaga();				// Apaga tots els LED
						// Donem valors inicials a les variables generals
	col=1;					// Variable que representa les columnes de la matriu
	fila=1;					// Variable que representa les files de la matriu
	red=0;					// Variable que controla el color vermell
	green=0;				// Variable que controla el color verd
	blue=0;					// Variable que controla el color blau
	tinicial=0;				// Variable que diu si existeix una tirada inicial
	bi=0;					// Variable del color blau de la tirada inicial
	gi=0;					// Variable del color verd de la tirada inicial
	ri=0;					// Variable del color vermell de la tirada inicial
	bc=0;					// Variable que conté el blau de les primeres quatre columnes d'una fila
	gc=0;					// Variable que conté el verd de les primeres quatre columnes d'una fila
	rc=0;					// Variable que conté el vermell de les primeres quatre columnes d'una fila
	tanca=0;				// Variable que serveix per tancar bucles per acabar la partida
	music=0;				// Variable que controla la música
	d1=0;					// Variable que conté les desenes de la puntuació del jugador 1
	d2=0;					// Variable que conté les desenes de la puntuació del jugador 2
	u1=0;					// Variable que conté les unitats de la puntuació del jugador 1
	u2=0;					// Variable que conté les unitats de la puntuació del jugador 2
	xtra=0;					// Variable que emmagatzema la puntuació extra
	TocaNota(189, 95, 0,0);			// Valor que correspon aproximadament a mi3
	TocaNota(158, 79, 2,0);			// Valor que correspon aproximadament a sol3
	TocaNota(94, 33, 1,0);			// Valor que correspon aproximadament a mi4
	TocaNota(118, 41, 3,0);			// Valor que correspon aproximadament a do4
	TocaNota(105, 37, 1,0);			// Valor que correspon aproximadament a re4
	TocaNota(78, 26, 1,0);			// Valor que correspon aproximadament a sol4
	Apaga();
	TRISC = 0b11110111; 			// Posa el bit 3 del port C com a sortida
	PORTC = 0b000001000;			// Activa el bit 3 del port C i, per tant, encén el LED
	TRISC = 0b00100000;			// Tot el port C és de sortida
	while (1) { 
		Apaga();
		Polsad = Polsador();
		Esborra();			// Esborra la pantalla i posa el cursor a l'inici
		for (int k = 0; k < 14; k++){
			EnviaL(nom1[k]);
		}
		Cursor(2, 1);			// Posició
		for (int k = 0; k < 14; k++){
			EnviaL(nom2[k]);
		}
		if (Polsad == 1) {		// Mode de joc de correcció manual on adivina el jugador 1
			mode=0;
			__delay_ms(100);
			u1=u1+Mode();
			tanca=0;
			fila=1;
			if (u1>=10){
				d1=d1+1;
				u1=u1-10;
			}
		} 
		if (Polsad == 2) {		// Mode de joc de correcció manual on adivina el jugador 2
			mode=0;
			__delay_ms(100);
			u2=u2+Mode();
			tanca=0;
			fila=1;
			if (u2>=10){
				d2=d2+1;
				u2=u2-10;
			}
		}
		if (Polsad == 3) {		// Mode de joc de correcció automàtica on adivina el jugador 1
			mode=1;
			__delay_ms(100);
			u1=u1+Mode();
			tanca=0;
			fila=1;
			if (u1>=10){
				d1=d1+1;
				u1=u1-10;
			}
		} 
		if (Polsad == 4) {		// Mode de joc de correcció automàtica on adivina el jugador 2
			mode=1;
			__delay_ms(100);
			u2=u2+Mode();
			tanca=0;
			fila=1;
			if (u2>=10){
				d2=d2+1;
				u2=u2-10;
			}
		}
		if (Polsad==5) {				
			if (music==0){				// Desactiva el so i apaga el primer LED superior
				music=-1;
				TRISC = 0b11110111;		// Posa els bits 0 i 2 del port C com a sortida
				PORTC = 0b00000000;		// Desctiva el bit 3 del port C i, per tant, encén el LED
				TRISC = 0b00100000;		// Tot el port C és de sortida
			} else {				// Activa el so i encen el primer LED superior
				music=0;
				TRISC = 0b11110111; 		// Posa els bits 0 i 2 del port C com a sortida
				PORTC = 0b00001000;		// Activa el bit 3 del port C i, per tant, encén el LED
				TRISC = 0b00100000;		// Tot el port C és de sortida
			}
		}
		nom1[12]='0'+d1;		// Actualitzem la variable de les desenes de la puntuació del jugador 1
		nom1[13]='0'+u1;		// Actualitzem la variable de les unitats de la puntuació del jugador 1
		nom2[12]='0'+d2;		// Actualitzem la variable de les desenes de la puntuació del jugador 2
		nom2[13]='0'+u2;		// Actualitzem la variable de les unitats de la puntuació del jugador 2
	} 
} 
void __interrupt() temporit(void) {
	INTCONbits.GIE = 0;			// Desactiva les interrupcions momentàniament
	if (INTCONbits.T0IF) {			// Comprovem que hi ha interrupció per Timer 0
		TMR0 = 139;			// Preselecció de Timer0
		INTCONbits.T0IF = 0;		// Desactiva el bit que indica interrupció pel Timer0
		if (Actiu != 0) {		// Si la matriu no està apagada
			Actiu--;		// Passem a activar un altre color
			if (Actiu == 0) {	// Si hem arribat a zero
				Actiu = 3;	// Torna a posar el 3
			}
		}
						// D'entrada els desactivem els tres
		Sortida[0] = 0x00;		// Vermell
		Sortida[2] = 0x00;		// Verd
		Sortida[4] = 0x00;		// Blau
		if (Actiu == 1) {		// Si és vermell
			Sortida[0] = 0x01;	// Vermell activat
		}
		if (Actiu == 2) {		// Si és verd
			Sortida[2] = 0x01;	// Verd activat
		}
		if (Actiu == 3) {		// Si és blau
			Sortida[4] = 0x01;	// Blau activat
		}
		Sortida[1] = 0x0C;		// Shutdown mode
		Sortida[3] = 0x0C;		// Shutdown mode
		Sortida[5] = 0x0C;		// Shutdown mode
		Envia_max(Sortida);		// Ho envia al MAX7221
	}
	INTCONbits.GIE = 1;			// Reactiva les interrupcions a l'acabar
}
void Auto(char extra) {
	unsigned char ba=0;
	unsigned char ga=0;
	unsigned char ra=0;
						// Descomposem la tirada inicial per posicions
	char Ti1[3]={Decompose(bi,1)>>7, Decompose(gi,1)>>7, Decompose(ri,1)>>7};
	char Ti2[3]={Decompose(bi,2)>>6, Decompose(gi,2)>>6,Decompose(ri,2)>>6};
	char Ti3[3]={Decompose(bi,3)>>5,Decompose(gi,3)>>5,Decompose(ri,3)>>5};
	char Ti4[3]={Decompose(bi,4)>>4,Decompose(gi,4)>>4,Decompose(ri,4)>>4};
						// Descomposem la tirada actual per posicions
	char T1[3]={Decompose(blue,1)>>7,Decompose(green,1)>>7,Decompose(red,1)>>7};
	char T2[3]={Decompose(blue,2)>>6,Decompose(green,2)>>6,Decompose(red,2)>>6};
	char T3[3]={Decompose(blue,3)>>5,Decompose(green,3)>>5,Decompose(red,3)>>5};
	char T4[3]={Decompose(blue,4)>>4,Decompose(green,4)>>4,Decompose(red,4)>>4};
						// Comparem les posicions i establim les correccions
	if (Compare(T1,Ti1)){			// Posició 1 de la tirada inicial igual a la posició 1 de la tirada actual
		ba=ba+8;			// Blau en la correcció
	} else {
		if(Compare(T1,Ti2) || Compare(T1,Ti3) || Compare(T1,Ti4)){
						// Posició actual 1 del mateix color que alguna de
						// les posicions de la tirada incial exceptuant la posició 1
						// Blanc en la correcció
			ba=ba+8;
			ga=ga+8;
			ra=ra+8;
			xtra=xtra+1;		// Sumem 1 a la putuació extra
		} else {			// LED apagat en la correcció
			xtra=xtra+2;		// Sumem 2 a la puntuació extra
		} 
	}
	if (Compare(T2,Ti2)){
		ba=ba+4;
	} else {
		if(Compare(T2,Ti3) || Compare(T2,Ti1) || Compare(T2,Ti4)){
			ba=ba+4;
			ga=ga+4;
			ra=ra+4;
			xtra=xtra+1;
		} else {
			xtra=xtra+2;
		} 
	}
	if (Compare(T3,Ti3)){
		ba=ba+2;
	} else {
		if(Compare(T3,Ti2) || Compare(T3,Ti1) || Compare(T3,Ti4)){
			ba=ba+2;
			ga=ga+2;
			ra=ra+2;
			xtra=xtra+1;
		} else {
			xtra=xtra+2;
		}
	}
	if (Compare(T4,Ti4)){
		ba=ba+1;
	} else {
		if(Compare(T4,Ti2) || Compare(T4,Ti1) || Compare(T4,Ti3)){
			ba=ba+1;
			ga=ga+1;
			ra=ra+1;
			xtra=xtra+1;
		} else {
			xtra=xtra+2;
		} 
	}
	if (extra==0) {				// Quan volem que surti la correcció i no ens importa l'extra
		xtra=0;
		blue=blue+ba;
		red=red+ra;
		green=green+ga;

		Sortida[1] = fila;		
		Sortida[3] = fila;
		Sortida[5] = fila;
		Sortida[0] = red;		// Vermells
		Sortida[2] = green;		// Verds
		Sortida[4] = blue;		// Blaus
		Envia3max(Sortida);		// Ho envia al MAX7221
	}	
}
char Decompose(char convert, char len){			
	unsigned char bin=0;
	if (len ==1 && (convert & 128)==128){	// Mira si el vuitè bit de convert és 1
		bin=128; 
	}
	if (len ==2 && (convert & 64)==64){	// Mira si el setè bit de convert és 1
		bin=64;
	}
	if (len ==3 && (convert & 32)==32){
		bin=32; 
	}
	if (len ==4 && (convert & 16)==16){
		bin=16; 
	}
	if (len ==5 && (convert & 8)==8){
		bin=8; 
	}
	if (len ==6 && (convert & 4)==4){
		bin=4; 
	}
	if (len ==7 && (convert & 2)==2){
		bin=2; 
	}
	if (len ==8 && (convert & 1)==1){
		bin=1;	
	}
	return bin;
}
char Compare(char v1[3], char v2[3]) {
	return (v1[0]==v2[0] && v1[1]==v2[1] && v1[2]==v2[2]);	// Comparem dos vectors de tres posicions
}
char Mode(void) {				// Joc en sí
	Apaga();
	blue=0;					// Retornem les variables generals als valors inicials
	green=0;
	red=0;
	col=0;
	tinicial=0;
	bi=0;
	ri=0;
	gi=0;
	bc=0;
	rc=0;
	gc=0;
	while (tanca==0) {
		unsigned char Compta = 0;	// Variable local per comptar
		unsigned char var=0;		// Variable que porta el valor del bit relacionat
						// a la posició de la fila
		Polsad = Polsador();		// Llegim els polsadors
		if (col==1) {
			var=128;
		}
		if (col==2) {
			var=64;
		}
		if (col==3) {
			var=32;
		}
		if (col==4) {
			var=16;
		}
		if (col==5) {
			if (tinicial==0) {	// Si no existeix tirada inicial agafa la tirada actual com a
						// aquesta i torna als valors inicials les variables
				bi=blue;
				gi=green;
				ri=red;
				var=0;
				col=0;
				red=0;
				green=0;
				blue=0;
				Apaga();
				tinicial=1;	// Tenim tirada inicial
			} else {
				var=8;
				if (mode==1){	// Si estem en el mode d'autocorregir completa la fila
						// amb la correcció
					Auto(0);
					col=9;
				}
			}
		} 
		if (col==6) {
			var=4;
		}
		if (col==7) {
			var=2;
		}
		if (col==8) {
			var=1;
		}
		if (col==9) {			// Hem acabat la fila de la matriu
			bc=Decompose(blue,5)+Decompose(blue,6)+Decompose(blue,7)+Decompose(blue,8);
						// Ens quedem amb les últimes quatre columnes de la tirada actual
			rc=Decompose(red,5)+Decompose(red,6)+Decompose(red,7)+Decompose(red,8);
			gc=Decompose(green,5)+Decompose(green,6)+Decompose(green,7)+Decompose(green,8);
			if ((bc==15 && rc==0 && gc==0) || fila==8) {
						// En cas que la correcció indiqui que s'ha encertat la combinació
						// o s'hagi arribat al límit de tirades s'envia al final de la partida
				__delay_ms(400);
				Apaga();
				Final();
				__delay_ms(100);
				tanca=1;
			} else {		// Mentre no haguem arribat al límit de tirades ni haguem acertat
						// la combinació
						// Tornem algunes variables generals a 0 i sumem 1 a la fila
				var=0;
				col=0;
				red=0;
				green=0;
				blue=0;
				fila++;
			}	
		}
		if (Pols0 == 0) {		// Si s'apreta el botó superior es torna al menú
						// principal sense actualitzar el marcador
			fila=0;
			tanca=1;
		}
		if (Polsad == 1) {		// Si s'ha premut el polsador 1
			if(col>=5){		// Si s'està corregint deixa el LED apagat i passa a la següent posició
				;
			} else {		// Si s'està endevinant marca el color vermell
				red=var+red; 
			}
			Sortida[1] = fila;	// Filera
			Sortida[3] = fila;
			Sortida[5] = fila;
			Sortida[0] = red;	// Vermells
			Sortida[2] = green;	// Verds
			Sortida[4] = blue;	// Blaus
			Envia3max(Sortida);
		}				// Ho envia al MAX7221
		if (Polsad == 2) {		// Si s'ha premut el polsador 2
			if(col>=5){		// Si s'està corregint encén el LED de color blanc
				red=red+var;
				green=green+var;
				blue=blue+var;
			}else {			// Si s'està endevinant encén el LED de color groc
				red=var+red;
				green=var+green;
			}
			Sortida[1] = fila;	// Filera
			Sortida[3] = fila;
			Sortida[5] = fila;
			Sortida[0] = red;	// Vermells
			Sortida[2] = green;	// Verds
			Sortida[4] = blue;	// Blaus
			Envia3max(Sortida);
		}
		if (Polsad == 3) {		// Si s'ha premut el polsador 3
			if(col>=5){		// Si s'està corregint encén el LED de color blau
				blue=blue+var;
			}else {			// Si s'està endevinant encén el LED de color verd
				green=var+green; 
			}
			Sortida[1] = fila;	// Filera
			Sortida[3] = fila;
			Sortida[5] = fila;
			Sortida[0] = red;	// Vermells
			Sortida[2] = green;	// Verds
			Sortida[4] = blue;	// Blaus
			Envia3max(Sortida);
		}
		if (Polsad == 4) {		// Si s'ha premut el polsador 4
			if(col>=5){		// Si s'està corregint no fa res
				col=col-1; 
			} else {		// Si s'està endevinant encén el LED de color cian
				Sortida[1] = fila;		// Filera 
				Sortida[3] = fila;
				Sortida[5] = fila;
				Sortida[0] = red;		// Vermells
				Sortida[2] = var+green;		// Verds
				Sortida[4] = var+blue;		// Blaus
				Envia3max(Sortida);		// Ho envia al MAX7221
				green=var+green;
				blue=var+blue;	
			}
		}
		if (Polsad == 5) {		// Si s'ha premut el polsador 5
			if(col>=5){		// Si s'està corregint no fa res
				col=col-1; 
			} else {		// Si s'està endevinant encén el LED de color magenta
				Sortida[1] = fila;		// Filera 
				Sortida[3] = fila;
				Sortida[5] = fila;
				Sortida[0] = var+red;		// Vermells
				Sortida[2] = green;		// Verds
				Sortida[4] = var+blue;		// Blaus
				Envia3max(Sortida);		// Ho envia al MAX7221
				red=var+red;
				blue=var+blue; 
			}
		}
		if (Polsad != 0){
			while (Polsad == 0)	// Esperem a que el polsador es deixi anar
				;		// No fem res
			do {			// Bucle per comptar quants cops detectem el polsador premut
				if (Polsad != 0)		// Si el polsador està premut
					Compta++;		// Incrementa Compta
				else				// Si no està premut
					Compta = 0;		// Posa el comptador zero
				__delay_ms(100);		// Retard de 1000 cicles
			} while (Compta < 5);	// Es repeteix fins que hem comptat 5 cops
		}
		if(Polsad!=0){			// Si es prem qualsevol polsador passem a la següent columna
			col=col+1;
		}
	}					// S'acaba el bucle
	return fila;				// Enviem la variable fila per a actualitzar la puntuació
}		
void Final (void) {
	unsigned char b2=0;			// Variable local que emmagatzema el blau de les
						// primeres quatre posicions de l'última tirada realitzada
	unsigned char g2=0;			// Variable local que emmagatzema el verd de les
						// primeres quatre posicions de l'última tirada realitzada
	unsigned char r2=0;			// Variable local que emmagatzema el vermell de les
						// primeres quatre posicions de l'última tirada realitzada
	b2=blue-bc;
	g2=green-gc;
	r2=red-rc;
	while (tanca==0) {
		Polsad = Polsador();		// Llegim els polsadors
		Sortida[1] = 1;			// Filera 1
		Sortida[3] = 1;
		Sortida[5] = 1;
		Sortida[0] = ri;		// Vermells de la tirada original
		Sortida[2] = gi;		// Verds de la tirada original
		Sortida[4] = bi;		// Blaus de la tirada original
		Envia3max(Sortida);		// Ho envia al MAX7221
		__delay_ms(100);
		Sortida[1] = 2;			// Filera 2
		Sortida[3] = 2;
		Sortida[5] = 2;
		Sortida[0] = r2;		// Vermells de l'última tirada realitzada
		Sortida[2] = g2;		// Verds de l'última tirada realitzada
		Sortida[4] = b2;		// Blaus de l'última tirada realitzada
		Envia3max(Sortida);		// Ho envia al MAX7221
		__delay_ms(100);
		if (music >= 0){		// Si la música està activada
			if (bi==b2 && ri==r2 && gi==g2){	// Si s'ha encertat la combinació sona la
								// música de victòria
				while (music<=1) {		// Inici del bucle de programa
					TocaNota(238,119,2,0);	// Valor que correspon aproximadament a DO3
					TocaNota(178,89,2,0);	// Valor que correspon aproximadament a FA3
					TocaNota(158,79,2,0);	// Valor que correspon aproximadament a SOL3
					TocaNota(141,71,0,0);	// Valor que correspon aproximadament a LA3
					TocaNota(158,79,2,0);	// Valor que correspon aproximadament a SOL3		
					__delay_ms(200);	// Retard de 0,2 s
					TocaNota(189,95,0,0);	// Valor que correspon aproximadament a MI3
					__delay_ms(200);	// Retard de 0,2 s
					music++;
				}
				if (music==2) {
					TocaNota(189,95,0,1);	// Valor que correspon aproximadament a MI3
					TocaNota(178,89,2,0);	// Valor que correspon aproximadament a FA3
					TocaNota(189,95,0,0);	// Valor que correspon aproximadament a MI3
					TocaNota(238,119,2,0);	// Valor que correspon aproximadament a DO3
					TocaNota(238,119,2,1);	// Valor que correspon aproximadament a DO3
					__delay_ms(400);	// Retard de 0,4 s
					music++;
				}
			} else {		// Si no s'ha encertat la combinació
				if (music==0) {
					TocaNota(88, 31, 1,1);	// Valor que correspon aproximadament a FA4
					TocaNota(118, 41, 3,1);	// Valor que correspon aproximadament a DO4
					TocaNota(141, 70, 0,1);	// Valor que correspon aproximadament a LA3
					TocaNota(178, 89, 2,2);	// Valor que correspon aproximadament a FA3
					music++;
				}
			}
		}
		if (Polsad != 0){		// Activant qualsevol pulsador
			Auto(1);		// Calculem la puntuació extra
			fila=fila+xtra;		// Afegim la puntuació extra a la normal
			if (music>= 0){		// Si la música estava activada torna la variable a 0
				music==0;
			}
			__delay_ms(200);				
			Apaga();
			tanca=1;		// Tanca el bucle de la funció Final i de la funció Mode
		}
	}
}
void Envia3max(char Val[6]) {			// Envia un joc de valors als tres MAX7221
	INTCONbits.GIE = 0;			// Desactiva les interrupcions momentàniament
	Envia_max(Val);
	INTCONbits.GIE = 1;			// Reactiva les interrupcions a l'acabar
}
void Envia_max(char Valor[6]) {			// Envia un joc de valors als tres MAX7221
	char Port = 0;				// Variable on guardem l'estat del port B
	char Temp;				// Variable temporal
	for (int j = 5; j >= 0; j--){		// Hem d'enviar 6 bytes
		for (int k = 1; k < 9; k++){	// De 8 bits
			Temp = Valor[j] & 0b10000000;		// Agafa el bit de més a l'esquerra
						// Temp només podrà valer 0 o 128
			if (Temp == 0) {	// Si val 0
				Port = Port & 0b11101111;	// Desactiva Data (bit 4)
			} else {		// Si val 128
				Port = Port | 0b00010000;	// Activa Data (bit 4)
			}
			Valor[j] = Valor[j] << 1;		// Rodem els bits per situar el següent
			PORTB = Port;		// Ho posa al port B
			Port = Port | 0b00100000;		// Activa Clock (bit 5) i força lectura
			PORTB = Port;		// Ho posa al port B
			Port = Port & 0b11011111;		// Desactiva Clock (bit 5)
			PORTB = Port;		// Ho posa al port B
		}
	}
	Port = Port | 0b01000000;		// Activa Latch (bit 6) per copiar a les sortides
	PORTB = Port;				// Ho posa al port B
}
void Ini3max(void) {				// Inicialitza els tres MAX7221
	char Bytes[6];				// Els sis bytes que cal enviar
	Bytes[0] = 0x00;			// Desactivat
	Bytes[1] = 0x0C;			// Shutdown mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x0C;
	Bytes[4] = 0x00;
	Bytes[5] = 0x0C;
	Envia_max(Bytes);			// Els envia
	Bytes[0] = 0x00;			// No decode
	Bytes[1] = 0x09;			// Decode mode
	Bytes[2] = 0x00;
	Bytes[3] = 0x09;
	Bytes[4] = 0x00;
	Bytes[5] = 0x09;
	Envia_max(Bytes);			// Els envia
	Bytes[0] = 0x07;			// Vuit fileres
	Bytes[1] = 0x0B;			// Scan limit
	Bytes[2] = 0x07;
	Bytes[3] = 0x0B;
	Bytes[4] = 0x07;
	Bytes[5] = 0x0B;
	Envia_max(Bytes);			// Els envia
}
void Apaga(void) {				// Apaga tots els LED
	char Bytes[6];				// Els sis bytes que cal enviar
	for (int j = 1; j <= 8; j++){		// Hem d'enviar 8 fileres
		Bytes[1] = j;			// Filera
		Bytes[3] = j;
		Bytes[5] = j;
		Bytes[0] = 0x00;		// Vermells
		Bytes[2] = 0x00;		// Verds
		Bytes[4] = 0x00;		// Blaus
		Envia3max(Bytes);		// Els envia
	}
}
void EnviaL(char Caracter) {
	INTCONbits.GIE = 0;			// Desactiva les interrupcions momentàniament
	RCSTAbits.SPEN = 1;			// Activa comunicació sèrie
	TXSTAbits.TXEN = 1;			// Activa comunicació
	TXREG = Caracter;			// Agafa el caràcter i l'envia
	__delay_ms(1);				// Donem temps
	while (PIR1bits.TXIF == 0)		// Esperem que s'acabi d'enviar
		;				// No fem res
	RCSTAbits.SPEN = 0;			// Desactiva comunicació sèrie
	TXSTAbits.TXEN = 0;			// Desactiva comunicació
	INTCONbits.GIE = 1;			// Activa les interrupcions
}
void Esborra(void) {
	EnviaL(254);				// Caràcter de control
	EnviaL(1);				// Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) {
	char Posicio = 0;			// Variable per a calcular la posició
	if (Filera == 2) {
		Posicio = 64;			// La primera columna de la segona fila és 64;
	}
	if (Columna > 0 && Columna < 33) {	// Comprovem que sigui un valor raonable
		Posicio = Posicio + Columna;	// Sumem les adreces
		Posicio = Posicio - 1;		// Restem 1 perquè numera des de 0
	}
	Posicio = Posicio + 128;		// Posa el bit de posicionat a 1
	EnviaL(254);				// Control de la posició del cursor
	EnviaL(Posicio);			// Canvia el cursor de lloc
}
char Polsador(void) {
	char Pols = 0;
	ADCON0bits.GO = 1;			// Posa en marxa el conversor
	while (ADCON0bits.GO == 1)		// Mentre no acabi
		;				// ens esperem
	if (ADRESH < 220 && ADRESH > 200) {
		Pols = 1;			// Comprova polsador 1
	}
	if (ADRESH < 194 && ADRESH > 174) {
		Pols = 2;			// Comprova polsador 2
	}
	if (ADRESH < 163 && ADRESH > 143) {
		Pols = 3;			// Comprova polsador 3
	}
	if (ADRESH < 90 && ADRESH > 70) {
		Pols = 4;			// Comprova polsador 4
	}
	if (ADRESH < 55 && ADRESH > 35) {
		Pols = 5;			// Comprova polsador 5
	}
	return Pols;
}

void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B, char v) {
	TRISC = 0b00100000;			// Definim com volem les E/S del port C
						// RC5 (sortida del PWM), de moment, com a entrada
	PR2 = ValPR2;				// Carrega PR2
	CCP1CON = CCP1CON & 0b11001111;		// Posa a zero els bits que corresponen a DC1B
	ValDC1B = ValDC1B % 4;			// DC1B va de 0 a 3
	ValDC1B = ValDC1B * 16;			// Desplaça els bits a la posició que els correspon a CCP1CON
	CCP1CON = CCP1CON + ValDC1B;		// Coloca DC1B al seu lloc
	CCPR1L = ValCCPR1L;			// Carrega CCPR1L, registre que ens dona l'amplada de tON
	PIR1bits.TMR2IF = 0;			// Desactiva el bit d'interrupció del Timer 2
	T2CON = 0b00000111;			// Configura el Timer 2
						// bits T2KCPS (bits 1-0) a 11 prescalat de 16
						// bit 2 (TMR2ON) a 1, Timer activat
						// Postscaler TOUTPS (bits 6-3) no afecten al PWM
	while (PIR1bits.TMR2IF == 0)		// Espera l'activació del bit d'interrupció del Timer 2
		;				// Esperem
	
	TRISC = 0b00000000;			// Posem RC5 (sortida del PWM) com a sortida
	if (v==0){
		__delay_ms(100);		// Retard de 0,2 s
		TRISC = 0b00100000;		// Posem RC5 (sortida del PWM) com a entrada
						// O sigui, silenci
		__delay_ms(100);		// Retard de 0,2 s
	}
	if (v==1){
		__delay_ms(150);		// Retard de 0,2 s
		TRISC = 0b00100000;		// Posem RC5 (sortida del PWM) com a entrada
						// O sigui, silenci
		__delay_ms(200);		// Retard de 0,2 s
	}
	if (v==2){
		__delay_ms(200);		// Retard de 0,2 s
		TRISC = 0b00100000;		// Posem RC5 (sortida del PWM) com a entrada
						// O sigui, silenci
		__delay_ms(200);		// Retard de 0,2 s
	}
	
}

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.