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 5

En aquest cas hi ha un jugador que intenta enfonsar els vaixells que ha situat la màquina. El programa situa quatre vaixells de manera aleatòria:

Mida Nombre de vaixells
2 caselles 2
1 casella 2

Els colors dels LED de la matriu representen:

Color Significat
Apagat Casella sobre la que no s'ha disparat
Blau Aigua
Vermell Tocat
Blanc 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 Avall
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>    
#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 (16 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 premu
char t = 1;  
char x = 7;  // Coordenada X del cursor (0 a 7)
char y = 7;    
char P=0;
char XX=0;
char YY=0;
char inici=1;  // Coordenada Y del cursor (0 a 7)
char mirar = 1;
char correcte=0;
char countd;
char countv;
char mascara;
char mascara1;
char mascara2;
char mascara3;
unsigned char Vaixells[8];
unsigned char Ocupats[8];
// Definició de les funcions que farem servir
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
void main (void) {
  OPTION_REG = 0b1000101;  // 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 = 0b01000000;  // 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 = 0b00000001;  // Desactiva les altres entrades analògiques
  PORTC = 0;  // Inicialitza a 0 el port C
  PORTB = 0;  // Inicialitza a 0 el port B
  ADCON1 = 0b00010000;  // Posa el conversor a 1/8 de la freqüència
  ADCON0 = 0b00100001;  // Activa el conversor A/D connectat a AN2
                        // amb el resultat justificat per l'esquerra
  for (int k = 0; k <43; k++){
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO == 1)
      ;
  }
  srand(ADRESH);
  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();
  while (1) {
    if (inici==1){
      countd=46;
      countv=6;
      while(correcte<4){   
        if (correcte<2){
          XX= rand()%8;
          YY= rand()%8;
          mascara=(1 << XX);
          mascara1=(1 << (XX-1));
          mascara2=(1 << (XX+1));
          if (Ocupats[YY]<<XX==0){
            Vaixells[YY]=Vaixells[YY] | mascara;
            correcte++;
            Ocupats[YY]=Ocupats[YY]| mascara;
            if(XX!=0){
              Ocupats[YY]=Ocupats[YY]| mascara1;
              if(YY!=0){
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara;
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara1;
              }
              if(YY!=7){
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara;
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara1;
              }
            }
            if(XX!=7){
              Ocupats[YY]=Ocupats[YY]| mascara2;
              if(YY!=0){
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara;
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara2;
              }
              if(YY==7){
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara;
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara2;
              }
            }
          }
        } else {
          P = rand()% 2;
          if (P==0) {
            XX= rand()%7;
            YY= rand()%8;
            mascara=(1 << XX);
            mascara1=(1 << (XX-1));
            mascara2=(1 << (XX+1));
            mascara3=(1 << (XX+2));
            if ((Ocupats[YY]<<XX==0) && (Ocupats[YY]<<(XX+1)==0)){
              correcte++;
              Vaixells[YY]=Vaixells[YY]| mascara;
              Vaixells[YY]=Vaixells[YY]| mascara2;
              Ocupats[YY]=Ocupats[YY]| mascara;
              Ocupats[YY]=Ocupats[YY]| mascara2;
              if(YY!=0){ 
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara;
                Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara2;
                if(XX!=0){
                  Ocupats[YY]=Ocupats[YY]| mascara1;
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara1;
                }
                if(XX!=6){
                  Ocupats[YY]=Ocupats[YY]| mascara3;
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara3;
                }
              }
              if(YY!=7){
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara;
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara2;
                if(XX!=0){
                  Ocupats[YY]=Ocupats[YY]| mascara1;
                  Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara1;
                }
                if(XX!=6){
                  Ocupats[YY]=Ocupats[YY]| mascara3;
                  Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara3;
                }
              }
            }
          }
          if (P==1){
            XX= rand()%8;
            YY= rand()%7;
            mascara=(1 << XX);
            mascara1=(1 << (XX-1));
            mascara2=(1 << (XX+1));
            if (Ocupats[YY]<<XX==0 && Ocupats[(YY+1)]<<XX==0){
              correcte++;
              Vaixells[YY]=Vaixells[YY]| mascara;
              Vaixells[(YY+1)]=Vaixells[(YY+1)]| mascara;
              Ocupats[YY]=Ocupats[YY]| mascara;
              Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara;
              if(XX!=0){
                Ocupats[YY]=Ocupats[YY]| mascara1;
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara1;
                if(YY!=0){
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara;
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara1;                                    
                }
                if(YY!=6){
                  Ocupats[(YY+2)]=Ocupats[(YY+2)]| mascara;
                  Ocupats[(YY+2)]=Ocupats[(YY+2)]| mascara1;   
                }
              }
              if(XX!=7){                           
                Ocupats[YY]=Ocupats[YY]| mascara2;
                Ocupats[(YY+1)]=Ocupats[(YY+1)]| mascara2;
                if(YY!=0){
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara;
                  Ocupats[(YY-1)]=Ocupats[(YY-1)]| mascara2;                                    
                }
                if(YY!=6){
                  Ocupats[(YY+2)]=Ocupats[(YY+2)]| mascara;
                  Ocupats[(YY+2)]=Ocupats[(YY+2)]| mascara2;   
                }
              }
            }
          }
        }
      }
      for (int k = 0; k < 8; k++){
        Ocupats[k] = 0;  // Comencem amb tots els LED apagats
      }
      inici=0;
    }
    ADCON0 = 0b00001001;
    correcte=0;
    // 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 4
        y = (y + 1) % 8;  // Incrementa y però la manté entre 0 i 7
        mirar = 0;
      }
      if (Polsad == 4) {  // Si s'ha premut el polsador 5
        x = (x - 1) % 8;  // Incrementa x però la manté entre 0 i 7
        mirar = 0;
      }
      if (Polsad == 5) {  // Si s'ha premut el polsador 3    
        Ocupats[y] = Ocupats[y] | 1 << x;
        mirar = 0;
        countd--;
      }
    } else {
      if (Polsad == 0) {  // Si no s'ha premut cap polsador (o dos a la vegada)
        mirar = 1;
      }
    }
    mascara=1 << x;
    // Anem a mostrar la figura actual a la matriu de LED
    for (int k = 0; k < 8; k++){
      Sortida[0] = Ocupats[k] & Vaixells[k];  // Vermells
      Sortida[2] = 0;  // Verds
      Sortida[4] = Ocupats[k] &~ Vaixells[k];  // Blaus
      // El cursor es mostra groc, independentment del punt
      if (y == k){                     // Si estem a la filera del cursor
        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);
    }
    if (countv==0 || countd==0){
      inici=1;
      for (int k = 0; k < 8; k++){
        Ocupats[k] = 0;
        Vaixells[k] = 0;
      }
      x=7;
      y=7;
    }
  }
}
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
  }
}
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&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 (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;
}

 

 

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