En aquest cas hi ha un jugador que intenta enfonsar els vaixells que ha situat la màquina. El programa situa cinc vaixells de manera aleatòria:
| Mida | Nombre de vaixells |
| 5 caselles | 1 |
| 4 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 |
| Verd | Tocat |
| Vermell | 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 | Avall |
| 3 | Amunt |
| 4 | Dreta |
| 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 #include <stdlib.h> // Carrega el fitxer on hi ha la funció rand() #define Polsador RA3 // Li assigna un nom a l'adreça del polsador #define _XTAL_FREQ 4000000 // La freqüència del rellotge 4 MHz
char Polsad; // Polsador que s'ha premut 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 (16 bits) char Sorti[6]; // Valors a enviar al MAX7221 des de la interrupció char Actiu; // Variable que diu quin color està actiu
// Definició de les funcions que farem servir char polsador(void); // Funció de lectura dels polsadors 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 // Apaga tots els LED void cursor(int, int, char[3]);// Funció cursor dels vaixells void pintar(int, int, char[3]); // Funció pintar vaixells void ColocarVaixell(int, char[8]); //Funció que coloca vaixell aleatòriament 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 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 = 0b00100000; // Tot el port C s de sortida
TRISB = 0; // Tot el port B s de sortida
TRISA = 0xFF; // Tot el port A 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;
CCP1CON = 0b00001100;
CCPR1L = 49;
PIR1bits.TMR2IF = 0;
T2CON = 0b00000011;
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Inicialitza a 0 el port B
__delay_ms(1000);
Ini3max(); // Inicialitza els tres MAX7221
Actiu = 1; // Activa el color vermell
TMR0 = 139; // Presselecció de 139, que són 117 iteracions
// Correspon a una interrupció cada 7,5 ms
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ó
RCSTAbits.SPEN = 0; // desactiva comunicació sèrie
TXSTAbits.TXEN = 0; // desactiva comunicació
int i = 0;
int j = 0;
int tocat = 0;
int intents = 0;
char color[3];
char mascara;
char mirar = 1;
// matriu colors (estat actual del joc)
char matriu[3][8] = { {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000},
{0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000} };
// vaixells amagats
char vaixells[8] = {0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000};
__delay_ms(500); // Delay per evitar errors a la pantlla LCD i esborrar
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('P'); // Lletra
EnviaL('R'); // Lletra
EnviaL('E'); // Lletra
EnviaL('S'); // Lletra
EnviaL('S'); // Lletra
EnviaL(' '); // Lletra
EnviaL('0'); // Lletra
Cursor(2, 1); // Posició
EnviaL('6'); // Lletra
EnviaL(' '); // Lletra
EnviaL('T'); // Lletra
EnviaL('I'); // Lletra
EnviaL('M'); // Lletra
EnviaL('E'); // Lletra
EnviaL('S'); // Lletra
__delay_ms(3000); // 3 segons el missatge per indicar que ha de pulsar 6 cops el pulsador 0
Esborra();
// Coloquem el vaixells aleatoris de les mides que volem
ColocarVaixell(5, vaixells);
ColocarVaixell(4, vaixells);
ColocarVaixell(3, vaixells);
ColocarVaixell(2, vaixells);
ColocarVaixell(2, vaixells);
__delay_ms(500); // Delay per evitar errors a la pantlla LCD i esborrar
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('G'); // Lletra
EnviaL('O'); // Lletra
EnviaL('O'); // Lletra
EnviaL('D'); // Lletra
Cursor(2, 1); // Posició
EnviaL('L'); // Lletra
EnviaL('U'); // Lletra
EnviaL('C'); // Lletra
EnviaL('K'); // Lletra
__delay_ms(3000); // 3 segons el missatge de good luck per començar la partida
Esborra();
// Inici del joc, pulsadors
Apaga();
while (1) {
Polsad = polsador(); // Llegim els polsadors
color[0] = matriu[0][i]; //vermell
color[1] = matriu[1][i]; //verd
color[2] = matriu[2][i]; //blau
pintar(i, j, color);
if (mirar == 1){
if (Polsad == 1) {// Si s'ha premut el polsador 1:ESQUERRA
j = (j+1)%8;
mirar = 0;
}
if (Polsad == 2) { // Si s'ha premut el polsador 2:BAIXA
i = (i+1)%8;
mirar = 0;
}
if (Polsad == 3) { // Si s'ha premut el polsador 3:PUJA
i = (i-1)%8;
mirar = 0;
}
if (Polsad == 4) { // Si s'ha premut el polsador 4:DRETA
j = (j-1)%8;
mirar = 0;
}
if (Polsad == 5) { // Si s'ha premut el polsador 5:CONFIRMAR
mascara = 0b00000001 << j;
intents = intents + 1;
if ((vaixells[i] & mascara) != 0){ //TOCAT
tocat=tocat + 1;
matriu[1][i] = matriu[1][i] | mascara; //posem a 1 verd
}
if ((vaixells[i] & mascara) == 0){ //AIGUA
matriu[2][i] = matriu[2][i] | mascara; //posem a 1 blau
}
color[0] = matriu[0][i]; //vermell
color[1] = matriu[1][i]; //verd
color[2] = matriu[2][i]; //blau
pintar(i, j, color);
mirar = 0;
}
}else {
if (Polsad == 0) { // Si no s'ha premut cap polsador (o dos a la vegada)
mirar = 1;
}
}
if (intents == 40){
Apaga();
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('G'); // Lletra
EnviaL('A'); // Lletra
EnviaL('M'); // Lletra
EnviaL('E'); // Lletra
Cursor(2, 1); // Posició
EnviaL('O'); // Lletra
EnviaL('V'); // Lletra
EnviaL('E'); // Lletra
EnviaL('R'); // Lletra
while(1);
}
if (tocat == 16){
Apaga();
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('Y'); // Lletra
EnviaL('O'); // Lletra
EnviaL('U'); // Lletra
Cursor(2, 1); // Posició
EnviaL('W'); // Lletra
EnviaL('I'); // Lletra
EnviaL('N'); // Lletra
while(1);
}
cursor(i, j, color); //Cursor vermell
_delay(50000); // Retard per permetre la visualització
}
}
void __interrupt() temporit(void){
// void interrupt temporit(void) { // Línia alternativa
if (INTCONbits.T0IF) { // Comprovem que hi ha interrupció per Timer 0
TMR0 = 100; // Preselecció de Timer0
INTCONbits.T0IF = 0; // Desactiva el bit que indica interrupció pel Timer0
if (Actiu != 0) { // Si la matriu no està apagada
Actiu--; // Passem a activar un altre color
if (Actiu == 0) { // Si hem arribat a zero
Actiu = 3; // Torna a posar el 3
}
}
// D'entrada els desactivem els tres
Sorti[0] = 0x00; // Vermell
Sorti[2] = 0x00; // Verd
Sorti[4] = 0x00; // Blau
if (Actiu == 1) { // Si s vermell
Sorti[0] = 0x01; // Vermell activat
}
if (Actiu == 2) { // Si s verd
Sorti[2] = 0x01; // Verd activat
}
if (Actiu == 3) { // Si s blau
Sorti[4] = 0x01; // Blau activat
}
Sorti[1] = 0x0C; // Shutdown mode
Sorti[3] = 0x0C; // Shutdown mode
Sorti[5] = 0x0C; // Shutdown mode
Envia_max(); // Ho envia al MAX7221
}
}
// FUNCIONS
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 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 (int j = 5; j >= 0; j--){ // Hem d'enviar 6 bytes
for (int 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,5"); // S'assegura que Clock està desactivat
asm("bcf _Port,6"); // S'assegura que Latch està desactivat
asm("movf _Port,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"); // Variable per comptar els bits
asm("Bucle:");
asm("banksel _Port");
asm("bcf _Port,4"); // Desactiva Data. Si toca activar-ho, ja ho farem
asm("banksel _Sorti");
asm("rlf _Sorti,f"); // Fa sortir el bit de més a l'esquerra cap a C
asm("rlf _Sorti+1,f"); // i roda els altres a l'esquerra
asm("rlf _Sorti+2,f");
asm("rlf _Sorti+3,f");
asm("rlf _Sorti+4,f");
asm("rlf _Sorti+5,f");
asm("banksel _Port");
asm("btfsc STATUS,0"); // Mira si el bit de l'esquerra era un 1
asm("bsf _Port,4"); // Si era 1, activa Data
asm("movf _Port,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,5"); // Activa Clock, forçant a llegir el bit
asm("movf _Port,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,5"); // Desactiva Clock
asm("movf _Port,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,f"); // Decrementa Compta
asm("goto Bucle"); // Si Compta no s zero, repeteix el bucle
asm("banksel _Port");
asm("bsf _Port,6"); // Torna a activar Latch
// Els valors es copiaran a la sortida del registre
asm("movf _Port,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 (int 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
}
}
void cursor(int fila, int col, char color[3]){
//Cursor: donada una fila i una columna, ilumina el LED de la fila i columna amb un color
char sortida[6] = {color[0], fila + 1, color[1], fila + 1, color[2], fila + 1};
char A = 0b00000001 << col;
sortida[0] = color[0] | A; //si vermell
sortida[2] = color[1] & ~A; //no verd
sortida[4] = color[2] & ~A; //no blau
Envia3max(sortida);
}
void pintar(int fila, int col, char color[3]){
// Pintar: actualitza la fila segons la matriu del joc.
char sortida[6] = {color[0], fila + 1, color[1], fila + 1, color[2], fila + 1};
Envia3max(sortida);
}
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 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 ColocarVaixell(int mida, char vaixells[8]) { //Funció per colocar els vaixells aletoris
char lliure = 0;
_delay(200000); // Retard per evitar problemes al polsador
while (Polsador == 1) // Mentre el polsador no estigui premut
; // No fa res
while (Polsador == 0) // Mentre el polsador estigui premut
; // No fa res
srand(TMR0); // Agafa una llavor
while(!lliure){
char random = rand() & 0x00FF; //Agafem els 6 primers bits per les posicions i
// els altres 2 per la direccio(adalt(vertical) 00, dreta 01(horitzontal)
char columna = 0b00000001 << ((random & 0b00111000) >> 3);
char fila = random & 0b00000111;
// direcció amunt(vertical)
if((random & 0b11000000) == 0 ) {
lliure = (fila >= 8 - mida); // cap?
lliure=lliure & (!(vaixells[fila - (-1 * 0b00000001)] & (max(columna,columna <<1))))
& (!(vaixells[fila - (-1 * 0b00000001)] & columna)) & (!(vaixells[fila - (-1 * 0b00000001)]
& (min(columna,columna >> 1))));
//original, mira su fila//fiquem el max per evitar problema columna 1 i8
for(int i=0; i<mida; i++){ // està ocupat?
lliure=lliure & (!(vaixells[fila - (i * 0b00000001)] & (max(columna,columna <<1))))
& (!(vaixells[fila - (i * 0b00000001)] & columna))//original, mira fila
& (!(vaixells[fila - (i * 0b00000001)] & (min(columna,columna >> 1))));
//fiquem el max per evitar problema columna 1 i 8
}
lliure=lliure & (!(vaixells[fila - (mida * 0b00000001)] & (max(columna,columna <<1))))
& (!(vaixells[fila - (mida * 0b00000001)] & columna)) & (!(vaixells[fila - (mida * 0b00000001)]
& (min(columna,columna >> 1)))); //fiquem el max per evitar problema columna 1 i 8
if (lliure){ //si cap
for(int i=0; i<mida; i++){ //coloquem el vaixell de la mida
vaixells[fila- (i * 0b00000001)] = vaixells[fila - (i * 0b00000001)] | columna;
}
}
}
// direcció dreta(horitzontal)
if((random & 0b11000000) == 64 ) {
lliure = (columna >= (0b00000001 << (mida - 1))); // cap?
lliure=lliure & (!(vaixells[min(fila,fila-1)] & (columna << 0b00000001)))& (!(vaixells[fila]
& (columna << 0b00000001))) & (!(vaixells[max(fila,fila+1)] & (columna << 0b00000001)));
for(int i=0; i<mida; i++){ // està ocupat?
lliure=lliure & (!(vaixells[min(fila,fila-1)] & (columna >> (i * 0b00000001))))
& (!(vaixells[fila] & (columna >> (i * 0b00000001))))& (!(vaixells[max(fila,fila+1)]
& (columna >> (i * 0b00000001))));
}
lliure=lliure & (!(vaixells[min(fila,fila-1)] & (columna >> (mida * 0b00000001))))
& (!(vaixells[fila] & (columna >> (mida * 0b00000001)))) & (!(vaixells[max(fila,fila+1)]
& (columna >> (mida * 0b00000001))));
if (lliure){ //si cap
for(int i=0; i<mida; i++){ //fiquem vaixell
vaixells[fila] = vaixells[fila] | (columna >> (i * 0b00000001));
}
}
}
}
}

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