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
}

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