Programació en C del PIC 16F690

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

Desenvolupament de jocs senzills

Guitar Hero

A l'iniciar el programa estan encesos els vuit LED de la filera inferior. Els tres de l'esquerra, en color blau, representen les columnes que no es faran servir i els cinc de la dreta, en vermell, representen les columnes que corresponen al joc. Tot seguit, s'encendrà un LED groc (que representa una nota musical) a la part superior, en una columna escollida aleatòriament i anirà baixant. Quan arribi a baix, l'usuari ha d'estar prement el polsador que correspon a la columna del LED groc.

Guitar Hero

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 <stdlib.h> // rand  // Feim servir la funció rand()
#define _XTAL_FREQ  4000000  // La freqüència del rellotge és 4 MHz
#define Polsa  RA3
#define clrbit(var, bit) ((var) &= ~(1 << (bit)))
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
//VARIABLES
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
char Vides=0;  // Nombre de vides, quan vides=0 el joc s'atura
char Polsad;  // Polsador que s'ha premut (1-5, 0==(cap o 2 alhora))
short Delay=+250;  // Ens ajuda a fer _delay() variable
char k=250;
char Cicles=0;  // Compta cicles
char figura[8];  // Aquí guardarem el dibuix (8 fileres)
char x = 0;  // Coordenada X del cursor (0 a 7). X = 0 és la columna de la dreta
char y = 0;  // Coordenada Y del cursor (0 a 7)
char mirar = 1;  // Espera que es deixi anar el polsador
char Punt;  // Sistema de puntuació
char D;  // Desenes
char U;  // Unitats
char r1;  // Unitats rècord
char r2;  // Detecta l'existència d'un rècord anterior
char r3;  // Detecta l'existència d'un rècord anterior
char r4;  // Detecta l'existència d'un rècord anterior
char p1=0;  // Unitats rècord variables
char Urec=0;  // Unitats rècord
char Drec=0;  // Desenes rècord
char control;  // Variable de control de la funció TocaNota. Si és 0 nota, si és 1 silenci
int bucles;  // Comptador d'iteracions de la nota
int silenci;  // Durada del silenci
char port=0;  // Variable auxiliar del port C
char Llengua=0;  // Determina l'idioma a la pantalla LCD
char menu[14] = {'1','.','C','A',' ','2','.','E','S',' ','3','.','E','N'};
char menu2[4] = {'4','.','E','U'};
char menu3[4] = {'5','.','I','T'};
char cat1[10] = {'P','R','E','M','I',' ','B','T','N','0'};
char cat2[3] = {'P','E','R'};
char cat3[5] = {'J','U','G','A','R'};
char cas1[5] = {'P','U','L','S','E'};
char btn[4] = {'B','T','N','0'};
char cas2[4] = {'P','A','R','A'};
char eng1[5] = {'P','R','E','S','S'};
char eng2[2] = {'T','O'};
char eng3[4] = {'P','L','A','Y'};
char eus1[6] = {'S','A','K','A','T','U'};
char eus2[16] = {'E','R','R','E','P','R','O','D','U','Z','I','T','Z','E','K','O'};
char ita1[5] = {'P','R','E','M','I'};
char ita2[7] = {'G','I','O','C','A','R','E'};
//FUNCIONS 
void Envia3max(char Valor[]);  // Envia un joc de valors als tres MAX7221
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. Definició de les funcions que farem servir 
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 valPre, char valPos, char valPR2, int numbuc, int numsil);
unsigned char llegir_EEPROM(unsigned char adre);  // Llegeix el contingut de l'EEPROM a la posició indicada per l'adreça
void escriu_EEPROM(unsigned char adre, unsigned char dada);  // Escriu el valor donat a l'adreça EEPROM indicada
char Polsador(void);
void main (void) {
  OPTION_REG = 0b10000101;  // Configuració de Timer0 cCom 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
  PORTA = 1;  // Inicialitza a 1 el port A
  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 = 0b11100000;  // Activem GIE i T0IE
  Apaga();  // Apaga tots els LED
  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
  Esborra();
  while(1){
    Polsad = Polsador();  // Llegim els polsadors
    if (Polsa == 0){  // Iniciam una partida
      Vides=4;
      Punt=0;
      Delay=250;
    }
    if (Vides == 0){  // Quan s'acaba una partida, 3 tons i cara trista a la matriu
      PORTC = 0b00000000;  // Quan Vides==0 apagam  els LED
      //MELODIA
      TocaNota(0, 5, 253, 132, 100);  // Valor que correspon aproximadament a mi3
      TocaNota(0, 5, 213, 156, 100);  // Valor que correspon aproximadament a sol3
      TocaNota(0, 3, 239, 209, 100);  // Valor que correspon aproximadament a do4
      //CARA TRISTA
      Sortida[1] = 0x01;  // Filera 1
      Sortida[0] = 0b11111111;  // Vermells
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x02;  // Filera 2
      Sortida[3] = 0x02;
      Sortida[5] = 0x02;
      Sortida[0] = 0b11111111;  // Vermells
      Sortida[2] = 0b01100110;  // Verds
      Sortida[4] = 0b01100110;  // Blaus
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x03;  // Filera 3
      Sortida[3] = 0x03;
      Sortida[5] = 0x03;
      Sortida[0] = 0b11111111;  // Vermells
      Sortida[2] = 0b01100110;  // Verds
      Sortida[4] = 0b01100110;  // Blaus
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x04;  // Filera 4
      Sortida[0] = 0b11111111;  // Vermells
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x05;  // Filera 5
      Sortida[0] = 0b11111111;  // Vermells
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x06;  // Filera 6
      Sortida[3] = 0x06;
      Sortida[5] = 0x06;
      Sortida[0] = 0b11111111;  // Vermells
      Sortida[2] = 0b00111100;  // Verds
      Sortida[4] = 0b00111100;  // Blaus
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x07;  // Filera 7
      Sortida[3] = 0x07;
      Sortida[5] = 0x07;
      Sortida[0] = 0b11111111;  // Vermells
      Sortida[2] = 0b01000010;  // Verds
      Sortida[4] = 0b01000010;  // Blaus
      Envia3max(Sortida);  // Ho envia al MAX7221
      Sortida[1] = 0x08;  // Filera 8
      Sortida[0] = 0b11111111;  // Vermells
      Envia3max(Sortida);  // Ho envia al MAX7221
      Esborra();
      //PUNTUACIÓ RÈCORD
      r1 = llegir_EEPROM(0);  // Rècord
      r2 = llegir_EEPROM(1);  // Número de control: 8
      r3 = llegir_EEPROM(2);  // Número de control: 7
      r4 = llegir_EEPROM(3);  // Número de control: 3
      if ((r2==8)&&(r3==7)&&(r4==3)){ // Número de control: 873. Si no hi és posam el rècord a 00
        if (p1>r1){
          escriu_EEPROM(0, p1);  // Escriu rècord
        }
      }else{  // Número de control: 873. Si no hi és posam el rècord a 00
        escriu_EEPROM(0, p1);
        escriu_EEPROM(1, 8);
        escriu_EEPROM(2, 7);  
        escriu_EEPROM(3, 3);
      }  
      r1 = llegir_EEPROM(0);  // Unitats rècord
      p1 = r1;
      //MISSATGE FI DE LA PARTIDA + PUNTUACIÓ OBTINGUDA
      if(Llengua==2){  // Castellà
        EnviaL(' ');
        EnviaL('F');
        EnviaL('I');
        EnviaL('N');
        EnviaL(' ');
        EnviaL('D');  
        EnviaL('E');
        EnviaL(' ');
        EnviaL('P');  
        EnviaL('A');
        EnviaL('R');  
        EnviaL('T');  
        EnviaL('I');
        EnviaL('D');  
        EnviaL('A');
        Cursor(2, 2);  // Posició
        EnviaL('P');  
        EnviaL('U');
        EnviaL('N');  
        EnviaL('T');
        EnviaL('U');  
        EnviaL('A');
        EnviaL('C');  
        EnviaL('I');
        EnviaL('O');
        EnviaL('N');
        EnviaL(' ');
        EnviaL(' ');
        EnviaL(D+'0');  // Desenes
        EnviaL(U+'0');  // Unitats
      }else if(Llengua==3){  // Anglès
        Cursor(1, 4);  // Posició
        EnviaL('G');
        EnviaL('A');
        EnviaL('M');  
        EnviaL('E');
        Cursor(1,10);  // Posició  
        EnviaL('O');
        EnviaL('V');
        EnviaL('E');
        EnviaL('R');
        Cursor(2, 5);  // Posició
        EnviaL('S');  
        EnviaL('C');
        EnviaL('O');  
        EnviaL('R');
        EnviaL('E');
        EnviaL(' ');
        EnviaL(D+'0');  // Desenes
        EnviaL(U+'0');  // Unitats
      } else if(Llengua==4){  // Èuscar
        Cursor(1, 2);  // Posició
        EnviaL('J');
        EnviaL('O');
        EnviaL('K');  
        EnviaL('O');
        EnviaL('A');
        Cursor(1,9);  // Posició  
        EnviaL('A');  
        EnviaL('M');
        EnviaL('A');
        EnviaL('I');
        EnviaL('E');
        EnviaL('R');
        EnviaL('A');
        Cursor(2, 2);  // Posició
        EnviaL('P');  
        EnviaL('U');
        EnviaL('N');  
        EnviaL('T');
        EnviaL('U');
        EnviaL('A');  
        EnviaL('Z');
        EnviaL('I');  
        EnviaL('O');
        EnviaL('A');
        EnviaL(' ');
        EnviaL(' ');
        EnviaL(D+'0');  // Desenes
        EnviaL(U+'0');  // Unitats
      } else if(Llengua==5){  // Italià
        Cursor(1, 3);  // Posició
        EnviaL('G');
        EnviaL('I');
        EnviaL('O');  
        EnviaL('C');
        EnviaL('O');
        Cursor(1,9);  // Posició  
        EnviaL('F');  
        EnviaL('I');
        EnviaL('N');
        EnviaL('I');
        EnviaL('T');
        EnviaL('O');
        Cursor(2, 5);  // Posició
        EnviaL('P');  
        EnviaL('U');
        EnviaL('N');  
        EnviaL('T');
        EnviaL('I');
        EnviaL(' ');
        EnviaL(D+'0');  // Desenes
        EnviaL(U+'0');  // Unitats
      }else{  // Si no es selecciona cap llengua, per defecte en català
        EnviaL('F');
        EnviaL('I');
        EnviaL(' ');
        EnviaL('D');  
        EnviaL('E');
        EnviaL(' ');  
        EnviaL('L');
        EnviaL('A');
        EnviaL(' ');
        EnviaL('P');  
        EnviaL('A');
        EnviaL('R');  
        EnviaL('T');  
        EnviaL('I');
        EnviaL('D');  
        EnviaL('A');
        Cursor(2, 3);  // Posició
        EnviaL('P');  
        EnviaL('U');
        EnviaL('N');  
        EnviaL('T');
        EnviaL('U');  
        EnviaL('A');
        EnviaL('C');  
        EnviaL('I');
        EnviaL('O');
        EnviaL(' ');
        EnviaL(D+'0');  // Desenes
        EnviaL(U+'0');  // Unitats
      }  
      _delay(4000000);
      while (Polsa!=0){
        Apaga();
        Esborra();
        Polsad = Polsador();  // Llegim els polsadors 
        if (Polsad==1){  // Català
          Llengua=1;
        }
        if (Polsad==2){  // Castellà
          Llengua=2;
        }
        if (Polsad==3){  // Anglès
          Llengua=3;
        }
        if (Polsad==4){  // Basc
          Llengua=4;
        }
        if (Polsad==5){  // Italià
          Llengua=5;
        }
        if(Llengua==0){  // Llengua==0 inicialment
          Cursor(1,2);  // Menú per a seleccionar llengüa. Segueix normativa ISO
          for (signed char k = 0; k < 14; k++){
            EnviaL(menu[k]);
          }
          Cursor(2,4);
          for (signed char k = 0; k < 4; k++){
            EnviaL(menu2[k]);
          }
          Cursor(2,10);
          for (signed char k = 0; k < 4; k++){
            EnviaL(menu3[k]);
          }
        }
        if(Llengua==1){  // Català  
          Cursor(1, 4);  // Posició  
          for (signed char k = 0; k < 10; k++){
            EnviaL(cat1[k]);
          }
          Cursor(2, 4);  // Posició
          for (signed char k = 0; k < 3; k++){
            EnviaL(cat2[k]);
          }
          Cursor(2, 9);  // Posició  
          for (signed char k = 0; k < 5; k++){
            EnviaL(cat3[k]);
          }
        }
        if(Llengua==2){  //Castellà
          Cursor(1,3);  // Posició
          for (signed char k = 0; k < 5; k++){
            EnviaL(cas1[k]);
          }  
          Cursor(1,11);  // Posició  
          for (signed char k = 0; k < 4; k++){
            EnviaL(btn[k]);
          }
          Cursor(2, 3);  // Posició
          for (signed char k = 0; k < 4; k++){
            EnviaL(cas2[k]);
          }
          Cursor(2, 10);  // Posició
          for (signed char k = 0; k < 5; k++){
            EnviaL(cat3[k]);
          }
        }
        if(Llengua==3){  // Anglès
          Cursor(1,4);  // Posició
          for (signed char k = 0; k < 5; k++){
            EnviaL(eng1[k]);
          }
          Cursor(1,10);  // Posició
          for (signed char k = 0; k < 4; k++){
            EnviaL(btn[k]);
          }
          Cursor(2, 5);  // Posició
          for (signed char k = 0; k < 2; k++){
            EnviaL(eng2[k]);
          }
          Cursor(2, 9);  // Posició
          for (signed char k = 0; k < 4; k++){
            EnviaL(eng3[k]);
          }
        }
        if (Llengua==4){  // Basc
          Cursor(1, 3);  // Posició
          for (signed char k = 0; k < 6; k++){
            EnviaL(eus1[k]);
          }
          Cursor(1,11);  // Posició  
          for (signed char k = 0; k < 4; k++){
            EnviaL(btn[k]);
          }
          Cursor(2, 1);  // Posició
          for (signed char k = 0; k < 16; k++){
            EnviaL(eus2[k]);
          }
        }
        if (Llengua==5){  // Italià
          Cursor(1,3);  // Posició
          for (signed char k = 0; k < 5; k++){
            EnviaL(ita1[k]);
          }
          Cursor(1,11);  // Posició
          for (signed char k = 0; k < 4; k++){
            EnviaL(btn[k]);
          }
          Cursor(2, 3);  // Posició
          for (signed char k = 0; k < 3; k++){
            EnviaL(cat2[k]);
          }
          Cursor(2, 8);  // Posició
          for (signed char k = 0; k < 7; k++){
            EnviaL(ita2[k]);
          }
        }
      }
    }
    while (Vides > 0) {  // Mentre tinguem vides el joc funcionarà
      Esborra();
      //REPRESENTACIÓ DE VIDES (LED)
      if (Vides == 4){
        PORTC = 0b00001111;
      }
      if (Vides == 3){
        PORTC = 0b00001110;
      }
      if (Vides == 2){
        PORTC = 0b00001100;
      }
      if (Vides == 1){
        PORTC = 0b00001000;
      }
      //DIBUIX FILA y=7
      Sortida[1] = 0x08;  // Mantenim dibuixada la fila 0
      Sortida[5] = 0x08;
      Sortida[0] = 0b00011111;  // Vermells
      Sortida[4] = 0b11100000;  // Blaus
      Envia3max(Sortida);  // Ho envia al MAX7221
      //REPRESENTACIÓ DE PUNTS A LA PANTALLA LCD
      U=Punt%10;
      D=(Punt-U)/10;
      Esborra();  // Esborra la pantalla i posa el cursor a l'inici
      EnviaL(D+'0');  // Desenes
      EnviaL(U+'0');  // Unitats
      //PUNTUACIÓ RÈCORD
      if (Punt>p1){
        p1=Punt;
      }
      Urec=p1%10;
      Drec=(p1-Urec)/10;
      Cursor(2,1);
      EnviaL('R');
      EnviaL('E');
      EnviaL('C');
      EnviaL('O');
      EnviaL('R');
      EnviaL('D');
      EnviaL(' ');
      EnviaL(Drec+'0');  // Desenes rècord
      EnviaL(Urec+'0');  // Unitats rècord
      //MOVIMENT DE LA NOTA
      y = (y + 1) % 8;  // Incrementa y però la manté entre 0 i 7  
      Cicles=Cicles+1;  // delay per als leds baixant la columna 
      if (Cicles==7){
        Cicles=0;
        Delay=Delay-5;
      }
      if (Delay>5){
        k=Delay;
      }
      while(k>1){  // delay variable, va accelerant
        _delay(500);
        k=k-1;
      }
      if (y==0){  // Variable x random cada vegada que arribam a y=0  
        x=rand() & 0b111;  // x random per la columna següent
        while (x>=5) {  // La x ha d'ésser <=5)
          x=rand() & 0b111;
        }
      }
      //FUNCIONAMENT DELS POLSADORS
      Polsad = Polsador();  // Llegim els polsadors 
      if (y==7){  // Quan arribam a la darrera fila
        if (x==0){  // Si som a la columna 7
          if (Polsad==5){  // Si el polsador 5, corresponent a la columna 7 està activat
            Punt=Punt+1;  // Afegim 1 punt cada vegada que completa una columna  
          }else{  // Si el polsador no està activat
            Vides=Vides-1;  // Perdem una vida
            TocaNota(0, 7, 239, 105, 20);  // El brunzidor toca un do3
          }
        }
        if (x==1){
          if (Polsad==4){
            Punt=Punt+1;  
          }else{
            Vides=Vides-1;
            TocaNota(0, 7, 239, 105, 20);
          }
        }
        if (x==2){
          if (Polsad==3){
            Punt=Punt+1;  
          }else{
            Vides=Vides-1;
            TocaNota(0, 7, 239, 105, 20);
          }
        }
        if (x==3){
          if (Polsad==2){
            Punt=Punt+1;  
          }else{
            Vides=Vides-1;
            TocaNota(0, 7, 239, 105, 20);
          }
        }
        if (x==4){
          if (Polsad==1){
            Punt=Punt+1;  
          }else{
            Vides=Vides-1;
            TocaNota(0, 7, 239, 105, 20);
          }
        }
      }
      for (unsigned char k = 0; k < 8; k++){
        char mascara;
        Sortida[0] = 0;  // Vermells
        Sortida[2] = 0;  // Verds
        Sortida[4] = figura[k];  // Blaus
        // El cursor es mostra groc, independentment del punt
        if (y == k){  // Si estem a la filera del cursor
          mascara = (1 << x);
          Sortida[0] = Sortida[0] | mascara;  // Encén vermell
          Sortida[2] = Sortida[2] | mascara;  // Encén verd
          Sortida[4] = Sortida[4] & ~mascara;  // Apaga blau
        }
        Sortida[1] = k+1;  // Filera
        Sortida[3] = k+1;
        Sortida[5] = k+1;
        Envia3max(Sortida);  // Ho envia al MAX7221
        __delay_ms(1);
      }
    }
  }
}
void __interrupt() temporit(void){
  if (PIR1bits.TMR2IF) {  // Comprovem que hi ha interrupció per Timer2
    PIR1bits.TMR2IF = 0;  // Desactiva el bit que indica interrupció pel Timer2
    if (control == 0){  // Si estem tocant una nota
      flipbit(port, 5);  // Inverteix la sortida del brunzidor
      PORTC = port;  // Ho copia al port C
    }
    bucles--;  // Comptador per a la durada de la nota
    if (bucles == 0){  // Si és zero, ja ha passat la durada de la nota
      if ((control == 1) || (silenci == 0)){  // Si s'acaba el silenci
        T2CONbits.TMR2ON = 0;  // Desactiva el Timer2
        PIE1bits.TMR2IE = 0;  // Desactiva les interrupcions per Timer2
      }
      if (control == 0){  // Si estem tocant una nota
        clrbit(port, 5);  // A l'acabar, deixa la sortida desactivada
        PORTC = port;  // Ho copia al port C
        if (silenci > 0){  // Si es preveu silenci
          bucles = silenci;  // Agafem la durada del silenci
          control = 1;  // Toca silenci
        }
      }
    }
  }
  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
  }
}
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");  // 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 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
}
void TocaNota(char valPre, char valPos, char valPR2, int numbuc, int numsil) {
  // Funció per tocar una nota
  while(T2CONbits.TMR2ON)  // Si està tocant una nota
    ;  // Esperem que acabi
  valPos &= 0b00001111;  // Per precaució, posem a zero els bits no emprats
  valPre &= 0b00000011;  // Per precaució, posem a zero els bits no emprats
  T2CON = ((valPos<<3) | valPre);  // Ho posa a la configuració del temporitzador
  PR2 = valPR2;  // Preselecció del Timer2
  bucles = numbuc;  // Comptador d'iteracions
  silenci = numsil;  // Durada del silenci
  control = 0;  // Comencem tocant la nota
  PIE1bits.TMR2IE = 1;  // Activem les interrupcions per Timer2
  T2CONbits.TMR2ON = 1;  // Activem el Timer2
}
unsigned char llegir_EEPROM(unsigned char adre) {  // Llegeix el contingut de l'EEPROM a la posició indicada per l'adreça
  EECON1bits.EEPGD = 0;  // Seleccionem EEPROM i no memòria de programa
  EEADR = adre;  // Adreça que volem llegir
  EECON1bits.RD = 1;  // Activa la lectura
  return EEDATA;  // Llegeix i retorna el resultat
}
void escriu_EEPROM(unsigned char adre, unsigned char dada) { // Escriu el valor donat a l'adreça EEPROM indicada
  EECON1bits.EEPGD = 0;  // Seleccionem EEPROM i no memòria de programa
  EEDATA = dada;  // Valor que volem escriure
  EEADR = adre;  // Adreça que volem escriure
  EECON1bits.WREN = 1;  // Habilita l'escriptura
  INTCONbits.GIE = 0;  // Desactiva interrupcions
  EECON2 = 0x55;  // Cal escriure uns valors predeterminats (55h i AAh)
  EECON2 = 0xAA;  // a EECON2 per activar el procés d'escriptura
  EECON1bits.WR = 1;  // Activa l'escriptura
  while (EECON1bits.WR == 1)  // Esperem a que l'escriptura acabi
    ;
  EECON1bits.WREN = 0;  // Deshabilitem l'escriptura
  INTCONbits.GIE = 1;  // Reactivem interrupcions
}

 

 

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