Els quatre polsadors de l'esquerra de la part inferior serveixen per moure el cursor: esquerra, amunt, avall i dreta. L'altre polsador de la part inferior serveix per acceptar la posició. El polsador de dalt permet reiniciar el joc.
Aquest grup va descomposar el programa en diversos fitxers que es presenten a continuació:
Fitxer main_Project.c
#include "Config.h" #include "Brunzidor.h" #include "LEDs_0-3.h" #include "Matriu_LED.h" #include "Pantalla_LCD.h" #include "Players.h" #define RA3 RA3 // Li assigna un nom a l'adreça del polsador
const char guanya[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
int guanyador(void); void joc(void);
void main(void) {
config();
novapartida:
inici();
while(1){
for(char i = 0; i < 9; i++){
taulell[i]=0; // per buidar el taulell
c1[i]=0; // per apagar les caselles enceses
c2[i]=0; // si no els valors de c1 i c2 es guarden
// fins la propera partida
}
joc();
Apaga();
reiniciar(); // missatge (Apagar: mantenir RA3, tens 2 segons)
if (RA3 == 0) goto apagar; // Si el polsador està premut (1 és no premut, 0 és premut)
}
// fi del joc
while(1){ // aquest while serveix per tornar a començar el joc
// un cop finalitzar i no haver de tornar a compilar
apagar:
Esborra(); // esborra la LCD
Apaga(); // apaga la matriu LED (la funció ve feta de la documentació)
PORTC = 0; // apaga els 4 LED
__delay_ms(1000); // aquest delay és per no sortir de cop del bucle
// un cop s'ha entrat per haver mantingut
// massa estona premut RA3 (et dona 1 seg. per veure
// que ho has apagat tot)
if (RA3 == 0) goto novapartida; // Si el polsador està premut (1 és no premut, 0 és premut)
} // si surts del primer while i prou el main s'executa
// en bucle (sí, en serio), i llavors tornes a començar
// sense voler-ho
// el segon while serveix per poder aturar la partida i poder-la
// reiniciar quan es vulgui sense forçar-te a tornar a començar
}
void joc(void){
char i = 0;
char jugador = 0;
char mou1r = 0;
decisio1(); // ha de dir que 1==IA 2==jugador 2
do{
Polsad = Polsador(); // Llegim els polsadors
if (Polsad == 1) jugador= 1;
if (Polsad == 2) jugador= 2;
} while(Polsad==0 || Polsad==3 || Polsad==4 || Polsad==5);
// aquí esculls si vols jugar amb el J2 o la IA
__delay_ms(250); // per a que no se solapi la primera desicio amb la
// del següent if si vols jugar contra la IA
if (jugador == 1){
decisio2(); // si vols jugar primer mou1r==0 sino, mou1r==1
do{
Polsad = Polsador();
if (Polsad == 1) mou1r= 0;
if (Polsad == 2) mou1r= 1;
} while(Polsad==0 || Polsad==3 || Polsad==4 || Polsad==5);
} // si has escollit la IA esculls si vols jugar primer o segon
X=0; // S'inicialitza a la casella 0
do{
if ((i+mou1r) % 2 == 0){ // torns de joc (comença jugador 1) entre 2
// perquè som 2 jugadors i sempre li tocarà i parelles
usuari(-1);
}
else{
if (jugador == 2) usuari(1);
else IA();
}
i++; // per incrementar el valor de la i per no tenir bucle infinit
} while(i < 9 && guanyador() == 0);
fguard(); // per il·luminar l'última posició abans de
// finalitzar la partida
// recorda: les funcions de la LCD dels guanyadors no
// tenen retards per poder visualitzar el misatge.
// la música actua de retard, si fas proves i desactives
// la música, no veuràs els missatges.
if (guanyador()==-1){
guanyadorL('1'); // guanyador jugador 1 a la lcd
victoria();
}
else if (guanyador()==1){
guanyadorL('2'); // guanyador jugador 2 o IA en funció de qui jugui
if (jugador==2) victoria(); // si ha guanyat un altre usuari
if (jugador==1) derrota(); // si ha guanyat la IA
} else{
empat(); // empat, intentar-ho de nou, lcd
}
}
int guanyador(void) { // el taulell té 9 posicions
// determina si un jugador ha guanyat, i sino retorna 0
char i; // per cada subllista (de 3 elements) de la llista de 8 elements
for(i = 0; i < 8; i++) { // ho mira a cada moviment
// es mira i es troba un tres en linia
if(taulell[guanya[i][0]]==taulell[guanya[i][1]]&&taulell[guanya[i][0]]==taulell[guanya[i][2]])
return taulell[guanya[i][2]]; // retorna el valor corresponent al valor
// del guanyador -1 si és X o 1
// si es O (els strings no s'usen però
// és per diferenciar els jugadors)
}
return 0; // el joc segueix si no passa res
}
Fitxer Config.h
// Configuració general del programa #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 <stdlib.h> #include <stdio.h> #include <xc.h> // Carrega el fitxer de funcions necessari per al compilador XC8 #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz
char Sortida[6]; // Valors a enviar al MAX7221 (48 bits) char Actiu; // Variable que diu quin color està actiu // Actiu = 0 Apagat // Actiu = 1 Vermell // Actiu = 2 Verd // Actiu = 3 Blau // Definició de les funcions que farem servir char Polsador(void); // Funció de lectura dels polsadors char Polsad; // Polsador que s'ha premut
// Definim les funcions generals que farem servir void config(void); void Esborra(void); // Esborra la pantalla i posa el cursor a l'inici void Cursor(char Filera, char Columna); void EnviaL(char Caracter); void DefCarac(char Numero, char Fileres[8]); // Crea un caràcter definit per l'usuari void interrupt temporit(void); void Apaga(void); void Ini3max(void); void Envia3max(char Valor[6]); void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); // Funció per a les notes del brunzidor
// Matriu LED
void interrupt temporit(void) {
INTCONbits.GIE = 0; // Desactiva les interrupcions momentàniament
if (INTCONbits.T0IF) { // Comprovem que hi ha interrupció per Timer 0
TMR0 = 139; // 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
Sortida[0] = 0x00; // Vermell
Sortida[2] = 0x00; // Verd
Sortida[4] = 0x00; // Blau
if (Actiu == 1) { // Si és vermell
Sortida[0] = 0x01; // Vermell activat
}
if (Actiu == 2) { // Si és verd
Sortida[2] = 0x01; // Verd activat
}
if (Actiu == 3) { // Si és blau
Sortida[4] = 0x01; // Blau activat
}
Sortida[1] = 0x0C; // Shutdown mode
Sortida[3] = 0x0C; // Shutdown mode
Sortida[5] = 0x0C; // Shutdown mode
Envia3max(Sortida); // Ho envia al MAX7221
}
INTCONbits.GIE = 1; // Reactiva les interrupcions a l'acabar
}
// Funcions generals del programa
// Config del les potes del microcontrolador
void config(void){
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
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
OPTION_REG = 0b10000101; // Configuració de Timer0
TRISA = 0xFF; // Tot el port A és d'entrada
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
PORTC = 0; // Inicialitza a 0 el port C
PORTB = 0; // Inicialitza a 0 el port B
Ini3max(); // Inicialitza els tres MAX7221
Apaga(); // Apaga tots els LED
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;
}
// Pantalla LCD
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 HA DE SER 1 MIL·LISEGON, ES
// L'INTERVAL DE TEMPS ESTRICTE
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(0x01); // 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 Envia3max(char Valor[]) { // Envia un joc de valors als tres MAX7221
INTCONbits.GIE = 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.GIE = 1; // Reactiva les interrupcions a l'acabar
}
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 = 0; 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
}
}
// Polsadors 1-5
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;
}
// Brunzidor
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
}
Fitxer Brunzidor.h
void victoria(void){
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
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
// Registre que ens dona l'amplada de tON
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
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
TocaNota(238, 119, 2); // do3
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(200); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
__delay_ms(50); // retard entre nota i nota
TocaNota(238, 119, 2); // do3
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(50); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
TocaNota(141, 71, 0); // la
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(400); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
}
void derrota(void){
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
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
// Registre que ens dona l'amplada de tON
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
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
TocaNota(158, 79, 2);//sol
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(350); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
__delay_ms(50);
TocaNota(168, 84, 2); // fa# sol b
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(350); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
__delay_ms(50);
TocaNota(178, 89, 2); // fa3
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(350); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
__delay_ms(50);
TocaNota(189, 95, 0); // mi3
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(350); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
__delay_ms(50);
TocaNota(200, 100, 2); // re# mi b
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(750); // Retard de 0,2 s (retard per allargar cada nota)
TRISC = 0b00100000; // Posem RC5 (sortida del PWM) com a entrada
}
Fitxer LEDs_0-3.h
// Funcions específiques dels LED RC
void Cotxe_fantastic(void){
RC0 = 1; // Activa el bit 0 del port C i, per tant, encén el LED
_delay(100000); // Retard de 100 000 cicles
RC0 = 0; // Desactiva el bit 0 del port C i, per tant, apaga el LED
RC1 = 1;
_delay(100000);
RC1 = 0;
RC2 = 1;
_delay(100000);
RC2 = 0;
RC3 = 1;
_delay(100000);
RC3 = 0;
RC2 = 1;
_delay(100000);
RC2 = 0;
RC1 = 1;
_delay(100000);
RC1 = 0;
}
void LEDJugador1(void){
RC0 = 1; // Activa el bit 0 del port C i, per tant, encén el LED
_delay(100000); // Retard de 100 000 cicles
RC1 = 0; // Desactiva el bit 0 del port C i, per tant, apaga el LED
RC2 = 0;
RC3 = 0;
}
void LEDJugador2(void){
RC1 = 1; // Activa el bit 0 del port C i, per tant, encén el LED
_delay(100000); // Retard de 100 000 cicles
RC0 = 0; // Desactiva el bit 0 del port C i, per tant, apaga el LED
RC2 = 0;
RC3 = 0;
}
Fitxer Matriu_LED.h
signed char taulell[9]; // les 9 posicions del taulell. Les variables signed char són
// com char però amb signe. ocupen el mateix número de bytes(1)
// per default els valors dels 9 índex de la variable taulell
// són 0. No convé assignar com a 0 un index que es pretengui
// modificar.
char c1[9]; // va de 0 a 8 són les 9 caselles
char c2[9];
char X;
// els const char no es modifiquen, només es criden les
// variables, són el que són. Els char es poden modificar
const char cj[3]={ 0b11000000, 0b00011000, 0b00000011 }; // les caselles per les que es mou cada
// jugador vénen omplertes per aquests bits
// Variables que defineixen el taulell i cada casella.
// li repeteixo la fila 1 i faig la llargada del taulell
// amb 9 files i no 8, per questions de codi, si no
// queda malament perquè es menja la primera línia
const char barres[9] = {0b00100100, 0b00100100, 0b00100100, 0b11111111, 0b00100100,
0b00100100, 0b11111111, 0b00100100, 0b00100100};
// definim les caselles (les caselles són le mateixes
// per a cada jugador, però li canviem el color quan ho enviem)
const char casella1[9]={0b11000000, 0b11000000, 0b11000000};
const char casella2[9]={0b00011000, 0b00011000, 0b00011000};
const char casella3[9]={0b00000011, 0b00000011, 0b00000011};
const char casella4[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11000000, 0b11000000};
const char casella5[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00011000, 0b00011000};
const char casella6[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000011, 0b00000011};
const char casella7[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b11000000, 0b11000000};
const char casella8[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00011000, 0b00011000};
const char casella9[9]={0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000011, 0b00000011};
// Funcions específiques per la il·luminació
// dels LED de la matriu
// Funció per a les files
void fila(char f){
Sortida[1] = f; // Filera f que serà 1 o 2 o 3....
Sortida[3] = f;
Sortida[5] = f;
}
// Funcions per la il·luminació de les fitxes en moviment
// i de les guardades a cada casella
void mouJ(char J){ // J=4 per al primer jugador i J=2 per al segon
// per mostrar a la matriu les caselles en moviment
// del jugador 1
char i;
if(X==0 || X==1 || X==2){ //primeres 3 caselles (tota la primera fila de caselles)
for (i=0; i<3; i ++){//només 2 files
fila(i);
if (X==0) Sortida[J]=cj[0]; //pren els bits de cj[0] i l'il·lumina
// amb el color corresponent
if (X==1) Sortida[J]=cj[1];
if (X==2) Sortida[J]=cj[2];
Envia3max(Sortida); // Ho envia al MAX7221
}
}
if(X==3 || X==4 || X==5){ // segones 3 caselles
for (i=4; i<6; i ++){ // només 2 files
fila(i);
if (X==3) Sortida[J]=cj[0];
if (X==4) Sortida[J]=cj[1];
if (X==5) Sortida[J]=cj[2];
Envia3max(Sortida); // Ho envia al MAX7221
}
}
if(X==6 || X==7 || X==8){ // terceres tres caselles
for (i=7; i<9; i ++){ // només 2 files
fila(i);
if (X==6) Sortida[J]=cj[0];
if (X==7) Sortida[J]=cj[1];
if (X==8) Sortida[J]=cj[2];
Envia3max(Sortida); // Ho envia al MAX7221
}
}
}
void fguard(void){
for (char i=0; i<=8; i++){
fila(i); // llegeix memòria de programa, ho posa als LED i incrementa amb el i++
Sortida[0]=barres[i]; // taulell vermell
if (taulell[0]==-1) c1[0]=casella1[i];
if (taulell[1]==-1) c1[1]=casella2[i];
if (taulell[2]==-1) c1[2]=casella3[i];
if (taulell[3]==-1) c1[3]=casella4[i];
if (taulell[4]==-1) c1[4]=casella5[i];
if (taulell[5]==-1) c1[5]=casella6[i];
if (taulell[6]==-1) c1[6]=casella7[i];
if (taulell[7]==-1) c1[7]=casella8[i];
if (taulell[8]==-1) c1[8]=casella9[i];
Sortida[4]=c1[0]|c1[1]|c1[2]|c1[3]|c1[4]|c1[5]|c1[6]|c1[7]|c1[8]; // Jugador 1 blau
if (taulell[0]==1) c2[0]=casella1[i];
if (taulell[1]==1) c2[1]=casella2[i];
if (taulell[2]==1) c2[2]=casella3[i];
if (taulell[3]==1) c2[3]=casella4[i];
if (taulell[4]==1) c2[4]=casella5[i];
if (taulell[5]==1) c2[5]=casella6[i];
if (taulell[6]==1) c2[6]=casella7[i];
if (taulell[7]==1) c2[7]=casella8[i];
if (taulell[8]==1) c2[8]=casella9[i];
Sortida[2]=c2[0]|c2[1]|c2[2]|c2[3]|c2[4]|c2[5]|c2[6]|c2[7]|c2[8];
Sortida[4]|Sortida[0]|Sortida[2]; // envia els bits predominants (els 1)
Envia3max(Sortida); // canvies el número de la sortida per fer
// un altre color i ale.
} // quan hagi enviat les 9 files (en realitat són 8 però
// hem d'enviar 9 perquè la primera no la llegeix)
// torna a començar
}
Fitxer Pantalla_LCD.h
const char ini[24] = {'T','r','e','s',' ','e','n',' ','r','a','t','l','l','a',
'E','X','P','E','R','I','E','N','C','E'};
// no li posis el mateix nom de la funció a la variable
const char Ju[17] = {'J','u','g','a','d','o','r',' ','G','u','a','n','y','a','d','o','r'};
// trec les adresses perque si no fa coses rares
const char emp[15] = {'E','m','p','a','t','N','o','u',' ','i','n','t','e','n','t'};
const char ocup[14] = {'C','a','s','e','l','l','a','o','c','u','p','a','d','a'};
const char tor[18] = {'A','p','a','g','a','r','M','a','n','t','e','n','i','r',' ','R','A','3'};
// missatge1 ha de dir que 1==IA 2==jugador 2
const char m1[27] = {'I','A',' ',' ',' ',' ',' ',' ',' ','J','2','P','o','l','s','a','d','1',
' ',' ','P','o','l','s','a','d','2'};
// missatge2 si vols jugar primer mou1r==0 sino, mou1r==1
const char m2[30] = {'T','u',' ','1','r',' ',' ',' ',' ','I','A',' ','1','r',
'P','o','l','s','a','d','1',' ',' ','P','o','l','s','a','d','2'};
// Funcions específiques de la pantalla
void Moure_esq(void){
for(char k=1; k<=16; k++) {
EnviaL(254); // Control de la posició del cursor
EnviaL(0x18);
__delay_ms(135);
if (k==16) break;
}
}
// les dues decisions van fora del do-while, si es posa
// un Esborra() per refrescar la LCD llavors no
// no es veurà res, estarà sempre borrant-se
// i escribint-se, l'Esborra() s'ha de posar fora la
// funció, per tant la funció també, en aquest cas
void decisio1(void){
char i;
i=0;
Esborra();
Cursor(1,4);
do{
EnviaL(m1[i]); // envia totes les lletres
i++;
} while(i!=11);
i=11;
Cursor(2,0);
do{
EnviaL(m1[i]); // envia totes les lletres
i++;
} while(i!=27);
}
void decisio2(void){
char i;
i=0;
Esborra();
Cursor(1,2);
do{
EnviaL(m2[i]); // envia totes les lletres
i++;
} while(i!=14);
i=14;
Cursor(2,0);
do{
EnviaL(m2[i]); // envia totes les lletres
i++;
} while(i!=30);
}
void inici(void){
char i;
i=0;
Esborra();
Cursor(1,18);
do{
EnviaL(ini[i]); // envia totes les lletres
i++;
} while(i!=14);
Moure_esq();
i=14;
// ESTRICTAMENT necessari canviar de variable, perquè la 'i'
// es crema i no es pot usar 2 cops si son 'const char'
// diferents.
// si vols usar un sol 'const char' i fer un text separat i
// vols treballar amb aquest únic text i diferents funcions
// com en aquesta, usa una sola o dos variables char 'i'
// usa la pos. última per cridar la inicial del següent
// missatge, com en la 14 aquí, perquè no la inclou
Cursor(2, 20); // Posició
do{
EnviaL(ini[i]); // envia totes les lletres
i++;
} while(i!=24);
__delay_ms(1000);
Cotxe_fantastic();
Moure_esq();
}
void guanyadorL(char J){ // aquesta funcio serveix tant pel J1 com pel J2
// i ocupa la meitat del que teniem
char i;
Esborra();
Cursor(1,4);
i=0;
do{
EnviaL(Ju[i]); // envia totes les lletres
i++;
} while(i!=8);
EnviaL(J); // número
i=8;
Cursor(2,5);
do{
EnviaL(Ju[i]); // envia totes les lletres
i++;
} while(i!=17);
// no cal retard, la música ja crearà el retard
}
void empat(void){
char i;
Esborra();
i=0;
Cursor(1,6);
do{
EnviaL(emp[i]); // envia totes les lletres
i++;
} while(i!=5);
i=5;
Cursor(2,4);
do{
EnviaL(emp[i]); // envia totes les lletres
i++;
} while(i!=15);
__delay_ms(1000);
}
void ocupat(void){
char i;
Esborra();
Cursor(1,2);
i=0;
do{
EnviaL(ocup[i]); // envia totes les lletres
i++;
} while(i!=7);
i=7;
Cursor(2,9);
do{
EnviaL(ocup[i]); // envia totes les lletres
i++;
} while(i!=14);
__delay_ms(1000);
}
void torn(char J){ // J és l'string 1 o 2 en funció del torn del jugador
char i;
Esborra();
i=0;
Cursor(1,4);
do{
EnviaL(Ju[i]); // envia totes les lletres
i++;
} while(i!=8);
EnviaL(J);
}
void reiniciar(void){
char i;
Esborra();
i=0;
Cursor(1,6);
do{
EnviaL(tor[i]); // envia totes les lletres
i++;
} while(i!=6);
i=6;
Cursor(2,3);
do{
EnviaL(tor[i]); // envia totes les lletres
i++;
} while(i!=18);
__delay_ms(2000);
}
Fitxer Players.h
// Funcions específiques dels jugadors i de la IA
void IA(void){ // aquí donem valors aleatoris, sí, el joc no intenta guanyar,
// dir-li IA és molt generós
char i;
// no cal posar res a la pantalla ni als leds perquè
// juga molt ràpid
char random=0;
do{
srand(random); // srand inicialitza la generació de números aleatoris
i= rand() % 9; // es dona el número aleatori amb rand() entre 0 i 8
// rand() sempre repeteix la mateixa seqüencia
// de valors aleatoris
// podem inicialitzar la seqüència aleatòria amb un
// valor d'inici tipo: srand(3)
random++;
} while(taulell[i] != 0); //comprovem si els números estan ocupats
// i que ens doni un altre
taulell[i]= 1;
// no tenim manera de crear valors realment aleatoris
// sense hardware extern.
// creem una variable random que vagi sumant +1 al valor
// inicial que és 0, al menys d'aquesta manera
// cada valor pel que comença a generar valors aleatoris
// és diferent, si es cumpleix taulell[i] != 0, però seguirà
// éssent un valor pseudo-random perquè li donem nosaltres.
}
void usuari(signed char juga){
do{
if(juga==-1){
LEDJugador1();
torn(' ');
}
if(juga==1){
LEDJugador2();
torn('2');
}
do{
Polsadors();
if(juga==-1)mouJ(4);
if(juga==1)mouJ(2);
fguard();
for(char i = 0; i < 9; i++){
c1[i]=0; // per apagar les caselles enceses
c2[i]=0; // les caselles siluminen al cridar fguard, però aquest bucle
// serveix per borrar caselles que s'iluminen per error
} // això resol tots els bugs de les caselles que
// s'il·luminen que no s'hauries d'il·luminar.
} while(Polsad!=5);
Polsad = Polsador(); // Llegim els polsadors
if (Polsad == 5) { // (Acceptar) Si s'ha premut el polsador 5
if (taulell[X] != 0) ocupat();
}
} while(taulell[X] != 0);
taulell[X]= juga; // la posicio serà el valor de la X
}
void Polsadors(void){
Polsad = Polsador(); // Llegim els polsadors
if (Polsad == 4){ // (Dreta) Si s'ha premut el polsador 4
if (X==1) X=2; // si la casella 2 esta activa(corresponen a X=1), desactiva
// la casella 2 i activa la 3 (corresponen a X=2)
if (X==0) X=1; // si la casella 1 esta activa, desactiva
// la casella 1 i activa la 2
if (X==4) X=5;
if (X==3) X=4;
if (X==7) X=8;
if (X==6) X=7;
__delay_ms(50);
}
if (Polsad == 3){ // (Baixa) Si s'ha premut el polsador 3
if (X==3) X=6; // si la casella 2 esta activa, desactiva
// la casella 2 i activa la 3
if (X==0) X=3; // si la casella 1 esta activa, desactiva
// la casella 1 i activa la 2
if (X==4) X=7;
if (X==1) X=4;
if (X==5) X=8;
if (X==2) X=5;
__delay_ms(50);
}
if (Polsad == 2){ // (Puja) Si s'ha premut el polsador 2
if (X==3) X=0;
if (X==6) X=3;
if (X==4) X=1;
if (X==7) X=4;
if (X==5) X=2;
if (X==8) X=5;
__delay_ms(50);
}
if (Polsad == 1) { // (Esquerra) Si s'ha premut el polsador 1
if (X==1) X=0;
if (X==2) X=1;
if (X==4) X=3;
if (X==5) X=4;
if (X==7) X=6;
if (X==8) X=7;
__delay_ms(50); // els delays són perquè sinó les fitxes es mouen massa ràpid
}
}

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