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 2

En aquest cas hi ha un jugador que intenta enfonsar els vaixells que ha situat la màquina. Hi ha vuit possibles configuracions de vaixells i a cada partida se n'agafa una aleatòriament. Hi ha quatre vaixells:

Mida Nombre de vaixells
5 caselles 1
3 caselles 1
2 caselles 2

Els colors dels LED de la matriu representen:

Color Significat
Apagat Casella sobre la que no s'ha disparat
Blau Aigua
Vermell Tocat
Groc 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 Dreta
2 Avall
3 Disparar
4 Mira tirades restants
5 Reinici del joc

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>  // Carrega el fitxer on hi ha la funció rand()
#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 band = 0;  // Bandera que podem utilitzar per whiles i/o altres funcions
char figura[8];  // Aquí guardarem el dibuix de l'aigua (8 fileres)
char figura2[8];  // Aquí guardarem el dibuix dels vaixells tocats (8 fileres)
// Guardem els vaixells a la memòria del programa amb vectors de x i de y.
const char vaixells_x1[12] __at(0x500) = {1,1,5,6,7,6,5,7,6,5,4,3};
const char vaixells_y1[12] __at(0x514) = {5,6,4,4,1,1,1,7,7,7,7,7};
const char vaixells_x2[12] __at(0x526) = {5,5,5,6,0,1,2,2,2,2,2,2};
const char vaixells_y2[12] __at(0x538) = {5,6,1,1,7,7,7,0,1,2,3,4};
const char vaixells_x3[12] __at(0x552) = {0,1,6,7,6,6,6,3,3,3,3,3};
const char vaixells_y3[12] __at(0x566) = {0,0,2,2,5,6,7,2,3,4,5,6};
const char vaixells_x4[12] __at(0x580) = {0,0,3,4,6,6,6,0,1,2,3,4};
const char vaixells_y4[12] __at(0x594) = {4,5,5,5,4,5,6,2,2,2,2,2};
char vaixells_x[12];  // Coordenada x del mapa triat "random" pel programa
char vaixells_y[12];  // Coordenada x del mapa triat "random" pel programa
unsigned char mapa;  // Variable de 8 bits sense signe (0 a 255)
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 led = 0;  // Determina el nombre de vaixells enfonsats
char enfonsat;  // LED del port C encesos i apagats
char vaixell_1 = 0;  // comptador de 0 a 2
char pantalla_1 = 0;  // Bandera per encendre LED 1
char vaixell_2 = 0;  // comptador de 0 a 2
char pantalla_2 = 0;  // Bandera per encendre LED 2
char vaixell_3 = 0;  // comptador de 0 a 3
char pantalla_3 = 0;  // Bandera per encendre LED 3
char vaixell_4 = 0;  // comptador de 0 a 5
char pantalla_4 = 0;  // Bandera per encendre LED 4
char tots = 0;  // Comptador de caselles útils tocades
char torns = 25;  // Comptador de tirades restants
char copia_torns = 0;  // Còpia per imprimir en pantalla
char Torns[2];  // Vector per imprimir en pantalla les tirades restants
char reinici = 0;  // Variable que permet diferenciar el reinici del programa del final d'aquest
void Dispara(void);  // Funció que permet disparar els vaixells de la "màquina"
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
char Polsador(void);  // Funció de lectura dels polsadors
char Tocat(char coord_x, char coord_y);  // Funció que determina si hi ha un vaixell
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B);  // Funció que fa sonar el brunzidor
// Funcions per escriure
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)
// Funcions de missatges per pantalla
void Enfonsat(void);  // Missatge d'enfonsat per pantalla
void GameOver(void);  // Missatge de GameOver per pantalla
void Guanyat(void);  // Missatge d'has guanyat per pantalla
void TiradesRestants(void);  // Missatge de les tirades restants
void PremPerContinuar(void);  // Missatge per seleccionar el nivell
unsigned char llegir_MemProg(unsigned short adre);  // Funció per llegir la memòria del programa 
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)
  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
  TRISA = 0xFF;  // Tot el port A és d'entrada
  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
  PORTC = 0;  // Inicialitza a 0 el port C
  PORTB = 0;  // Inicialitza a 0 el port B
  __delay_ms(1000);
  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
  while(1){
    mirar = 1;
    torns = 25;  // Cada cop que s'inicia del programa es posa a 25
    reinici = 0;  // Desactivem la bandera de reinici de programa
    Esborra();  // Esborrem si queda alguna cosa residual a la pantalla
    PremPerContinuar();  // Missatge per pantalla
    Esborra();  // Esborrem aquest missatge per pantalla
    while(Polsador() == 0){
      ;  // Al prémer un polsador permetem triar la llavor de manera random
    }
    srand(TMR0);  // Agafa una llavor
    mapa = rand() % 9;  // Valor está entre 1 i 8
    // A continuació fem un bucle que permet adjudicar el mapa que hagi tocat de manera aleatòria
    // Per conseguir un major nombre de mapes, existeixen les opcions transposades
    for (signed char k = 0; k < 12; k++){  // Ens movem per les posicions de cada vector
      if (mapa == 1){
        vaixells_x[k] = llegir_MemProg(0x500 + k);  // LLegim a la memòria de programa
        vaixells_y[k] = llegir_MemProg(0x514 + k); 
      } else if (mapa == 2){ 
        vaixells_x[k] = llegir_MemProg(0x526 + k);
        vaixells_y[k] = llegir_MemProg(0x538 + k);
      } else if (mapa == 3){ 
        vaixells_x[k] = llegir_MemProg(0x552 + k);
        vaixells_y[k] = llegir_MemProg(0x566 + k);
      } else if (mapa == 4){     
        vaixells_x[k] = llegir_MemProg(0x580 + k);
        vaixells_y[k] = llegir_MemProg(0x594 + k);
      } else if (mapa == 5){ 
        vaixells_x[k] = llegir_MemProg(0x514 + k);
        vaixells_y[k] = llegir_MemProg(0x500 + k);
      } else if (mapa == 6){  
        vaixells_x[k] = llegir_MemProg(0x538 + k);
        vaixells_y[k] = llegir_MemProg(0x526 + k);
      } else if (mapa == 7){       
        vaixells_x[k] = llegir_MemProg(0x566 + k);
        vaixells_y[k] = llegir_MemProg(0x552 + k);
      } else if (mapa == 8){       
        vaixells_x[k] = llegir_MemProg(0x594 + k);
        vaixells_y[k] = llegir_MemProg(0x580 + k);
      }
    }
    enfonsat = 0b11110000;  // Determinarà els LED encesos segons els vaixells enfonsats
    PORTC = enfonsat;  // Variable que ens permetrà encendre els LED
    Dispara();  // Funció per disparar a cada casella
    if (reinici == 0){  // S'executa si no arribem a través del polsador 5
      if (torns > 0){  // Si torns > 0, ha guanyat
        Guanyat();  // Mostrem per pantalla que ha guanyat
        __delay_ms(500);
        TiradesRestants();  // Mostrem per pantalla les tirades restants
      } else{
        GameOver();         // Mostrem per pantalla que ha perdut
        __delay_ms(2000);
      }
    }
    // Reiniciem les variables corresponents per poder reiniciar el joc
    mirar = 0;                 
    band = 0;
    x = 0;  // Coordenada X del cursor (0 a 7)
            // X = 0 és la columna de la dreta
    y = 0;  // Coordenada Y del cursor (0 a 7)
    led = 0;  // Determina el nombre de vaixells enfonsats
    enfonsat = 0b11110000;  // LED del port C encesos i apagats
    vaixell_1 = 0;  // comptador de 0 a 2
    pantalla_1 = 0;  // Variable per mostrar el missatge enfonsat
    vaixell_2 = 0;  // comptador de 0 a 2
    pantalla_2 = 0;  // Variable per mostrar el missatge enfonsat
    vaixell_3 = 0;  // comptador de 0 a 3
    pantalla_3 = 0;  // Variable per mostrar el missatge enfonsat
    vaixell_4 = 0;  // comptador de 0 a 5
    pantalla_4 = 0;  // Variable per mostrar el missatge enfonsat
    tots = 0;  // Variable que determina si tots estan enfonsats
    torns = 0;  // comptador de tirades restants
    copia_torns = 0;  // Còpia per imprimir en pantalla
    for (signed char k = 0; k < 8; k++){
      figura[k] = 0;  // Esborrem la figura  
      figura2[k] = 0;
    }        
    Apaga();  // Apaguem els LED
  }
}
void __interrupt() temporit(void){
  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 Dispara (void){
  for (signed char k = 0; k < 8; k++){
    figura[k] = 0;  // Comencem amb tots els LED apagats
  }
  while (torns > 0 & tots < 12){
    // 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 == 1){  // Si s'ha premut el polsador 1
        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
        y = (y + 1) % 8;  // Incrementa y però la manté entre 0 i 7
        mirar = 0;
      }
      if (Polsad == 3){  // Si s'ha premut el polsador 3
                         // Invertim el LED corresponent
        if (Tocat(x,y) == 1){
          figura2[y] = figura2[y] ^ (1 << x);
          TocaNota(189, 95, 0);  // Valor que correspon aproximadament a mi3
        } else{
          figura[y] = figura[y] ^ (1 << x);
          TocaNota(238, 119, 2);  // Valor que correspon aproximadament a do3
        }
        mirar = 0;
        torns -= 1;
        // Si s'enfonsa algun dels vaixells, s'encén el LED corresponent
        if (vaixell_1 == 2){  // Si el vaixell 1 està enfonsat
          pantalla_1 += 1;
          enfonsat = enfonsat | 0b00000001;
          PORTC = enfonsat;  // Encenem el LED corresponent
          if (pantalla_1 == 1){
            Enfonsat();  // Mostrem enfonsat per pantalla
          }
        }
        // Repetim això per tots els vaixells
        if (vaixell_2 == 2){
          pantalla_2 += 1;
          enfonsat = enfonsat | 0b00000010;
          PORTC = enfonsat;
          if (pantalla_2 == 1){
            Enfonsat();
          }
        }
        if (vaixell_3 == 3){
          pantalla_3 += 1;
          enfonsat = enfonsat | 0b00000100;
          PORTC = enfonsat;
          if (pantalla_3 == 1){
            Enfonsat();
          }
        }
        if (vaixell_4 == 5){
          pantalla_4 += 1;
          enfonsat = enfonsat | 0b00001000;
          PORTC = enfonsat;
          if (pantalla_4 == 1){
            Enfonsat();
          }
        }
      }
      if (Polsad == 4){  // Si s'ha premut el polsador 4
        mirar = 0;
        TiradesRestants();  // Ens mostra les tirades restants per pantalla
      }
      if (Polsad == 5) {  // Si s'ha premut el polsador 5
        reinici = 1;  // Activem la bandera de reinici
        break;  // Sortim de la funció Dispara
      }
    } else {
      if (Polsad == 0){  // Si no s'ha premut cap polsador (o dos a la vegada)
        mirar = 1;
      }
    }
    // Anem a mostrar la figura actual a la matriu de LED
    for (unsigned char k = 0; k < 8; k++){
      char mascara;
      Sortida[0] = figura2[k];  // 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 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;
}
char Tocat(char coord_x, char coord_y){  // Funció per mirar si hi ha vaixell o aigua
  char band = 0;
  for (signed char k = 0; k < 12; k++){
    if (vaixells_x[k] == coord_x && vaixells_y[k] == coord_y){  // Comprovem si la posició és la d'un vaixell
      band = 1;  // Activa la bandera si les coordenades corresponen a un vaixell
      // Ara determinem a quin vaixell correspon
      // Com estan ordenats dins dels vectors, es fa per posicions
      if (0 <= k && k <= 1){
        vaixell_1 += 1;
        tots += 1;
      }
      if (2 <= k && k <= 3){
        vaixell_2 += 1;
        tots += 1;
      }
      if (4 <= k && k <= 6){
        vaixell_3 += 1;
        tots += 1;
      }
      if (7 <= k && k <= 11){
        vaixell_4 += 1;
        tots += 1;
      }
    }
  }
  return band;
}
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
  PORTC = 0;  // Desactiva les sortides del port C
  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;   // Configura el Timer 2
                        // bits T2KCPS (bits 1-0) a 11 prescalat de 16
                        // bit 2 (TMR2ON) a 0, Timer aturat
  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
}

// Funcions per escriure
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 Enfonsat(void){  // Missatge d'enfonsat per pantalla
  char missatge[8] = {'E','n','f','o','n','s','a','t'};
  for (signed char j = 0; j < 8; j++){
    EnviaL(missatge[j]);
  }
  __delay_ms(2000);
  Esborra();
}
void GameOver(void){  // Funció per mostrar a l'usuari, per pantalla, que ha perdut
  char missatge1[4] = {'G','a','m','e'};
  char missatge2[4] = {'O','v','e','r'};
  for (signed char j = 0; j < 4; j++){
    EnviaL(missatge1[j]);
  }
  Cursor(2,1);
  for (signed char j = 0; j < 4; j++){
    EnviaL(missatge2[j]);
  }
  __delay_ms(2000);
  Esborra();
}
void Guanyat(void){  // Funció per mostrar que l'usuari ha guanyat, per pantalla
  char missatge1[3] = {'H','a','s'};
  char missatge2[7] = {'G','u','a','n','y','a','t'};
  for (signed char j = 0; j < 3; j++){
    EnviaL(missatge1[j]);
  }
  Cursor(2,1);
  for (signed char j = 0; j < 7; j++){
    EnviaL(missatge2[j]);
  }
  __delay_ms(2000);
  Esborra();
  TiradesRestants();
}
void TiradesRestants(void){  // Funció per mostrar les tirades restants per pantalla
  char missatge_1[8] = {' ','T','i','r','a','d','e','s'};
  char missatge_2[8] = {'R','e','s','t','a','n','t','s'};
  copia_torns = torns;
  for (signed char j = 0; j < 2; j++){
    Torns[j] = copia_torns % 10;
    copia_torns = copia_torns / 10;
  }
  // afegir torns aquí
  if (Torns[1] != 0){
    EnviaL(Torns[1] +'0');
  }
  EnviaL(Torns[0] + '0');
  for (signed char j = 0; j < 8; j++){
    EnviaL(missatge_1[j]);
  }
  Cursor(2,1);
  for (signed char j = 0; j < 8; j++){
    EnviaL(missatge_2[j]);
  }
  __delay_ms(2000);
  Esborra();
}
void PremPerContinuar(void){  // Funció per mostrar el missatge següent per pantalla
  char missatge1[8] = {'P','r','e','m',' ','p','e','r'};
  char missatge2[9] = {'C','o','n','t','i','n','u','a','r'};
  for (signed char j = 0; j < 8; j++){
    EnviaL(missatge1[j]);
  }
  Cursor(2,1);
  for (signed char j = 0; j < 9; j++){
    EnviaL(missatge2[j]);
  }
  __delay_ms(2000);
}
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
}

 

 

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