BRICK GAME 1.0

BRICK GAME 1.0 HACIENDO USO DEL NUCLEO STM32

Abstract: The following text describes the operation of the first phase of the code for a game of brick game street and Tetris using the STM32411RE module is detailed as a processing module. For the visualization of the game, an 8X8 LED matrix connected to a MAX7219 was used as a multiplexing system under the language of C ++ programming.

Resumen: A continuacion se detalla el funcionamiento de la primera fase del codigo para 2 juegos de tetris usando el modulo STM32411RE, como modulo de procesamiento, para la visulaizaion del juego se uso una matriz LED 8X8 conectada a un MAX7219 como sistema de multiplexacion bajo el lenguaje de programacion C++.

Keywords: Sistemas Embebidos, STM32, C++, Tetris, Matriz LED, MAX7219

/media/uploads/djinn77/captura.png

SMT32411 RE https://os.mbed.com/platforms/ST-Nucleo-F411RE/

/media/uploads/djinn77/max719.png

MAX7219 y matrix LED

https://www.sparkfun.com/datasheets/Components/General/COM-09622-MAX7219-MAX7221.pdf

Descripcion del protocolo SPI

El Protocolo SPI (Serial Peripherical Interface) o en español Interfaz Periferica Serial es un protocolo síncrono que trabaja de modo full dúplex para recibir y transmitir información, permitiendo que los dos dispositivos pueden comunicarse entre sí al mismo tiempo utilizando canales diferentes o líneas diferentes en el mismo cable. Al ser un protocolo síncrono el sistema cuenta con una línea adicional a la de datos encargada de llevar el proceso de sincronismo.

Dentro de este protocolo se define un maestro que será aquel dispositivo encargado de transmitir información a sus esclavos. Los esclavos serán aquellos dispositivos que se encarguen de recibir y enviar información al maestro. Existen cuatro líneas lógicas encargadas de realizar todo el proceso:

• MOSI (Master Out Slave In):. Línea utilizada para llevar los bits que provienen del maestro hacia el esclavo. • MISO (Master In Slave Out):. Línea utilizada para llevar los bits que provienen del esclavo hacia el maestro. • CLK (Clock):. Línea proviniente del maestro encarga de enviar la señal de reloj para sincronizar los dispositivos. • SS (Slave Select):. Línea encargada de seleccionar y a su vez, habilitar un esclavo.

Descripcion de la conexion

Para poder usar el codigo primero que todo es necesario realizar las correctas conexciones entre el Nucleo STM32 y la matriz led, debemos aseguranos de conectar el PIN MOSI, el Habilitador (CS), y el clock de la siguiente manera

/media/uploads/djinn77/captura_diff4FH.png

Conexion al MAX7219

Acontinuacion se parecian con mayor detalle las conexiones

/media/uploads/djinn77/cableado2.png

/media/uploads/djinn77/cableado.png

Conexion al nucleo STM32

Descripcion del programa

El programa "BRICK GAM 1.0 "cuenta con dos partes un programa principal "tetris_pc.cpp" y un "calles.cpp", que contiene y hace uso de todas las funciones que se usaran para el funcionamiento del programa y adiconal a este se encuentra un archivo de encabezado "piezas. h" y "avenidas.h" que en el cual se encuentran todas las figuras que se utilizan en el juego, como se muestra acontinuacion:

/media/uploads/djinn77/pc.png

A fin de faciliitar el desarrollo de la tarea tambien se procedio a la configuracion y creacion de un shield para la tarjeta sacandoo provecho de su similitud en tamano y pines de un modulo arduino 1.

/media/uploads/djinn77/shield2.png

/media/uploads/djinn77/shiled1.png

Descripcion del Codigo

EL codigo cuenta con un menu que muestra el juego a elejir

0. Para el himno de la alegria.

/media/uploads/djinn77/cero.png

1. Para el cruza calles.

/media/uploads/djinn77/uno.png

2. Para tetris.

/media/uploads/djinn77/dos.png

3. Para carros.

/media/uploads/djinn77/tres.png

Una vez seleccionada la opcion a conformidad haciendo uso del jostick el usuario debera apretar el boton de seleccion mientras mantiene la palanca en la opcion a su gusto inmediatamente acontinuacuon ingresara en la opcion seleccionadad:

Selector de juego

Selector de juego

int main() {
                   
   inicializar_matriz();
   pc.baud(38400);
   
   while(1){
      
      int selec_p=0;
      meas_vx = vrx.read() * 3300; // Convierte el valor de lectura de la entrada entre 0-3300 eje X
      
      if(meas_vx < 1600)
         global_disp = DOS, selec_p=2;
      else if (meas_vx < 1700)  
         global_disp = SELEC, selec_p=0;
      else
         global_disp = UNO, selec_p=1;
      
      pantalla_pr();
      
      if (selec_p==1 && sel==1)
          calle_funtion();
      else if (selec_p==2 && sel==1)    
          tetris();
      else if (selec_p==0 && sel==1)
          himno_legria();
      }
      
}



void pantalla_pr(){      
          for(int i= 1;i<=8;i++){
          sendSPI(i, global_disp[i-1]);
          }
    }

Codigo del cruza calles

El codigo del cruza calles posee 3 matrices que se transponen entre si para mostrar una imagen entonces tenemos que:

Matriz del jugador

/media/uploads/djinn77/jugador.png

Matriz de las calles

/media/uploads/djinn77/carros.png

Matrices del jugador + calles

/media/uploads/djinn77/carrosjugador.png

Matrices del jugador + calles+puntaje

/media/uploads/djinn77/puntoganado.png

main

int main() {
   pc.baud(38400);                 // Establece la velocidad de comunicacion Serial
   inicializar_matriz();           // llama a la funcion que configura el MAX
   nivel= AV_1;                    // Asigna el trasado de las calles al juego
   victorias=puntos;               // Asigna los puntos acumulados en la pantalla inicia en 0
   jugador=player;                 // Asigna la forma del jugador
   tp.attach(&printstatus_cll,0.2);    // MIRAR para que sirve
   ubicacion=1;                    // Inicializa la varibale que cuenta la posicion del jugador
   

       
   while(1){
       
   meas_vx = vrx.read() * 3300; // Convierte el valor de lectura de la entrada entre 0-3300 eje X
   meas_vy = vry.read() * 3300; // Convierte el valor de lectura de la entrada entre 0-3300 eje Y
   
//------ realiza el corriemiento del vector hacia la izq y der respectivamente.

  if (meas_vx < 1600)           // si se cumple esta condicion el jugador se desplaza a la izq
      desplazar_izq_cll(); 
  else if (meas_vx > 1700)      // si se cumple esta condicion el jugador se desplaza a la der
      desplazar_der_cll();
 
//------ mueve a el jugador hacia arriba en el mapa
    
  if(meas_vy < 1550){   
     arriba_cll();                  // hace el llamado a la funcion que mueve al jugador a la parte superior
     ubicacion++;               // cada vez que se ejecuta actualiza la posicion del jugador en el mapa
     pc.printf("\n ubicacion:\n %i",ubicacion);  // imprime la ubicacion del jugador en el puerto serial
     if(ubicacion==7)           // si la posicion del jugador es igual a 7 ejecuta la funcion puntaje_cll();
        puntaje_cll();         
     }
     
// ----- El siguiente ciclo realiza el desplazamiento de los vehiculos
  pista_cll(); 
  
  wait(velocidad); // Velocidad del juego
               
       }
}
<</


Adicional a esto cuenta con una matriz de desplazmiento a la derecha que reorganiza el vector donde esta definido el jugador cuanto esteaprieta el jostick hacia la derecha

include the mbed library with this snippet

void desplazar_der_cll(){               // Esta funcion desplaza al jugador hacia la derecha
      
      int der = jugador[7];    
      for(int i= 7; i>=0;i--){  
          jugador[i]=jugador[i-1];
          }
      jugador[0] = der;

    }

Cuenta con una matriz de desplazmiento a la izquierda que reorganiza el vector donde esta definido el jugador cuanto esteaprieta el jostick hacia la izquierda

Mover izquierda

      int izq = jugador[0];
      for(int i= 0; i<8;i++){  
          jugador[i]=jugador[i+1];
          }
      jugador[7] = izq;

Cuenta con una matriz de desplazmiento a la arriba que reorganiza el vector donde esta definido el jugador cuanto esteaprieta el jostick hacia arriba

<<code title=arriba>>

int arb = 1; for(int i= 0; i<8;i++){ jugador[i]= jugador[i] << arb; } arb++;

<</code>>

El desplzamiento de los vehiculos ocurre a medida que estos se desplazan a la derecha

vehiculos

    
void pista_cll(){                       // Esta funcion ejecuta el movimiento de los vehiculos
    
    int aux = nivel[0];
      for(int i= 0; i<8;i++){  
          nivel[i]=nivel[i+1];
          }
      nivel[7] = aux;

Las codiciones de vicotria o derrota se determinan dependiendo si el jugador no choco contra algun coche mientras cruzabas

puntaje

void puntaje_cll(){                     // Esta funcion hace el conteo de los puntos ganados
      
      victorias[conteo]=0x80;       // cada vez que se llega al otro lado de la calle suma 1 punto que se visualiza en pantalla
      for(int i= 0; i<8;i++){       // Este ciclo for regresa al jugador a la pos 1
          jugador[i]= jugador[i] >> 6;  
          }
      ubicacion=1;                  // Renicializa la pos del jugador
      conteo++;                     // Cuenta cuantas veces a llegado el jugador al otro lado  hasta un maximo de 4
      if(conteo == 6){              // cuando el conteo es igual a 6 se llama a la funcion aumentar dificultad
         aumentar_dificultad_cll();
         }

Si el jugador chae clic en la opcion 0 , el podra oir el himno de la alegria

/media/uploads/djinn77/himnoalegria.png

el codigo usar la freuencias del piezo electro para dertermina que tono debe tocar

Himno de la alegria

#include "mbed.h"

PwmOut buzzer(A1);

int periodos1[]={1516,1431,1275,1275,1431,1516,1702,1911,1911,1702,1516,1516,1702};
int periodos2[]={1516,1431,1275,1275,1431,1516,1702,1911,1911,1702,1516,1702,1911};
int periodos3[]={1702,1516,1911,1702,1516,1431,1516,1911,1702,1516,1431,1516,1702,1911,1702,1275};
double duracion1[]={2,1,1,1,1,1,1,1,1,1,1,2,2};
double duracion2[]={2,1,1,1,0.5,0.5,1,1,1,0.5,0.5,1,1,1,1,2};

int i;
int main(){
    while(1){
        buzzer=0.2;
        for (i=0; i<13; i++) {
            buzzer.period_us(periodos1[i]);
            wait(0.5*duracion1[i]);
        }
        for (i=0; i<13; i++) {
            buzzer.period_us(periodos2[i]);
            wait(0.5*duracion1[i]);
        }
        for (i=0; i<16; i++) {
            buzzer.period_us(periodos3[i]);
            wait(0.5*duracion2[i]);
        }
    }
}


Como se informo anteriormente el programa cuenta con una cabezera en la cual se encuentran configuradas cada una de las piezas que se mostraran sobre la matriz LED al ser llamadas por el programa principal de maera similar a para una figura tipo L, definida por un vector de tamaño 8, con tres posiciones principales que almacenan la forma de la pieza.

Encabezado

Encabezado piezas.h

#ifndef PIEZAS_H  
#define PIEZAS_H  
#include "mbed.h"
 
//FORMA DE LA PIEZA
 uint16_t PZA_LD[8]={0b0010000000,  
                     0b1110000000,
                     0b0000000000,
                     0,0,0,0,0};

#endif // PIEZAS_H

Nota: Cabe destacar que para el funcionamiento de la matriz led y por facilidad para el majeno de bits la figura siempre se desplazara de izquierda a derecha.

Programa Principal

Esta seccion encontraremos la descripcion del programa principal, este hace uso de un gran numero de funciones para generar la lectura de sus datos y su posterior procesamiento.

Al principio del programa encontraremos todo lo referente al llamdo de las librerias necesarias para el funcionamiento del programa adicional a ello encontraremos , el establecimiento de las conexiones seriales y la definicion de los pines para cada uno parametros del parametros del protocolo SPI.

Declaracion de Funciones

#include "mbed.h"
#include "piezas.h"
//#define DEBUG 1
 
//Establecimiento de la comunicacion
Serial pc(USBTX,USBRX);            //Establecimiento de la comunicacion serial
SPI deviceM(PB_15, PB_14, PB_13);  //Se defienen los datos que realizaran la comunicacion serial
DigitalOut ssel (PB_12);


Como lo indica su nombre la funcion principal es la mas importante del programa desde ella se iniciara la ejecucion de los demas programas, para esto hace un primer llamamiento a la fucnion de inicializar(), que al ejecutarce establecera como se comporatara el MAX7219, como el modo de trabajo y su luminosidad, posterior ha eso dentro de un while infiniro hace el llamado a la funcion de captura de datos queejecutara la captura de datos para su posterior ejecucion.

Funcion Principal

 
int main() {
    inicializar(); // Inicializa el programa para establecer los modos de trabajo liminosidad
    while(1){
            captura_datos(); // Inicia la lectura de la informacion
            enableizq=1;     // reactiva los desplazamientos
            enableder=1;     // reactiva los desplazamientos
            perder();             // detecta cuando se ha perdido el juego
            }
}


En base a lo anterior el primer llamado de la funcion principal es a esta funcion inicializar(), que establece el modo de trabajo del MAX 7219 como se detalla acontinuacion, posterior ha eso realiza un limpieza de pantalla que evita que se mantengan led encendidos luego de reinicializar el programa.

Funcion inicializar


void inicializar(){ //INICIALIZA LA MATRIZ 
    
    sendSPI(0x0c,1);    
    sendSPI(0x0b,7);
    sendSPI(0x09,0);    //SELECCIONA EL MODO DE TRABAJO DE LA MATRIZ
    sendSPI(0x0A,0x0f); //SELECCIONA LA LUMINOSIDAD DE LA MATRIZ
    int i;
    for (i=0;i<2;i++){
        sendSPI(0x0F,1);
        wait (0.5);
        sendSPI(0x0f,0);
        wait (0.5);
    }
    
    for (int j= 1; j<=8;j++){  // limpia la pantalla al encenderce o reiniarcea asi 
                               //no quedan leds encendidos cuando se ejecute el programa nuevamente
          
          sendSPI(j, 0x00);    //pone cada columna y vecto en blanco al inicializar
                            } 
    }

La funcion de lectura es la más laga de todas desde aqui se capturan los datos para ser procesado, estableciendo una comunicacion serial de 38400 bauds, enviandolos a las variables de posicion (pos), figura y rotacion.

Debe Ingresar 3 datos al abrir el send string del coolterm el primero indica la posicion , luego la figura y finalmente el giro en el siguiente formato 00 00 00 en hexadecimal a 38400 bauds, estos comandos se deben ingresar dentro de el equivalente hexadecimal de '<' y '>', es decir 3C y 3E.

/media/uploads/djinn77/comados.png

captura de datos

 
void captura_datos(){
         
         pc.baud(38400); //Inicializa la velocidad de comunicacion
         // Establece las variables que tomaran los comandos
         char inicio=0,final=0;
         figura=0;
         giro=0;
         posicion=0;
         
         debuging("\n Ingrese el inicio del comando. ");
         inicio=pc.getc(); 
         debuging("\n Ingrese la Figura. ");
         figura=pc.getc();
         debuging("\n Seleccione el giro. ");
         giro=pc.getc();
         debuging("\n Seleccione la posicion. ");
         posicion=pc.getc(); 
         debuging("\n Ingrese el final del comando. ");
         final=pc.getc();    
         
         // Detecta si se ha generado algun error al ingresar el comando
         if(inicio!= '<' || final != '>'){
             
             debuging("\n Error en el comando.");
             
             }else{
                 
                 read();
                  
                 }
                 
         
 
    }

Inicializacion del Programa.

Luego de conectar al PC el Dispositivo debemos ir al icono de escritorio y abrir el programa.

/media/uploads/djinn77/coolterm.png

Luego se debe esteblecer la velocidad de conexion del puerto. Esta debe estar en 38400 bauds y en el puerto detectado por el PC con el nucleo STM32.

luego debe hacer clic en conectar.

/media/uploads/djinn77/conectar_q7axQGC.png

Se debe ir a la siguiente opcion.

/media/uploads/djinn77/sendstring.png

Aparecera la siguiente pantalla en la cual se ingresa el comando este debe estar en el siguiente formato

comando = "3C 01 01 01 3E".

/media/uploads/djinn77/comados.png

/media/uploads/djinn77/enviocomando.png

los valores 3C y 3E, indican el inicio y finalizacion del comando, cada uno de estos caracteres es equivalente a '<' y a '>', respectivamente, solo si estos son enviados al inicio y el final del programa seran capturados y ejecutados de manera correcta de lo contraio se preguntara por ellos nuevamente hasta que se envie el comando correctamente

El valor # 2 del comando selecciona una posicion entre 00-07, en la cual se desplegara la figura inicialmente.

/media/uploads/djinn77/pos_C0G1ii1.png

El siguiente comando ingresa la figura tal que: :

00. L,

/media/uploads/djinn77/l.png

01. T,

/media/uploads/djinn77/t.png

02. Linea.

/media/uploads/djinn77/linea.png

03. Cuadrado.

/media/uploads/djinn77/cuadrado.png

04. Z.

/media/uploads/djinn77/zinv.png

Los giros van el siguiente recuadro lo explica para la letra L:

00 = 0° grados.

/media/uploads/djinn77/l.png

01 =90° grados,

/media/uploads/djinn77/ln.png

02 =180° grados,

/media/uploads/djinn77/lo.png

03 = 270°grados,

/media/uploads/djinn77/ldd.png

En su segunda parte como se puede ver en el ejemplo el procesamiento de la variables anteriores con dos ciclos swicth anidados, es realizado, el primero escoje la figura y el segundo la rotacion, una vez dentro de esto swicth se realiza el llamado a la funcion desplazamiento tomando como parametros de entrada al vector de la figura extraido del encabezado y a la posicion en el que este se mostrara en la matriz

Funcion de lectura

void read(){
         
         switch(figura){ //Este switch escoje la figura con que trabajaar y actualiza los limite laterales e inferiores por figura
             case 0: // L
             if(giro == 0)
             imprimir =  PZA_L,liminf=7, limizq=6, limder=0;
             if(giro == 1)
             imprimir =  PZA_LDN,liminf=7, limizq=5, limder=0;
             if(giro == 2)
             imprimir =  PZA_LDO,liminf=7, limizq=5, limder=-1;
             if(giro == 3)
             imprimir =  PZA_LDD,liminf=8, limizq=5, limder=0;
             break;
             case 1://T       
             if(giro == 0)
             imprimir =  PZA_T,liminf=8, limizq=5, limder=0;
             if(giro == 1)
             imprimir =  PZA_TN,liminf=7, limizq=6, limder=0;
             if(giro == 2)
             imprimir =  PZA_TO,liminf=7, limizq=5, limder=0;
             if(giro == 3)
             imprimir =  PZA_TD,liminf=7, limizq=5, limder=-1;
             break;
             case 2://I
             if(giro == 0 || giro == 2)
             imprimir =  PZA_I,liminf=7, limizq=6, limder=-1;
             if(giro == 1 || giro == 3)
             imprimir =  PZA_IR,liminf=8, limizq=5, limder=0;
             break;
             case 3://Cuadrado
             if(giro == 0 || giro == 1 || giro == 2 || giro == 3)
             imprimir =  PZA_C,liminf=8, limizq=6, limder=0;
             break;
             case 4:
             if(giro == 0 || giro == 2)
             imprimir =  PZA_Z,liminf=8, limizq=5, limder=0;
             if(giro == 1 || giro == 3)
             imprimir =  PZA_ZN,liminf=7, limizq=6, limder=0;
             break;
             default:
             imprimir = VACIO;
             break;
             }
            // pc.printf("\n limite inferior read %d\n ",liminf);
             desplazar();
     }    
  
     

Una vez capturados los datos anteriores la funcion de desplazamiento posee un vector del mismo tamaño de la pieza capturada y es inicializado en ceros cada vez que es llamado, la figura es reubicada en base a la posicion deseada mediante el otro dato capturado por la funcion aqui la variable i inicializa desde que i = posicion ingresada hasta que cubre las tres posiciones principales que sobre la figura para luego de organizada ser llevada a la matriz de captura.

Funcion de desplazamiento

void desplazar(){
      
      uint16_t desplazamiento[8]={0};      // Inicia un vector auxiliar con solo Ceros
      int j= 0;
       for(int i=posicion; i<(posicion+3);i++){  // Inicia un vector auxiliar con solo Ceros
           desplazamiento[i]=imprimir[j]; // Alamcena los nuevos datos tomados en el vector 
           j++;                    
                          }
       imprimir=desplazamiento;          //  Actualiza el puntero imprimir con la posicion seleccionada para la fig
       captura_matriz();
      }  
  
  

La matriz de captura es la encargada de memorizar y de realizar la impresion de los datos que ejecutara el programa. cuenta con 2 ciclos while que permiten que se ejecute el codigo haste que cierto parametro no se cumpla, el pimer ciclo while, realizar el corrimiento de los bits del vector capturado hasta la parte inferior de la matriz para luego ser capturados en la memoria, el segundo ciclo while imprime a cada "columna" el corrimento del vector, e l programa cuenta con un sistema que le permite identifcar la colicion con otra figura previamente enviada haciendo uso de la operacion and, mientras recorre el vector el resultado de esta siempre sera 0 hasta que finalemente vale 1 al chocar con otro objeto y luego ser nuevamente almacenado en la memoria todos los valores del la posicion del corrimiento en la memoria.

Funcion de captura de matriz

while(j<=8){ //se encarga de seleccionar que posicion del vector imprimira
         
         sendSPI(j, memoria[j-1]|(imprimir[j-1]>>i));  //Imprime el resultado de aplicar OR a la memoria y al desplamamiento de imprimir
         //wait(0.1); // Activar este wait para pruebas de desplazamiento y captura de los datos
 
     if(i==liminf || (memoria[j-1]&(imprimir[j-1]>>i+1))!=0){  //Detiene el desplazamiento cuando los bits tocan fondo, 
         enable=0;// desabilitador del ciclo while 
         
         for(int k=0; k<8;k++){                          // Almacena todos lo datos del vector en la posicion que corrimiento en la memoria
              memoria[k]= memoria[k]|(imprimir[k]>>i);
             }
    
         }
     j++;
     } 
     wait(velocidad); // espera para tomar el otro valor de lectura
     i++;
     }

Para poder desplazar la figura sobre la matriz es necesario capturar el puntero imprimir el cual almacena temporalmente la figura que se desplaza sobre el mapa, para ello se usa una interrupcion que llama a la funcion en el flanco de bajada y provoca el desplazamiento del vector y la limpieza de los otros valores desplazados

desplazamiento izquierda

void desplazar_izq(){                                       // Desplaza el vector de impresion hacia el lado izq de la pantalla
      if(posicion<limizq && corrimiento<liminf && enableizq){ // Establece los limite de movimiento del vector
          posicion++;                                         // Aumenta el valor de la posicion segun las veces se haya pulsador el boton
            for(int i=7; i >=0; i--){
                imprimir[i]=imprimir[i-1];
                if(i==0){
                    imprimir[i]=0;
                    
                    } 
                if((imprimir[i]&& memoria[i+1])!=0){          // Si esta condicion se cumple desactiva el desplzamiento izq   
                    enableizq=0;
                    }      
                            
                }
            for(int j=1;j<=8;j++){
             sendSPI(j, memoria[j-1]|(imprimir[j-1]>>corrimiento));
 
                 }   
            wait(velocidad);  
          
          }
      return;
      }
  

Similar al anterior ambos codigo desplazan la figura hacia uno de los dos lados y terminan su desplazamiento cuando alguna de las condiciones iniciales se incumplen

desplazamiento derecha

void desplazar_der(){                                           // Desplaza el vector de impresion hacia el lado derecho de la pantalla
      if(posicion>limder && corrimiento<liminf && enableder){     // Establece los limite de movimiento del vector
           posicion--;                                            // Disminuye el valor de la posicion segun las veces se haya pulsador el boton
            for(int i=0; i <8; i++){
 
                imprimir[i]=imprimir[i+1];
                if(i==7){
                    imprimir[i]=0;
                    
                    }
                if((imprimir[i]&& memoria[i-1])!=0){              // Si esta condicion se cumple desactiva el desplzamiento der  
                    enableder=0;
                    }     
                }    
            for(int j=1;j<=8;j++){
                 sendSPI(j, memoria[j-1]|(imprimir[j-1]>>corrimiento));
                 }   
            wait(velocidad); 
      }
      return;
      } 
      
  

el codigo de giro de la figura esta dividido en 2 parte la primera parte es identica a la seleccion inicial de la figura hecho por el cual no se mostrara acontinuacion, sin embargo esta nueva funcion toma utiliza una funcion de retorno para girar la figura y imprimirla en su ultima condicion conocida.

giro de la figura

uint16_t* girar(uint16_t* pieza, int posicion){          // gira la figura y la desplza a ultima posicion conocida
     uint16_t desplazamiento[8]={0};                      
     int j= 0;
     for(int i=posicion; i<(posicion+3);i++){             // Inicia un vector auxiliar con solo Ceros
     desplazamiento[i]=pieza[j];                          // Alamcena los nuevos datos tomados en el vector 
     j++;                    
     }
    
    return desplazamiento;                               // regresa el vector procesado y lo asigna al puntero imprimir
    }
    

Acontinuacion se muestra el codigo en conjunto del desplazamiento, giro e impresion de las figuras.

codigo en conjunto

oid captura_matriz(){
    
int i=0; // inicia el contador i en 0
int enable=1;
 
pc.printf("\n limite inferior captura_matriz %d\n ",liminf);
 while(enable){ //se encarga de desplazar los bits dentro del vector
    //pc.printf("\n1- conteo del corriemiento:\n %d",i);
    corrimiento=i;
    int j=1;  // inicia el contador j en 1        
    pulsador_izq.fall(&desplazar_izq);           // interupcion al activarce el boton izquierdo
    pulsador_der.fall(&desplazar_der);           // interupcion al activarce el boron  derecho
    
    //////////////////////////////////////////777
   while(p_giro == 1){                           // se activa al pulsar boton giro
           giro++;                               // actualiza el valor del giro para seleccionar la figura girada
          
           if(giro ==4){                         // Si giro == 4 reseta el giro para volver a la fig inicial
               giro=0;
               }
           switch(figura){
             case 0: // L
             if(giro == 0)
             imprimir= girar(PZA_L, posicion),liminf=7, limizq=6, limder=0;
             if(giro == 1)
             imprimir= girar(PZA_LDN, posicion),liminf=7, limizq=5, limder=0;
             if(giro == 2)
             imprimir= girar(PZA_LDO, posicion),liminf=7, limizq=5, limder=-1;
             if(giro == 3)
             imprimir=girar(PZA_LDD, posicion),liminf=8, limizq=5, limder=0;
             break;
             case 1://T       
             if(giro == 0)
             imprimir= girar(PZA_T, posicion),liminf=8, limizq=5, limder=0;
             if(giro == 1)
             imprimir= girar(PZA_TN, posicion),liminf=7, limizq=6, limder=0;
             if(giro == 2)
             imprimir= girar(PZA_TO, posicion),liminf=7, limizq=5, limder=0;
             if(giro == 3)
             imprimir= girar(PZA_TD, posicion),liminf=7, limizq=5, limder=-1;
             break;
             case 2://I
             if(giro == 0 || giro == 2)
             imprimir= girar(PZA_I, posicion),liminf=7, limizq=6, limder=-1;
             if(giro == 1 || giro == 3)
             imprimir=girar(PZA_IR, posicion),liminf=8, limizq=5, limder=0;
             break;
             case 3://Cuadrado
             if(giro == 0 || giro == 1 || giro == 2 || giro == 3)
             imprimir= girar(PZA_C, posicion),liminf=8, limizq=6, limder=0;
             break;   
             case 4: //Z
             if(giro == 0 || giro == 2)
             imprimir= girar(PZA_Z, posicion),liminf=8, limizq=5, limder=0;
             if(giro == 1 || giro == 3)
             imprimir= girar(PZA_ZN, posicion),liminf=7, limizq=6, limder=0;
             break;
 
             }
             wait(velocidad);  
             }  
             
    ///////////////////////////////////////////    
    while(j<=8){ //se encarga de seleccionar que posicion del vector imprimira
         
         sendSPI(j, memoria[j-1]|(imprimir[j-1]>>i));  //Imprime el resultado de aplicar OR a la memoria y al desplamamiento de imprimir
         //wait(0.1); // Activar este wait para pruebas de desplazamiento y captura de los datos
 
     if(i==liminf || (memoria[j-1]&(imprimir[j-1]>>i+1))!=0){  //Detiene el desplazamiento cuando los bits tocan fondo, 
         enable=0;// desabilitador del ciclo while 
         
         for(int k=0; k<8;k++){                          // Almacena todos lo datos del vector en la posicion que corrimiento en la memoria
              memoria[k]= memoria[k]|(imprimir[k]>>i);
             }
    
         }
     j++;
     } 
     wait(velocidad); // espera para tomar el otro valor de lectura
     i++;
     }
 
  }
  
  void desplazar_izq(){                                       // Desplaza el vector de impresion hacia el lado izq de la pantalla
      if(posicion<limizq && corrimiento<liminf && enableizq){ // Establece los limite de movimiento del vector
          posicion++;                                         // Aumenta el valor de la posicion segun las veces se haya pulsador el boton
            for(int i=7; i >=0; i--){
                imprimir[i]=imprimir[i-1];
                if(i==0){
                    imprimir[i]=0;
                    
                    } 
                if((imprimir[i]&& memoria[i+1])!=0){          // Si esta condicion se cumple desactiva el desplzamiento izq   
                    enableizq=0;
                    }      
                            
                }
            for(int j=1;j<=8;j++){
             sendSPI(j, memoria[j-1]|(imprimir[j-1]>>corrimiento));
 
                 }   
            wait(velocidad);  
          
          }
      return;
      }
      
  void desplazar_der(){                                           // Desplaza el vector de impresion hacia el lado derecho de la pantalla
      if(posicion>limder && corrimiento<liminf && enableder){     // Establece los limite de movimiento del vector
           posicion--;                                            // Disminuye el valor de la posicion segun las veces se haya pulsador el boton
            for(int i=0; i <8; i++){
 
                imprimir[i]=imprimir[i+1];
                if(i==7){
                    imprimir[i]=0;
                    
                    }
                if((imprimir[i]&& memoria[i-1])!=0){              // Si esta condicion se cumple desactiva el desplzamiento der  
                    enableder=0;
                    }     
                }    
            for(int j=1;j<=8;j++){
                 sendSPI(j, memoria[j-1]|(imprimir[j-1]>>corrimiento));
                 }   
            wait(velocidad); 
      }
      return;
      } 
      
  uint16_t* girar(uint16_t* pieza, int posicion){          // gira la figura y la desplza a ultima posicion conocida
     uint16_t desplazamiento[8]={0};                      
     int j= 0;
     for(int i=posicion; i<(posicion+3);i++){             // Inicia un vector auxiliar con solo Ceros
     desplazamiento[i]=pieza[j];                          // Alamcena los nuevos datos tomados en el vector 
     j++;                    
     }
    
    return desplazamiento;                               // regresa el vector procesado y lo asigna al puntero imprimir
    }
    

Para finalizar el codigo se identifica cuando la memoria ha alcanzado el limite superior denotando una derrota del juego para esto se usa el puntero borde que al tener una equivalencia superior a 128 finaliza y reinia el juego.

condiciones de derrota

void perder(){
     for(int i=0; i<8;i++){                             // detecta si alguna parte de una figura ha tocado el borde superior para reinicializar el juego
        borde= &memoria[i];
        if(*borde>=128){
          NVIC_SystemReset();
          }
        }
    }  

Codigo de carros

De manera analoga a los demas juegos desarrollados, en este caso usaremos 3matrices diferentes como se muestra en la siguiente imagen

la primera de ella hace referencia al vehiculo del jugador.

/media/uploads/djinn77/car.png

la segunda de ellas hace referencia al borde de la calle.

/media/uploads/djinn77/camino.png

la tercera de ellas hace referencia a la sumatoria de todas las matrices con sus correspondienes obstaculos.

/media/uploads/djinn77/carros_EFkzsGp.png

Este juego se ejecuta infinitamente hasta que el jugador chica contra alguno de los obstaculos, en ese caso el programa regresara al menu principal

La siguiente imagen hace referencia al codigo de los obstaculos

Obstaculos

#ifndef VEHICULOS_H  
#define VEHICULOS_H  
#include "mbed.h"

uint16_t MICARRO[8]={0b00000000,
                     0b00000000,
                     0b00000101,
                     0b00001111,
                     0b00000101,
                     0b00000000,
                     0b00000000,
                     0b00000000};
 
 uint16_t CALLE[8]={ 0b11111111,
                     0b00000000,
                     0b00000000,
                     0b00000000,
                     0b00000000,
                     0b00000000,
                     0b00000000,
                     0b11111111}; 
                     
 uint16_t CR_DER[8]={0b00000000000,
                     0b01010000000,
                     0b11110000000,
                     0b01010000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000};
 
 uint16_t CR_IZQ[8]={0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b01010000000,
                     0b11110000000,
                     0b01010000000,
                     0b00000000000}; 
                     
 uint16_t CJ_IZQ[8]={0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b11110000000,
                     0b11110000000,
                     0b11110000000,
                     0b00000000000};
 
 uint16_t CJ_DER[8]={0b00000000000,
                     0b11110000000,
                     0b11110000000,
                     0b11110000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000,
                     0b00000000000}; 
                     
 uint16_t EQUIS[8]= {0b11111111,
                     0b11111111,
                     0b11111111,
                     0b11111111,
                     0b11111111,
                     0b11111111,
                     0b11111111,
                     0b11111111};                                                                                
                                                            
#endif //  VEHICULOS_H

la siguiente imagen hace refencia al codigo general,

En esta seccion se encuentra el programa principal una el vehiculo choca contra un obstaculo el sistema se reinicia para esto se utiliza un operador binario & (AND) que identifica el coque cuando su resultado es dieferente de 0

codigo principal del sistema

#include "mbed.h"
#include "vehiculos.h"

// Definicion de parametros de comunicacion

Serial pc(USBTX,USBRX);
SPI deviceM(PB_5, PB_4, PB_3);  //D4(gris), Ninguno, D3(azul)
DigitalOut ssel (PA_4);         //A2(morado)
Ticker tp;
InterruptIn pulsador_abj(D8);               // Lee el boton del jostick

int printjugador =1;

// Definiendo Botones

AnalogIn vry(A3);
AnalogIn vrx(A4);
DigitalIn sw(A5);

// Definicion de Funciones

void sendSPI();
void inicializar_matriz();
void desplazar_izq();
void desplazar_der();
void selec_nivel();
void desplazar();
void selec();
void juego();
void printstatus();


// Definicion de Variables

uint16_t* nivel;
uint16_t* fail;
uint16_t* jugador;
uint16_t* camino;
uint8_t  enable_abj=1;
uint8_t  enable_der=1;
uint8_t  enable_izq=1;
uint8_t  figura;
uint8_t  pos;
uint8_t  giro;
uint8_t  posicion_fig=3;
float velocidad = 0.4;


void sendSPI(uint8_t d1, uint8_t d2)
{
    deviceM.unlock();
    ssel=0;
    deviceM.write(d1); 
    deviceM.write(d2);  
    ssel=1;
    deviceM.lock();
};


void inicializar_matriz(){
    sendSPI(0x0c,1);    
    sendSPI(0x0b,7);
    sendSPI(0x09,0);    //SELECCIONA LA LUMINOSIDAD DE LA MATRIZ
    sendSPI(0x0A,0x00); //SELECCIONA LA LUMINOSIDAD DE LA MATRIZ
    
    int i;
    for (i=0;i<2;i++){
        sendSPI(0x0F,1);
        wait (0.5);
        sendSPI(0x0F,0);
        wait (0.5);
    }
  
  }

int main() {
    
    pc.baud(38400);
    inicializar_matriz();
    
    while(1){

        selec();

        }

    }
    

 
 void selec(){
   
   figura=rand()%4;
   
   switch(figura){ //Este switch escoje la figura con que trabajaar
             case 0: // carro derecha
             nivel = CR_DER;
             break;
             case 1: // carro izquierda       
             nivel = CR_IZQ;
             break;
             case 2: // caja derecha
             nivel = CJ_DER;
             break;
             case 3: // caja izquierda
             nivel = CJ_IZQ;
             break;
             }
       
       juego();
       
   }  
 
 void  aum_velocidad_tx(){
     velocidad=0.2;
     }  
 
 void juego(){
 
   jugador=MICARRO;
   camino= CALLE;
   fail=EQUIS;
   //tp.attach(&printstatus,0.2);
   enable_abj=1;
   enable_der=1;
   enable_izq=1;
   // Declaracion de Variables de lectura del jostick
   float meas_vx;
   int i=0;
 
while(enable_abj){

    int j=1;  // inicia el contador j en 1 
     
    while(j<=8){ //se encarga de seleccionar que posicion del vector imprimira
         
         sendSPI(j, jugador[j-1]|(nivel[j-1]>>i)|camino[j-1]);  //Imprime el resultado de aplicar OR a la memoria y al desplamamiento de imprimir
         //wait(0.1); // Activar este wait para pruebas de desplazamiento y captura de los datos
 
     if(i==13){  //Detiene el desplazamiento cuando los bits tocan fondo, 
         enable_abj=0;// desabilitador del ciclo while 
         }  
     if((jugador[j-1]&(nivel[j-1]>>i))!=0){
         
         NVIC_SystemReset();
         
         }  
     j++;
     } 
     wait(velocidad); // espera para tomar el otro valor de lectura
     // ----------------------Lectura del jostick-----------------------------
     
     // Lectura de parametros del jostick
     meas_vx = vrx.read() * 3300; // Convierte el valor de lectura de la entrada entre 0-3300 eje X

    if (meas_vx < 1600 && enable_izq)
           desplazar_izq(); 
    else if (meas_vx > 1700 && enable_der)
           desplazar_der();
     i++;
     pulsador_abj.fall(&aum_velocidad_tx);
     }
}
     

La siguiente imagen hace referecia al codigo de desplzamiento del vehiculo.

para esta parte del codigo el juego reorganiza las posiciones del vector vehiculos, de esta manera al mover los campos de este vector se aprecia el desplazamiento del mismo desde una borde hacia el otro al mover el jostick

codigo del desplazamieno de los vehiculos

     
void desplazar_izq(){
      
      enable_der=1;
      posicion_fig--;
      
      
      if(posicion_fig==2)
         enable_izq=0;
      
      
      int izq = jugador[0];
      for(int i= 0; i<8;i++){  
          jugador[i]=jugador[i+1];
          }
      jugador[7] = izq; 
    
}

void desplazar_der(){
      
      enable_izq=1;
      posicion_fig++;
      
      if(posicion_fig==5)
         enable_der=0;
          
      int der = jugador[7];
      for(int i= 7; i>=0;i--){  
          jugador[i]=jugador[i-1];
          }
      jugador[0] = der;
      
    }


Para mas informacion puede visitar los siguientes enlaces:

1. https://drive.google.com/open?id=18LxjhfQ7sTEd2r316q1CN2qZuNM1WJ5o

2. https://drive.google.com/open?id=1Z5J7cLjWl7QM84lvCdH_pyFUXef9isOn

3. https://drive.google.com/open?id=1fTFKVzpz2CauPSMowCayQmsoqZJYUY8f

4. https://drive.google.com/open?id=1_HB4bgzSwmUMdbu0HE6zHlmdiYrzXcwq

5. PDF DEL SHIELD https://drive.google.com/file/d/1yoUoAPmoeSXeexuKacp5lrrLmwdC4Yfl/view?usp=sharing

6. ARCHIVOS GERBER https://drive.google.com/file/d/1zmv2abw0yEvXhhpZA_-kXWQnUzxYC_f3/view?usp=sharing

Nota: cada vez que se requiera enviar una figura debe enviarce un nuevo comando desde el coolterm


Please log in to post comments.