Programació en C del PIC 16F690

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

Joc d'enfonsar vaixells electrònic

Programa del grup 4

En aquest cas hi ha un jugador que intenta enfonsar els vaixells que ha situat la màquina. El programa situa quatre vaixells de manera aleatòria:

Mida Nombre de vaixells
4 caselles 1
3 caselles 1
2 caselles 1
4 caselles en forma l'ela 1

Els colors dels LED de la matriu representen:

Color Significat
Apagat Casella sobre la que no s'ha disparat
Blau Aigua
Vermell Tocat
Verd Posició del cursor

Els polsadors de la part inferior serveixen per moure el cursor i per disparar sobre la casella actual, segons el següent ordre:

Polsador Funció
1 Esquerra
2 Dreta
3 Amunt
4 Avall
5 Disparar

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>
#define _XTAL_FREQ  4000000  // La freqüència del rellotge és 4 MHz
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 figura[8];  // Aquí guardarem el dibuix (8 fileres) de les aigües
char vaixells[8];  // Aquí guardarem el dibuix (8 fileres) dels vaixells
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)
             // Y = 0 és la fila de dalt
char mirar = 1;  // Espera que es deixi anar el polsador
char conta_vaixells[4]={0,0,0,0};  // Nombre de tocs que ha rebut cada vaixell
char pok=0;  // Diu quin vaixell s'ha tocat
char led_vaixells=0;  // Diu els LED que s'han d'il·luminar
char led_matriu=1;  // Marca la posició que s'ataca
int punts=0;  // Comptador de la puntuació
signed char graella1[26];  // Guarda la posició X i Y del vaixell
signed char dx[4]= { 1, -1, 0, 0};  // Per escollir la direcció X del vaixell quan es crea
signed char dy[4]= { 0, 0, 1, -1};  // Per escollir la direcció Y del vaixell quan es crea
// Missatges de text que s'envien a la pantalla (es guarden a la memòria de dades)
const unsigned char Tocat[5] __at(0x260) = {84, 79, 67, 65, 84};  
const unsigned char Enfonsat[8] __at(0x265) = {69, 78, 70, 79, 78, 83, 65, 84};
const signed char Benvingut[15] __at(0x273)={66, 69, 78, 86, 73, 78, 71, 85, 84, 80, 82, 69, 77, 32, 53};
const unsigned char Aigua[5] __at(0x288) = {65, 73, 71, 85, 65};
const signed char Victoria[11] __at(0x293) = {72, 65, 83, 32, 71, 85, 65, 78, 89, 65, 84};
const signed char Punts[7] __at(0x304) = {80, 85, 78, 84, 83, 58, 32};
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
char Polsador(void);  // Funció de lectura dels polsadors
char posok (char x, char y);  // Diu si s'ha tocat vaixell i quin
// Escriuen missatges per pantalla i que soni el brunzidor
void aigua (void);  
void tocat (void);
void enfonsat (void);
void inici (void);
void victoria(void);
// Funcions auxiliars per obrir i tancar ports
void obreportsbrun(void);
void tancaportsbrun(void);
void creavaixells(void);  // Crea una distribució de vaixells aleatòria
void polsador3(void);  // Ataca la posició que vulguis
void polsador3toc(char x);  // Difèrencia entre victòria, enfonsat i tocat i encén els LED individuals
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
void score (void);  // Ensenya la puntuació per pantalla
unsigned char llegir_MemProg(unsigned short adre);  // Llegeix de la memòria del programa
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);  // Fa sonar el brunzidor
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();  
  Actiu = 1;  // Activa el color vermell
  TMR0 = 150;  // Presselecció de 150
  INTCON = 0b10100000;  // 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
  RCSTAbits.SPEN = 1;  // Activa comunicació sèrie
  TXSTAbits.TXEN = 1;  // Activa comunicació
  for (char k = 0; k < 8; k++){
    figura[k] = 0;  // Comencem amb tots els LED apagats
    vaixells[k]=0;
  }
  __delay_ms(1000);
  inici(); 
  while (Polsador()!=5){
    ;  // Posa el joc en standby fins que s'apreta el botó d'engegat
  }
  srand(TMR0);  // Defineix la llavor aleatòria en funció del temps que triga el usuari
  creavaixells();
  Esborra();
  __delay_ms(300);
  while (1){
    // 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();  
    if (mirar == 1){
      if (Polsad == 1) {  // Si s'ha premut el polsador 1 (es mou cap a la esquerra)
        x = (x + 1) % 8;  // Incrementa x però la manté entre 0 i 7
        mirar = 0;
      }
      if (Polsad == 2) {  // Si s'ha premut el polsador 2 (es mou cap a la dreta)
        if (x!=0){
          x = x - 1;
        } else {
          x=7;
        }
        mirar = 0;
      }
      if (Polsad == 3){  // Si s'ha premut el polsador 3 (es mou cap a dalt)
        if (y!=0){
          y = y - 1;
        } else {
          y=7;
        }
        mirar = 0;
      }
      if (Polsad == 4) {  // Si s'ha premut el polsador 4 (es mou cap a la baix)
        y = (y + 1) % 8;  // Incrementa y però la manté entre 0 i 7
        mirar = 0;
      }
      if (Polsad == 5) {  // Si s'ha premut el polsador 5 (ataca))
        // Invertim el LED corresponent (vermell= tocat, blau=aigua)
        polsador3();
      }
      if (Polsad == 6) {  // Si s'ha premut el polsador 0 (es reinicia)
        for (char k = 0; k < 8; k++){
          figura[k] = 0;  // Esborrem la figura
          vaixells[k]=0;  // Comencem amb tots els LED apagats
        }
        PORTC=0;
        // Reinicia totes les variables i crea una nova distribució de vaixells
        led_vaixells=0;
        for(char i = 0; i < 4; ++i){
          conta_vaixells[i] = 0;
        }
        x=0;
        y=0;
        punts=0;
        mirar = 0;
        creavaixells();
      }
    } else {
      if (Polsad == 0) {  // Si no s'ha premut cap polsador (o dos a la vegada)
        mirar = 1;
      }
    }
    score();
    // Anem a mostrar la figura actual a la matriu de LED
    for (char k = 0; k < 8; k++){
      char mascara;
      Sortida[0] = vaixells[k];  // Vermells
      Sortida[2] = 0;  // Verds
      Sortida[4] = figura[k];  // Blaus
      // El cursor es mostra verd, independentment del punt
      if (y == k){  // Si estem a la filera del cursor
        mascara = (1 << x);
        Sortida[0] = Sortida[0] & ~mascara;  //  apaga vermell
        Sortida[2] = Sortida[2] | mascara;  //  encen verd
        Sortida[4] = Sortida[4] & ~mascara;  //  apaga blau
      }
      Sortida[1] = k+1;  // Filera
      Sortida[3] = k+1;
      Sortida[5] = k+1;
      Envia3max(Sortida);  
      __delay_ms(1);
    }
  }
}
void __interrupt() temporit(void){
  if (INTCONbits.T0IF){  // Comprovem que hi ha interrupció per Timer 0
    TMR0 = 150;
    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();  
  }
}
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
}
char posok (char x, char y){
  // c1=vaixell L, c2=vaixell 2, c3=vaixell 3, c4=vaixell 4
  for (char k = 0; k < 13; k++){
    if (x==graella1[2*k] && y==graella1[2*k+1]){ //Retorna quin vaixell hem tocat
      if (k<=3){
        return 1;
      }
      if (k>= 4 && k <= 7){
        return 4;
      }
      if (k>= 8 && k<=10){
        return 3;
      }
      if (k>=11){
        return 2;
      }
    } 
  }
  return 0;
}
char posokay(signed char i,signed char j, char v){
  if (i < 0 || i > 7 || j < 0 || j >7)
    return 0;  //Comprova que la casella esta dins la matriu
  if (v != 0) {
    for (char k = 0; k < 13; ++k) {  //Comprova que no estigui tocant o en diagonal de cap vaixell ja col·locat
      if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == j))
        return 0;
      if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == (j + 1)))
        return 0;
      if ((graella1[2 * k] == i) && (graella1[2 * k + 1] == (j - 1)))
        return 0;
      if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == j))
        return 0;
      if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == j))
        return 0;
      if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == (j - 1)))
        return 0;
      if ((graella1[2 * k] == (i - 1)) && (graella1[2 * k + 1] == (j + 1)))
        return 0;
      if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == (j - 1)))
        return 0;
      if ((graella1[2 * k] == (i + 1)) && (graella1[2 * k + 1] == (j + 1)))
        return 0;
    }
  }
  return 1;
}
void creavaixells(void){
  signed char x1, y1, d;  //Seran las variables que farem servir per col·locar els vaixells
  char found = 0;  //Variable que indicarà si es pot col·locar el vaixell
  while (found == 0) {  //Posem el vaixell en forma de ela
    for(char i = 0; i < 26; ++i)
	  graella1[i] = -2;
    x1 = rand() % 8;
    y1 = rand() % 8;
    d = rand() % 4;
    while (posokay(x1, y1, 0) == 0 || posokay(x1 + dx[d], y1 + dy[d], 0) == 0) {
      x1 = rand() % 8;
      y1 = rand() % 8;
      d = rand() % 4;
    }
    for(char i = 0; i < 2; ++i){
      graella1[2*i] = x1 + i*dx[d];
      graella1[1+2*i] = y1 + i*dy[d];
    }
    signed char xi = x1 + dx[d];
    signed char yi = y1 + dy[d];
    d = (d + 2) % 4;
    if (posokay(xi + dx[d], yi + dy[d], 0) == 1 && posokay(xi + dx[d] * 2, yi + dy[d] * 2, 0)==1) {
      found = 1;
      for(char i = 0; i < 2; ++i){
        graella1[4+2*i] = xi + (i+1)*dx[d];
        graella1[5+2*i] = yi + (i+1)*dy[d];
      }
    }
  }
  // Posem el vaixell de quatre posicions
  while (posokay(x1, y1, 1) == 0 || posokay(x1 + dx[d], y1 + dy[d], 1)== 0 || posokay(x1 + 2 * dx[d], y1 + 2 * dy[d], 1) == 0 || posokay(x1 + 3 * dx[d], y1 + 3 * dy[d], 1)==0) {
    x1 = rand() % 8;
    y1 = rand() % 8;
    d = rand() % 4;
  }
  for(char i = 0; i <4; ++i){
    graella1[8+2*i] = x1 + i*dx[d];
    graella1[9+2*i] = y1 + i*dy[d];
  }
  // Posem el vaixell de tres posicions
  while (posokay(x1, y1, 2) == 0 || posokay(x1 + dx[d], y1 + dy[d], 2) == 0 || posokay(x + 2 * dx[d], y + 2 * dy[d], 2) == 0) {
    x1 = rand() % 8;
    y1 = rand() % 8;
    d = rand() % 4;
  }
  for(char i = 0; i <3; ++i){
    graella1[16+2*i] = x1 + i*dx[d];
    graella1[17+2*i] = y1 + i*dy[d];
  }
  //Posem el vaixell de dos posicions
  while (posokay(x1, y1, 3) == 0 || posokay(x1 + dx[d], y1 + dy[d], 3) == 0) {
    x1 = rand() % 8;
    y1 = rand() % 8;
    d = rand() % 4;
  }
  for(char i = 0; i <2; ++i){
    graella1[22+2*i] = x1 + i*dx[d];
    graella1[23+2*i] = y1 + i*dy[d];
  }
}

// Si no utilitzem aquestes funcions el brunzidor no se sent
void obreportsbrun(void){
  TRISC = 0b00100000;  // Definim com volem les E/S del port C
                       // RC5 (sortida del PWM), de moment, com a entrada
  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
  PIR1bits.TMR2IF = 0;  // Desactiva el bit d'interrupció del Timer 2
  T2CON = 0b00000011;
  TMR0 = 0;
}
void tancaportsbrun(void){
  TRISC = 0;
  CCP1CON = 0;
  T2CON = 0; 
  TMR0 = 150;
}
void tocat (void){ 
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  unsigned short adressa = 0x260;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 5; ++k){  //Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
  } 
  obreportsbrun();  //Fem sonar el brunzidor
  TocaNota(141, 71, 0);
  TocaNota(118, 59, 2);  
  tancaportsbrun();
}
void enfonsat (void){  
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  unsigned short adressa = 0x265;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 8; ++k){  //Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
  }  
  obreportsbrun();  //Fem sonar el brunzidor
  TocaNota(189, 95, 0);
  TocaNota(189, 95, 0);
  TocaNota(189, 95, 0);
  TocaNota(212, 106, 2);  
  TocaNota(189, 95, 0);
  tancaportsbrun(); 
}
void aigua (void){  
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  unsigned short adressa = 0x288;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 5; ++k){  //Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
  }  
  obreportsbrun();  //Fem sonar el brunzidor
  TocaNota(224, 112, 2);
  TocaNota(238, 119, 2);  
  tancaportsbrun();
}
void victoria (void){
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  unsigned short adressa = 0x293;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 11; ++k){  // Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
  }
  obreportsbrun();  // Fem sonar el brunzidor
  TocaNota(168, 84, 2);
  TocaNota(141, 71, 0);  
  TocaNota(212, 106, 2);
  TocaNota(126, 63, 2);
  TocaNota(118, 59, 2);
  tancaportsbrun();
}
void inici (void){
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  unsigned short adressa = 0x273;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 15; ++k){  //Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
    if(k == 8)
      Cursor(2, 1);
    if(k == 10)
      Cursor(2, 3);
  } 
}
void score (void){
  Esborra();  // Esborra la pantalla i posa el cursor a l'inici
  Cursor(1,1);
  unsigned short adressa = 0x304;  // Variable de 16 bits per a l'adreça
  for(char k = 0; k < 7; ++k){  //Enviem el missatge a pantalla
    EnviaL(llegir_MemProg(adressa + k));
  } 
  unsigned char Valor=punts;  // Valor a convertir (dos bytes, de 0 a 65535)
  char Digits[3];  // Variable amb el número dígit a dígit
  // Digits[0] són les unitats
  if (punts<0){  // Si els punts son negatius enviar '-' a pantalla
    EnviaL('-');
    Valor=-punts;
  }  
  if (punts==0){  // Si tenim 0 punts
    EnviaL('0');
  }  
  for (signed char j = 0; j < 3; j++){  // Guardem els tres dígits
    Digits[j] = Valor % 10 +'0';
    Valor = Valor / 10;
  }  
  unsigned char c=0;  //Si té menys de tres dígits començar per el primer diferent de zero
  for(char k = 0; k < 3; k++){
    if (Digits[2-k]!='0'){
      c=1;
    }
    if (c==1){  // Envia la puntuació a pantalla
      EnviaL(Digits[2-k]);
    }
  }
}
void polsador3(){
  led_matriu=1;
  for (signed char k=0;k<x;k++){  // Marquem la casella
    led_matriu=led_matriu*2;
  }
  if ((vaixells[y]!=(vaixells[y]|led_matriu))&(figura[y]!=(figura[y]|led_matriu))){
    pok=posok(x,y);
    if (pok!=0)
	  polsador3toc(pok);  // Si hem tocat un vaixell anem a aquesta funció
    else {  //Si hem tocat aigua
      figura[y] = figura[y]|led_matriu;  // Actualitzem la matriu
      aigua();
      punts-=5;
      __delay_ms(500);  //delay de 4 segons aprox
      Esborra();
    }
  }
  mirar = 0;
}
void polsador3toc(char j){
  conta_vaixells[j-1]++;
  // Mirem si hem enfonsat, encenem el Led corresponent i actualitzem la puntuació
  if((j==1 && conta_vaixells[0]==4)||(j==2 && conta_vaixells[1]==2)||(j==3 && conta_vaixells[2]==3)||(j==4 && conta_vaixells[3]==4)){
    if((j-1) == 0) {
      led_vaixells=led_vaixells|0b00000001;
      punts+=25;
    }
    if((j-1) == 1){
      led_vaixells=led_vaixells|0b00000010;
      punts+=35;
    }
    if((j-1) == 2){
      led_vaixells=led_vaixells|0b00000100;
      punts+=30;
    }
    if((j-1) == 3){
      led_vaixells=led_vaixells|0b00001000;
      punts+=20;
    }
    PORTC=led_vaixells;
    enfonsat();
  } else {  //Si només hem tocat
    tocat();
    punts+=10;
  }
  __delay_ms(500);  // delay de 4 segons aprox
  Esborra();
  vaixells[y] = vaixells[y]|led_matriu;  // Actualitzem la matriu
  if (led_vaixells==0b00001111){  // Si hem enfonsat els 4 vaixells
    victoria();
    __delay_ms(1500);  // delay de 4 segons aprox
    score();
    __delay_ms(1500);  // delay de 4 segons aprox
    Esborra();
    Polsad=6;
  }
}
unsigned char llegir_MemProg(unsigned short adre) {
  // Llegeix el contingut de la memòria de programa
  // a la posició indicada per l'adreça
  EEADRH = adre/256;  // Part més significativa de l'adreça que volem llegir
  EEADR = adre%256;  // Part menys significativa de l'adreça que volem llegir
  EECON1bits.EEPGD = 1;  // Seleccionem memòria de programa i no EEPROM
  EECON1bits.RD = 1;  // Activa la lectura
  _delay(5);  // Donem temps a fer la lectura
  return EEDAT;  // Llegeix i retorna el resultat
}
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
  }
  if (PORTAbits.RA3==0){
    Pols=6;
  }
  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 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
}

 

 

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