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 dos jugadors, un situa els vaixells i l'altre els intenta enfonsar. Després s'intercanvien els papers. Cal situar deu vaixells:

Mida Nombre de vaixells
4 caselles 1
3 caselles 2
2 caselles 3
1 casella 4

Els colors dels LED de la matriu representen:

Color Significat
Apagat Casella sobre la que no s'ha disparat
Vermell Aigua
Verd 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 Esquerra
2 Amunt
3 Disparar
4 Avall
5 Dreta

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
#define flipbit(var, bit) ((var) ^= (1<<(bit)))
#define _XTAL_FREQ  4000000
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 Actiu;
char f;
char r;
char g;
char b;
char c;
char a;
char j;
char unitats;
char desenes;
char q;
char cv;
char fv;
char intentsj2;
char intentsj1;
char contador;
char tocat;
char ab;
char Polsad;
unsigned char Valor; // Variable de 8 bits sense signe (0 a 255)
char NoPremut; // Estat del polsador
char Adreta; // Sentit de gir
char M[8][8]= {{0, 0, 0, 0, 0, 0, 0, 0}, // Fila de la matriu
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}}; // Tenim una matriu de quatre fileres i vuit columnes
char llista[10][1] = {'0','1','2','3','4','5','6','7','8','9'};
// 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
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)
void EncenMatriu_vaixells(char M[8][8], char f, char c,char j);
void main(void) {
  OPTION_REG = 0b10000101; // Configuració de Timer0
                           // Com a temporitzador basat en rellotge
                           // 101 - Factor d'escala de 64
                           // I resistències de pull-up desactivades (valor per defecte)
  TRISC = 0; // Tot el port C és de sortida
  TRISB = 0; // Tot el port B és de sortida
  TRISA = 0xFF; // Tot el port A és d'entrada
  ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
  ANSELH = 0; // Desactiva les altres entrades analògiques
  PORTC = 0; // Inicialitza a 0 el port C
  PORTB = 0; // Inicialitza a 0 el port B
  Ini3max(); // Inicialitza els tres MAX7221
  Actiu = 1;
  TMR0 = 100; // Presselecció de 100, que són 156 iteracions
              // Correspon a una interrupció cada 7,5 ms
  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ó
  Esborra();
  INTCON = 0b10100000; // Activem GIE i T0IE
  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
  Apaga(); // Apaga tots els LED // Matriu 1
  f = 8;
  c = 7;
  a=1;
  contador = 20;
  ab=1;
  q=1;
  EnviaL('I');
  EnviaL('n');
  EnviaL('t');
  EnviaL('e');
  EnviaL('n');
  EnviaL('t');
  EnviaL('s');
  EnviaL(' ');
  EnviaL('J');
  EnviaL('1');              
  Cursor(2, 1);
  EnviaL(llista[0][0]);
  EnviaL(llista[0][0]);
  unitats=1;
  desenes=0;   
  intentsj2=0;
  intentsj1=0;
  while (1) {
    Polsad = Polsador();
    if ((Polsad == 5) && (c > 0)) {
      Apaga();
      c--;
    }
    if ((Polsad == 2) && (f>1)) {
      Apaga();
      f--;
    }
    if ((Polsad == 4)&&(f < 8)) {
      Apaga();
      f++;
    }
    if ((Polsad == 1)&&(c < 7)) {
      Apaga();                  
      c++;
    }
    if ((Polsad == 3)&& (contador!=0) && (M[f-1][7-c] !=1)){
      Apaga();
      M[f-1][7-c] = 1;
      contador--;
      a=1;
    }
    if (a==1){
      __delay_ms(500);
      Apaga();
      f = 8;
      c = 7;
      a = 0;
    }
    while(contador==0){          
      if (ab==1){
        r=(0<<7);
        g=(0<<7);
        for (int k = 1; k < 9; k++){
          Sortida[1] = k; // Filera 1
          Sortida[3] = k;
          Sortida[5] = k;
          Sortida[0] = r; // Vermells
          Sortida[2] = g; // Verds
          Sortida[4] = 0b11111111; // Blaus
          Envia3max(Sortida);  
        }
        __delay_ms(3000);
        Apaga();
        ab=0;
        a=1;
      }
      Polsad = Polsador();
      if ((Polsad == 5) && (c > 0)) {
        Apaga();
        c--;
      }
      if ((Polsad == 2) && (f>1)) {
        Apaga();
        f--;
      }
      if ((Polsad == 4)&&(f < 8)) {
        Apaga();
        f++;
      }
      if ((Polsad == 1)&&(c < 7)) {
        Apaga();                  
        c++;
      }
      if ((Polsad == 3)&& (M[f-1][7-c]!=2)&& (M[f-1][7-c]!=3)){
        Esborra();
        EnviaL('I');
        EnviaL('n');
        EnviaL('t');
        EnviaL('e');
        EnviaL('n');
        EnviaL('t');
        EnviaL('s');
        EnviaL(' ');
        if(q==1){
          EnviaL('J');
          EnviaL(llista[1][0]);
        }
        if(q==0){
          EnviaL('J');
          EnviaL(llista[2][0]);
        }
        Cursor(2, 1);
        Cursor(2, 1);
        if(unitats>9){
          desenes++;
          unitats=0;
        }
        EnviaL(llista[desenes][0]);
        EnviaL(llista[unitats][0]);
        unitats++;
        if (M[f-1][7-c]==1){
          M[f-1][7-c]=3;
          tocat++;
        }
        if (M[f-1][7-c] ==0){
          M[f-1][7-c]=2;                
        }
        a=1;
      }        
      if (a==1){
        __delay_ms(500);
        Apaga();
        f = 8;
        c = 7;
        a = 0;
      }
      if(tocat==20){
        __delay_ms(1000);
        Apaga();
        intentsj2=desenes*10+unitats;
        if ((intentsj2>intentsj1)&&(intentsj1!=0)){
          Esborra();
          EnviaL('G');
          EnviaL('u');
          EnviaL('a');
          EnviaL('n');
          EnviaL('y');
          EnviaL('a');
          EnviaL(' ');
          EnviaL('J');
          EnviaL('1');
          EnviaL('!');
          break;
        }
        if ((intentsj2<intentsj1)&&(intentsj1!=0)){
          Esborra();
          EnviaL('G');
          EnviaL('u');
          EnviaL('a');
          EnviaL('n');
          EnviaL('y');
          EnviaL('a');
          EnviaL(' ');
          EnviaL('J');
          EnviaL('2');
          EnviaL('!');
          break;
        }
        if (intentsj2==intentsj1){
          Esborra();
          EnviaL('E');
          EnviaL('m');
          EnviaL('p');
          EnviaL('a');
          EnviaL('t');
          EnviaL('!');
          break;
        }
        intentsj1=desenes*10+unitats;
        f = 8;
        c = 7;
        a=1;
        contador = 20;
        ab=1;
        Esborra();
        EnviaL('I');
        EnviaL('n');
        EnviaL('t');
        EnviaL('e');
        EnviaL('n');
        EnviaL('t');
        EnviaL('s');
        EnviaL(' ');
        EnviaL('J');
        EnviaL('2');
        Cursor(2, 1);
        EnviaL(llista[0][0]);
        EnviaL(llista[0][0]);   
        q=0;
        __delay_ms(50); 
        unitats=1;
        desenes=0;
        tocat=0;
        for (fv=1; fv<9 ; fv++) {
          for(cv=0; cv<8; cv++){
            M[fv][cv]=0;
          }
        }
      }
      EncenMatriu_vaixells(M,f,c,2);
      __delay_ms(50);   
    }
    EncenMatriu_vaixells(M, f,  c, 1);
    __delay_ms(50);
  }
}
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
    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
    Envia_max(); // Ho envia al MAX7221
  }
}
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 _Sortida");
  asm("rlf _Sortida,f"); // Fa sortir el bit de més a l'esquerra cap a C
  asm("rlf _Sortida+1,f"); // i roda els altres a l'esquerra
  asm("rlf _Sortida+2,f");
  asm("rlf _Sortida+3,f");
  asm("rlf _Sortida+4,f");
  asm("rlf _Sortida+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
  }
}
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 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 EncenMatriu_vaixells(char M[8][8],char f, char c,char j) {
  char fv;
  char cv;
  char rv;
  char gv;
  char bv;    
  char fila;
  char fil;
  rv=(0<<cv);
  bv=(0<<cv);
  gv=(0<<cv);
  if (j==1){
    for (fv=1; fv<9 ; fv++) {
      fila=0;
      for(cv=0; cv<8; cv++){
        if (M[fv-1][cv]==1){
          fil=1<<(7-cv);
          fila= fila | fil;
        }
      }
      rv=fila;
      bv=fila;
      gv=(0<<cv);
      if (fv==f){
        rv=rv | (1<<c);
        gv=gv | (1<<c);  
      }
      Sortida[1] = fv; // Filera 1
      Sortida[3] = fv;
      Sortida[5] = fv;
      Sortida[0] = rv; // Vermells
      Sortida[2] = gv; // Verds
      Sortida[4] = bv; // Blaus
      Envia3max(Sortida);
    }
  }
  if (j==2){
    for (fv=1; fv<9 ; fv++) {
      fila=0;
      for(cv=0; cv<8; cv++){
        if (M[fv-1][cv]==3){
          fil=1<<(7-cv);
          fila= fila | fil;
        }
      }
      rv=(0<<cv);
      bv=(0<<cv);
      gv=fila;
      fila=0;
      for(cv=0; cv<8; cv++){
        if (M[fv-1][cv]==2){
          fil=1<<(7-cv);
          fila= fila | fil;
        }
      }
      rv=rv|fila;
      bv=bv|(0<<cv);
      gv=gv|(0<<cv);
      if (fv==f){
        rv=rv | (1<<c);
        gv=gv | (1<<c);  
        bv=bv | (0<<c);
      }
      Sortida[1] = fv; // Filera 1
      Sortida[3] = fv;
      Sortida[5] = fv;
      Sortida[0] = rv; // Vermells
      Sortida[2] = gv; // Verds
      Sortida[4] = bv; // Blaus
      Envia3max(Sortida);
    }
  }
}

 

 

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