Programació en C del PIC 16F690

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

Desenvolupament de jocs senzills

El laberint

Es tracta de recórrer un laberint. Durant el trajecte, segons la dificultat, es poden anar recollint una o més monedes, acció que repercutirà en la puntuació final. La següent taula indica el significat dels diferents colors que pot representar la matriu de LED:

Color Significat
Vermell Punt final, on s'ha d'arribar
Cian Monedes a recollir
Magenta Parets del laberint
Groc Posició del jugador

Els polsadors tenen les funcions que s'indiquen a continuació:

Polsador Finalitat
1 Pujar
2 Baixar
3 Esquerra
4 Dreta
5 Escollir la dificultat

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 <xc.h>    // Carrega el fitxer de funcions
#define _XTAL_FREQ  4000000    // La freqüència del rellotge és 4 MHz
#define cic_int 5    // Nombre de cicles per a la intermitència
char Port;    // Gestió del port a la funció Envia_max
char Compta;    // Comptador de bits a la funció Envia_max
char Sortida[6];    // Valors a enviar al MAX7221 (48 bits)
char Sorti[6];    // Valors a enviar al MAX7221 des de la interrupció
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
char iniciar = 0;
char x = 7;    // Coordenada X del cursor (0 a 7)                        
char y = 0;    // Coordenada Y del cursor (0 a 7)
char TEMPS = 3;    // Emplena la barra de temps
char mirar = 1;    // Espera que es deixi anar el polsador
char compt_int = 0;    // Comptador de cicles per a la intermitència
char cur_on = 1;    // Controla l'estat del cursor
char color = 3;    // Color vermell                     
char compte = 0;    // Compta les vegades que passa el bucle
char posicions = 0;    // Controla les posicions de la barra de temps
char dificultat = 0;    // Cada valor que pren correspon a una dificultat
char t = 0;    // Controla la velocitat de la partida
               // canviant el nombre de vegades que es fa el bucle per sumar el temps
char reprodueix=0;    // Controla quantes vegades s'ha reproduit el so de victòria i reinicia el joc
char DifActual = 999;    // Comprova la dificultat (fàcil, mitja o difícil)
char JocIniciat=0;    // Comprova si la partida ha començat o no
char desplazamiento = 0;    //Desplaça els colors aleatòriament a la matriu de LED
char moneda1=0;    // Comprova si s'ha agafat la moneda 1
char moneda2=0;    // Comprova si s'ha agafat la moneda 2
char moneda3=0;    // Comprova si s'ha agafat la moneda 3
char sumaMonedes=0;    // Suma les monedes que s'han afagat
char escrit=0;    // Comprova que no es torni a escriure una paraula ja escrita a la pantalla LCD
char posMoneda=2;    // Indica la posició en que s'ha de dibuixar la moneda al final de la partida
// La matriu serveix per dibuixar les parets del laberint, així com
// per identificar les posicions que son paret i les que no
char figura[8][8] = { {0, 0, 0, 5, 0, 0, 0, 5},
                      {5, 5, 0, 5, 0, 5, 0, 5},
                      {0, 0, 0, 0, 0, 5, 0, 0},
                      {0, 5, 5, 5, 5, 5, 5, 0},
                      {0, 0, 5, 0, 0, 0, 0, 0},
                      {5, 5, 5, 0, 5, 5, 5, 0},
                      {5, 0, 0, 0, 5, 0, 5, 0},
                      {0, 0, 5, 5, 5, 0, 0, 0} };
// Definició de les funcions que farem servir 
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);   // Envia la nota musical al brunzidor
void Envia3max(char Valor[]);    // Envia un joc de valors als tres MAX7221
                                 // desactivant interrupcions
void Envia_max(void);    // 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)         
char Polsador(void);    // Funció de lectura dels polsadors
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 = 0;    // 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
                            // amb el resultat justificat per l'esquerra
    Ini3max();    // Inicialitza els tres MAX7221
    Actiu = 1;    // Activa el color vermell
    TMR0 = 100;    // Presselecció de 100, que són 156 iteracions
                   // Correspon a una interrupció cada 7,5 ms
    INTCON = 0b10100000;    // Activem GIE i T0IE
    Apaga();    // Apaga tots els LED
    ANSEL = 0b00000101;    // Configura AN0 i AN2 com entrada analògica
    ANSELH = 0;    // Desactiva les altres entrades analògiques
    TRISC = 0;    // Tot el port C és de sortida
    TRISB = 0;    // Tot el port B és de sortida
    __delay_ms(2000);    // Esperem que arrenqui la pantalla
    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
    while (1) {    // Inici del bucle de programa
        if(reprodueix == 3){    // Reinicia el joc i torna a la pantalla d'inici
            x = 7;    // Coordenada X del cursor (0 a 7)                        
            y = 0;    // Coordenada Y del cursor (0 a 7)
            TEMPS = 3;    // Emplena la barra de temps
            mirar = 1;    // Espera que es deixi anar el polsador
            compt_int = 0;    // Comptador de cicles per a la intermitència
            cur_on = 1;    // Controla l'estat del cursor
            color = 3;    // Color vermell                        
            compte = 0;    // Compta les vegades que passa el bucle  
            posicions = 0;    // Controla les posicions de la barra de temps
            dificultat = 0;    // Cada valor que pren correspon a una dificultat
            t = 0;    // Controla la velocitat de la partida, canviant el
                      // nombre de vegades que es fa el bucle per sumar el temps
            reprodueix=0;    // Controla quantes vegades s'ha reproduit el so de victòria i reinicia el joc
            DifActual=999;    // Comprova la dificultat (fàcil, mitja o difícil)
            JocIniciat=0;    // Comprova si la partida ha començat o no
            desplazamiento = 0;    // Desplaça els colors aleatòriament a la matriu de LED
            moneda1=0;    // Comprova si s'ha agafat la moneda 1              
            moneda2=0;    // Comprova si s'ha agafat la moneda 2
            moneda3=0;    // Comprova si s'ha agafat la moneda 3
            sumaMonedes=0;    // Suma les monedes que s'han afagat
            escrit=0;    // Comprova que no es torni a escriure una paraula ja escrita a la pantalla LCD
            posMoneda=2;    // Indica la posició en que s'ha de dibuixar la moneda al final de la partida
            iniciar = 0;    
        }
        if((dificultat == 0) && (iniciar == 0)&& (DifActual != 0)){
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('E');    // Lletra
            EnviaL('S');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL(' ');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('P');    // Lletra
            EnviaL('r');    // Lletra
            EnviaL('e');    // Lletra
            EnviaL('m');    // Lletra
            Cursor(2,1);    //Canvia la posició a la pantalla LCD
            EnviaL('D');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('F');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai  
            EnviaL('B');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('5');    // Nombre
            DifActual=0;    //Canvia la dificultat
        }
        if((dificultat == 1) && (iniciar == 0)&& (DifActual != 1)){ 
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('D');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('F');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('P');    // Lletra
            EnviaL('r');    // Lletra
            EnviaL('e');    // Lletra
            EnviaL('m');    // Lletra
            Cursor(2,1);    //Canvia la posició a la pantalla LCD
            EnviaL('F');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai    
            EnviaL('B');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('5');    // Nombre
            DifActual=1;    //Canvia la dificultat
            t = 160;    //Canvia el temps disponible durant la partida
        }
        if((dificultat == 2) && (iniciar == 0)&& (DifActual != 2)){
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('D');    // Lletra                             
            EnviaL('I');    // Lletra
            EnviaL('F');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('P');    // Lletra
            EnviaL('r');    // Lletra
            EnviaL('e');    // Lletra
            EnviaL('m');    // Lletra
            Cursor(2,1);    //Canvia la posició a la pantalla LCD
            EnviaL('M');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('J');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('B');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('5');    // Nombre
            DifActual = 2;    //Canvia la dificultat a triar
            t = 110;    //Canvia el temps disponible durant la partida
        }
        if ((dificultat == 3) && (iniciar == 0)&& (DifActual != 3)){    
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('D');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('F');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('L');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('P');    // Lletra
            EnviaL('r');    // Lletra
            EnviaL('e');    // Lletra
            EnviaL('m');    // Lletra
            Cursor(2,1);    //Canvia la posició del cursor a la pantalla LCD
            EnviaL('D');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('F');    // Lletra
            EnviaL('I');    // Lletra
            EnviaL('C');    // Lletra
            EnviaL('I');    // Lletra  
            EnviaL('L');    // Lletra            
            EnviaL(' ');    // Espai             
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL(' ');    // Espai 
            EnviaL('B');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('5');    // Nombre
            DifActual=3;    //Canvia la dificultat a triar
            t = 65;    //Canvia el temps disponible durant la partida
        }
        if ((iniciar == 1)&& (JocIniciat == 0)){
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('T');    // Lletra
            EnviaL('E');    // Lletra
            EnviaL('M');    // Lletra
            EnviaL('P');    // Lletra
            EnviaL('S');    // Lletra
            EnviaL(' ');    // Lletra
            EnviaL('R');    // Lletra
            EnviaL('E');    // Lletra
            EnviaL('S');    // Lletra
            EnviaL('T');    // Lletra                
            EnviaL('A');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('T');    // Lletra
            EnviaL(':');    // Símbol
            JocIniciat = 1;    // La partida passa a estar iniciada
         }
        if ((compte > t) && (posicions < 17) && (JocIniciat > 0)){
            JocIniciat = JocIniciat + 1;
            Cursor(2, posicions);    // Canvia la posició del cursor de la pantalla LCD
            EnviaL(TEMPS);    // Emplena una posició de la barra de temps
            compte = 0;    // Reinicia el compte vegades que passa el bucle del programa
            posicions = posicions + 1;  // Canvia la posició a emplenar a la barra de temps
         }
        if ((posicions == 17) && (reprodueix<3)){ //Comprova si la barra de temps està plena
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('H');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('S');    // Lletra
            EnviaL(' ');    // Espai
            EnviaL('P');    // Lletra
            EnviaL('E');    // Lletra
            EnviaL('R');    // Lletra
            EnviaL('D');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('T');    // Lletra                
            EnviaL('!');    // Símbol
            EnviaL('!');    // Símbol
            EnviaL('!');    // Símbol
            TRISC = 0b00100000;    // Definim com volem les E/S del port C
                                   // RC5 (sortida del PWM), de moment, com a entrada
            PORTC = 0;    // Desactiva les sortides del port C
            CCP1CON = 0b00001100;    // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
                                     // DC1B = 00 (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
            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
            TocaNota(189, 95, 0);    // Valor que correspon aproximadament a do3
            TocaNota(212, 106, 2);    // Valor que correspon aproximadament a re3
            TocaNota(238, 119, 2);    // Valor que correspon aproximadament a mi3
            __delay_ms(200);    // Retard de 0,2 s
            reprodueix=reprodueix+1;    // Torna a reproduir el so fins a 3 vegades
        }
        if ((posicions == 99) && (reprodueix<3)&& (escrit==0)){
            Esborra();    // Esborra la pantalla i posa el cursor a l'inici
            EnviaL('H');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('S');    // Lletra
            EnviaL(' ');    // Espai
            EnviaL('G');    // Lletra
            EnviaL('U');    // Lletra
            EnviaL('A');    // Lletra
            EnviaL('N');    // Lletra
            EnviaL('Y');    // Lletra
            EnviaL('A');    // Lletra                
            EnviaL('T');    // Lletra
            EnviaL('!');    // Símbol
            EnviaL('!');    // Símbol
            Cursor(2,1);    //Canvia la posició del cursor a la pantalla LCD
            sumaMonedes=moneda1+moneda2+moneda3; //Suma les monedes que s'han recollit durant la partida
            escrit=1;    //Canvia el valor perquè no es torni a escriure la frase
            for (signed char k = 1; k <= DifActual; k++){   //Dibuixa parells de claudàtors segons el nivell
                 EnviaL('[');    // Signe
                 EnviaL(' ');    // Espai
                 EnviaL(']');    // Lletra
            }
            if (sumaMonedes>0){    //Si no s'han aconseguit monedes no es dibuixarà res més 
                for (signed char k = 1; k <= sumaMonedes; k++){
                    // Introdueix les estrelles obtingudes dins els claudàtors
                    Cursor(2,posMoneda);    //Canvia la posició del cursor a la pantalla LCD
                    EnviaL('*');    // Símbol
                    posMoneda=posMoneda+3;    //Canvia la posició en què s'ha de mostrar la moneda 
                }
            }
            TRISC = 0b00100000;    // Definim com volem les E/S del port C
                                   // RC5 (sortida del PWM), de moment, com a entrada
            PORTC = 0;    // Desactiva les sortides del port C
            CCP1CON = 0b00001100;    // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
                                     // DC1B = 00 (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
            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
                                   // Inici del bucle de programa
            TocaNota(238, 119, 2);    // Valor que correspon aproximadament a do3
            TocaNota(212, 106, 2);    // Valor que correspon aproximadament a re3
            TocaNota(189, 95, 0);    // Valor que correspon aproximadament a mi3
            __delay_ms(200);    // Retard de 0,2 s
             TocaNota(238, 119, 2);    // Valor que correspon aproximadament a do3
            TocaNota(212, 106, 2);    // Valor que correspon aproximadament a re3
            TocaNota(189, 95, 0);    // Valor que correspon aproximadament a mi3
            __delay_ms(200);    // Retard de 0,2 s
             reprodueix=3;    // Reinicia el joc
        }
        // Mirem els polsadors
        // Un cop s'ha fet l'acció del polsador, no es tornarà a fer fins que es detecti que s'han deixat anar
        Polsad = Polsador();    // Llegim els polsadors
        if (mirar == 1){
            if ((Polsad == 5) && (iniciar == 0)){    // Si s'ha premut el polsador 5 (DIFICULTAT)
               dificultat = dificultat + 1;    // Canvia la dificultat
                mirar = 0;
            }
            if ((Polsad == 5) && (dificultat == 4) && (iniciar == 0)){
                // Si s'ha premut el polsador 5 (DIFICULTAT) quan la dificultat és difícil
                dificultat = 0;    //Torna a començar l'elecció de dificultat
                mirar = 0;    
            }
            if ((Polsad == 1) && (x < 7 && figura[y][(7-x)-1] == 0) && (iniciar > 0)){
                // Si s'ha premut el polsador 1 // ESQUERRA // LA X Y LA Y no es recorren (0,0)xy ==(0,8))
                x = (x + 1);    // Incrementa x
                mirar = 0;    
            }
            if ((Polsad == 2) && (x > 0 && figura[y][(7-x)+1] == 0) && (dificultat > 0)){
                // Si s'ha premut el polsador 2 // DRETA // LA X Y LA Y no es recorren (0,0)xy ==(0,8))
                x = (x - 1);    // Disminueix x
                mirar = 0;
                if ((iniciar == 0) ) {    // Si el joc no s'ha iniciat i es prem el polsador 2,
                                          // comença la partida
                    iniciar = 1;    // Incrementa x però la manté entre 0 i 7 
                }
            }
            if ((Polsad == 3) && (y > 0 && figura[y-1][(7-x)]  == 0) && (iniciar > 0)){
                // Si s'ha premut el polsador 3 // AMUNT // LA X Y LA Y no es recorren (0,0)xy ==(0,8))
                y = (y - 1);    // Disminueix y
                mirar = 0;
            }
            if ((Polsad == 4) && (y < 7 && figura[y+1][7-x]  == 0) && (iniciar > 0)){
                // Si s'ha premut el polsador 4 // AVALL // LA X Y LA Y no es recorren (0,0)xy ==(0,8))
                y = (y + 1);    // Incrementa y
                mirar = 0;
            } 
        } else {
            if (Polsad == 0) {    // Si no s'ha premut cap polsador (o dos a la vegada)
                mirar = 1;
            }
        }
        // Mostrarem la figura actual a la matriu de LED
        for (signed char j = 0; j < 8; j++) {    // Fileres
            char mascara;
            char col = 0;   
            for (signed char k = 0; k < 8; k++) {    // Columnes
                col = 0;    // Canvia el color
                if ((y == j) && (x == k)) {    // Si estem a la casella del cursor
                    if (cur_on == 1) {    // Si toca el cursor encès
                        col = color;    // Color actual
                    }
                } else {
                    col = figura[j][7 - k];    // Utilitzar el valor de la figura
                }
                if ((x == 7) && (y == 7)){    // Condició per a la victòria (afegirem efecte multicolor)
                     posicions=99;    
                     desplazamiento = rand() % 7;    // Desplaçament aleatori entre 0 y 6
                     if (compte % 1 == 0) {  
                        desplazamiento = rand() % 7;    // Desplaçament aleatori entre 0 y 6
                    }
                    // Apliquem el desplaçament per al color en funció de la columna
                    switch((k + desplazamiento) % 7) {  // Movem el patró de colors
                        case 0:
                            col = 2;   // Vermell
                            break;
                        case 1:
                            col = 4;   // Taronja
                            break;
                        case 2:
                            col = 5;   // Groc
                            break;
                        case 3:
                            col = 6;   // Verd
                            break;
                        case 4:
                            col = 2;   // Blau cel
                            break;
                        case 5:
                            col = 7;   // Blau
                            break;
                        case 6:
                            col = 7;   // Lila
                            break;
                    }
                }
                if (posicions == 17) {    // Condició per a la derrota (posicions == 17)
                    col = 1;    // Color per la derrota (vermell)
                    color = 1;   
                }
                if ((j == 7) && (k == 7) && (posicions != 99))  {
                    // Si estem a la casella del cursor a la última posició
                    col = 1;    
                }
                //Dibuixarem les monedes a la pantalla de LED
                //------------------CAS DE DIFICULTAT FÀCIL------------------
                // Només tindrem una moneda
                if ((j == 2) && (k == 7) &&(DifActual==1)&&(moneda1==0)&&(posicions<17)) {
                    // Si estem a la casella de la moneda
                    col=6;    // Dibuixa la moneda
                }
                if ((y == 2) && (x == 7)&&(DifActual==1)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda1=1;    
                }
                //------------------CAS DE DIFICULTAT MITJA------------------
                // Tindrem dues monedes
                if ((j == 4) && (k == 6) &&(DifActual==2)&&(moneda1==0)&&(posicions<17)) {
                    // Si estem a la casella de la moneda
                    col=6;    // Dibuixa la moneda
                }
                if ((y == 4) && (x == 6)&&(DifActual==2)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda1=1;    
                }
                if ((j == 6) && (k == 0) &&(DifActual==2)&&(moneda2==0)&&(posicions<17)) {
                    // Si estem a la casella de la moneda
                    col=6;    // Dibuixa la moneda
                }
                if ((y == 6) && (x == 0)&&(DifActual==2)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda2=1;
                }
                //------------------CAS DE DIFICULTAT DIFÍCIL------------------
                // Tindrem tres monedes
                if ((j == 4) && (k == 6) &&(DifActual==3)&&(moneda1==0)&&(posicions<17)) {
                    // Si estem a la casella de la moneda
                    col=6;    // Dibuixa la moneda
                }
                if ((y == 4) && (x == 6)&&(DifActual==3)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda1=1;
                }
                if ((j == 6) && (k == 2) &&(DifActual==3)&&(moneda2==0)&&(posicions<17)) {
                    // Si estem a la casella de la moneda
                    col=6;    // Dibuixa la moneda
                }
                if ((y == 6) && (x == 2)&&(DifActual==3)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda2=1;
                }
                if ((j == 1) && (k == 1) &&(DifActual==3)&&(moneda3==0)&&(posicions<17)) {
                    // Si estamos en la casilla del cursor
                    col=6;
                }
                if ((y == 1) && (x == 1)&&(DifActual==3)){
                    // Si passem per sobre de la casella, la moneda desapareix i es té en compte que la hem afagat
                    moneda3=1;
                }
                // Colocar los bits en la columna correspondiente
                mascara = col & 0b0000001;    // Será 1 si hay rojo
                Sortida[0] = Sortida[0] | (mascara << k);
                mascara = (col & 0b0000010) >> 1;    // Será 1 si hay verde
                Sortida[2] = Sortida[2] | (mascara << k);
                mascara = (col & 0b0000100) >> 2;    // Será 1 si hay azul
                Sortida[4] = Sortida[4] | (mascara << k);
            }
            Sortida[1] = j + 1;    // Fila
            Sortida[3] = j + 1; // Fila
            Sortida[5] = j + 1; // Fila
            Envia3max(Sortida);    // Envia al MAX7221
        }
        __delay_ms(1);
        compt_int++;
        if (compt_int == cic_int){    // Si toca intermitència
            compt_int = 0;
            cur_on = (cur_on + 1) % 2;    // Canvia el cursor
        }
    }
}
void __interrupt() temporit(void){
// void interrupt temporit(void) {    // Línia alternativa
    if (INTCONbits.T0IF) {    // Comprovem que hi ha interrupció per Timer 0
        TMR0 = 100;    // 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
        Sorti[0] = 0x00;    // Vermell
        Sorti[2] = 0x00;    // Verd
        Sorti[4] = 0x00;    // Blau
        if (Actiu == 1) {    // Si és vermell
            Sorti[0] = 0x01;    // Vermell activat
        }
        if (Actiu == 2) {    // Si és verd
            Sorti[2] = 0x01;    // Verd activat
        }
        if (Actiu == 3) {    // Si és blau
            Sorti[4] = 0x01;    // Blau activat
        }
        Sorti[1] = 0x0C;    // Shutdown mode
        Sorti[3] = 0x0C;    // Shutdown mode
        Sorti[5] = 0x0C;    // Shutdown mode
        Envia_max();    // Ho envia al MAX7221
        compte = compte + 1;
    }
}
void Envia3max(char Valor[]) {    // Envia un joc de valors als tres MAX7221
    INTCONbits.T0IE = 0;    // Desactiva les interrupcions momentàniament
    char Port = 0;    // Variable on guardem l'estat del port B
    char Temp;    // Variable temporal
    for (signed char j = 5; j >= 0; j--){    // Hem d'enviar 6 bytes
        for (signed char 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
    INTCONbits.T0IE = 1;    // Reactiva les interrupcions a l'acabar
}
void Envia_max(void) {    // Envia un joc de valors als tres MAX7221
    asm("banksel _Port");
    asm("bcf (_Port&7fh),5");    // S'assegura que Clock està desactivat
    asm("bcf (_Port&7fh),6");    // S'assegura que Latch està desactivat
    asm("movf (_Port&7fh),w");    // Agafa el valor de Port
    asm("movwf PORTB");    // I el posa al port B
    asm("banksel _Compta");
    asm("movlw 48");    // Número de bits a enviar
    asm("movwf (_Compta&7fh)");    // Variable per comptar els bits
    asm("Bucle:");
    asm("banksel _Port");
    asm("bcf (_Port&7fh),4");    // Desactiva Data. Si toca activar-ho, ja ho farem
    asm("banksel _Sorti");
    asm("rlf (_Sorti&7fh),f");    // Fa sortir el bit de més a l'esquerra cap a C
    asm("rlf ((_Sorti+1)&7fh),f");    // i roda els altres a l'esquerra
    asm("rlf ((_Sorti+2)&7fh),f");
    asm("rlf ((_Sorti+3)&7fh),f");
    asm("rlf ((_Sorti+4)&7fh),f");
    asm("rlf ((_Sorti+5)&7fh),f");
    asm("banksel _Port");
    asm("btfsc STATUS,0");    // Mira si el bit de l'esquerra era un 1
    asm("bsf (_Port&7fh),4");    // Si era 1, activa Data
    asm("movf (_Port&7fh),w");    // Agafa el valor de Port. El valor que ha canviat és Data
    asm("movwf PORTB");    // I el posa al port B
    asm("bsf (_Port&7fh),5");    // Activa Clock, forçant a llegir el bit
    asm("movf (_Port&7fh),w");    // Agafa el valor de Port. El valor que ha canviat és Clock
    asm("movwf PORTB");    // I el posa al port B
    asm("bcf (_Port&7fh),5");    // Desactiva Clock
    asm("movf (_Port&7fh),w");    // Agafa el valor de Port. El valor que ha canviat és Clock
    asm("movwf PORTB");    // I el posa al port B
    asm("banksel _Compta");
    asm("decfsz (_Compta&7fh),f");    // Decrementa Compta
    asm("goto (Bucle&7ffh)");    // Si Compta no és zero, repeteix el bucle
    asm("banksel (_Port&7fh)");
    asm("bsf (_Port&7fh),6");    // Torna a activar Latch
                                 // Els valors es copiaran a la sortida del registre
    asm("movf (_Port&7fh),w");    // Agafa el valor de Port. El valor que ha canviat és Latch
    asm("movwf PORTB");    // I el 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;
    Envia3max(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;
    Envia3max(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;
    Envia3max(Bytes);    // Els envia
}
void Apaga(void) {    // Apaga tots els LED
    char Bytes[6];    // Els sis bytes que cal enviar
    for (unsigned char 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
    }
}
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) {
    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
    __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
}
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
}

 

 

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