Tetris en Un Microcontrolador PIC

Tetris en un microcontrolador PIC El PIC Tetris juego (PICtris) generado a partir de una pregunta reciente RetroBrad en

Views 165 Downloads 5 File size 386KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Tetris en un microcontrolador PIC El PIC Tetris juego (PICtris) generado a partir de una pregunta reciente RetroBrad en el foro. Quería saber cómo manipular los LEDs y dibujar gráficos en 2D. Yo soy más de un tipo de hombre práctico y en el pasado, los gráficos no son un motivo de preocupación. Yo estaba intrigado a adentrarse en el mundo de 2D a averiguar cómo funcionan las cosas motiva. Los LEDs 64 y cuatro botones están controlados por un único PIC (18LF4520) y dos baterías AA. El código fuente opera de manera muy eficiente, y el programa es extremadamente sensible. Yo estaba preocupado por este último, ya que estaba decidido a utilizar algoritmos gráficos basados en rotaciones con respecto a las constantes predefinidas. Desde aquí me vendría bien un enfoque similar para crear otros juegos interactivos! Como siempre, las nuevas características son una necesidad! Dado que el vídeo de arriba, he añadido lo siguiente: 

Una pantalla de presentación que muestra "TETRIS" cuando se inicia el juego.



Las puntuaciones altas - sus esfuerzos se graban en la EEPROM.



Alta potencia controlador darlington para iluminar la pantalla. Todas las características anteriores se incorporan en el código fuente (que se encuentra a continuación)

Creación de gráficos 2D En el juego de Tetris, los gráficos son tratados como objetos de píxel 8x16. Para aliviar la sobrecarga de diseño gráfico, hice una hoja de cálculo de Excel que hace todo el trabajo duro por usted. Hay un campo de 8x16 donde usted puede colocar una "x" para cada bloque del objeto. Cualquier bloque con una "x" se dará formato a parecer que lo hace a continuación (me pareció que el enfoque más fácil de interpretar en comparación con dispersión de x). La hoja de cálculo se calcula y muestra el código necesario para el pez espada gráfico! Simple. Aquí hay una captura de pantalla:

Crear y mostrar texto

La hoja de cálculo se puede utilizar para crear cualquier objeto, incluyendo texto. Recientemente he querido añadir una pequeña característica - un toque de pantalla. Utilizando el diseñador gráfico hecho que sea extremadamente fácil de hacer. Puse una "x" en todos los puntos que componen la palabra TETRIS en la pantalla de 8x16. Tenía que ser un poco creativo y dividir la palabra en dos columnas, como se muestra a la derecha. Si a usted le gusta ver cómo he utilizado el objeto como un texto - navegar por el código fuente (que se enumeran más abajo), habrá una rutina que se llama "SplashScreen".

Gráficos en un PIC Existen diversas alternativas para tomar cuando se trabaja con gráficos en 2D. He explorado las matemáticas detrás de dos enfoques: trigonometría (rotando coordenadas cartesianas ) y transformación 2D matriz afín .Ambos suenan como que necesita un título universitario para entender, a pesar de que son muy sencillos en su aplicación. I utilizado originalmente trigonometría para girar los objetos, aunque la transformación de matriz afín era mucho más simple y más importante, más rápido .

Transformation Matrix Affine Rotación de un objeto 2D + / -90 grados se puede hacer fácilmente de este modo: otación Gráfico

definir el origen objeto PX = originx PY = originY / / definir object width Q = 0 / / claro la matriz de destino Para X1 = 0 a 7 pTarget ( X1 ) = 0 Siguiente / / analizar cada

¿Qué está pasando? Pfuente La matriz contiene información gráfica para el objeto. Cada byte representa una columna de píxeles, que se puede denominar en X, Y formato de este modo: pObject ( X ) . Bits ( Y )

pObject es de tipo Word . Esto significa que cada índice tiene 16 bits (dos bytes). Esto permite que dos pantallas 8x8 para ser unido y forman una sola pantalla 8x16 . Considere la posibilidad de cualquier objeto en la pantalla: Teniendo en cuenta que la esquina superior izquierda es 0,0 píxel : Sólo hay cuatro pixels que están habilitados, que son:          

X = 3, Y = 2



X = 4, Y = 2



X = 5, Y = 2



X = 4, Y = 3 La información anterior se puede colocar en pObject muy fácilmente:



pObject (3). Bits (2)



pObject (4). Bits (2)



pObject (5). Bits (2)



pObject (4). bits (3) Ahora tenemos una gran variedad de información de los píxeles que se puede utilizar de todos modos queremos.

Rotación de píxeles En el juego de Tetris, que estaba originalmente rotación de objetos CCW, aunque ahora ha cambiado a CW. Como este ejemplo fue escrito antes de que el cambio, se centrará en convertir un objeto hacia la izquierda. Si desea girar un objeto hacia otro lado, a continuación, comprobar el código fuente - ambas fórmulas están incluidos. Fórmula Rotación de CCW X2 = (Y1 + PX - PY) Y2 = (PX + PY - X1 - Q)

Paso 2 Defina la longitud del objeto / anchura (Q) Estamos trabajando en un solo píxel por píxel medio ambiente. Esto significa que la longitud y la anchura (Q) de cada píxel es siempre 0. He incluido este paso para su uso con otras condiciones.

Paso 3 Definir el píxel a ser movido (X1, Y2) Al principio, me voy a girar pixel (3,2).

Paso 4 Ejecutar las matemáticas Si PX = 4 PY = 2 = 3 X1 Y1 = 2 Q = 0

Y X2 = (Y1 + PX - PY) Y2 = (PX + PY - X1 - Q)

Por lo tanto X2 = 4 Y2 = 3

Una rotación de 90 grados de pixel (3,2) aterrizaría en el pixel (4,3) .

Paso 5 Enjuague y Repita El último paso es repetir el proceso para cada píxel y cada

Código Fuente PICtris (Tetris en un microcontrolador PIC) "V1.0 "liberación del código fuente. Tetris sin campanas + silbidos. " v1.1 scorekeeping Añadido 'y Puntuaciones. El juego mostrará la puntuación más alta por última vez en el principio. " Si su puntaje es mejor que la puntuación más alta, se guardan en la EEPROM como el nuevo alto PROGRAMA

utilizado para la selección al azar gráficos Const NumberOfShapes = 7 Const RndWindow = 255 / NumberOfShapes / / terminología (podría haber añadido más ..) Const CW = 1 Const CCW = 0 / / TMR2 las variables Dim TMR2IE Como PIE1.1, TMR2IF Como PIR1.1, TMR2ON Como T2CON.2, mS como Word , CurrentX como Byte , sWDT Como Byte Const

mS_Inc

=

2

/ / TMR2 interrupción permitir bandera / / TMR2 desbordamiento / / Activa TMR2 para comenzar incrementando / / mS registro / Ver / Software Dog Timer para entrar en el modo SLEEP

Const

DebounceDelay

=

10

/ / Modo de suspensión registra Dim IDLEN Como OSCCON.7, SCS1 Como OSCCON.1, SCS0 Como OSCCON.0 / / / /

/ FORMAS! / Asegúrese de actualizar "NumberOfShapes" si se añaden más (o algunos se eliminan) / # # # /

# # # / /

# # # / /

# # / /

# # # / /

# # # / / sub línea de comando SLEEP Asm sueño End Asm End Sub interrupción TMR2_Interrupt ( 2 ) Guardar ( 0 ) Si

/ / Copia de seguridad de las variables del sistema

TMR2IF = 1 entonces / / Comprobar si la interrupción fue de TMR2 TMR2IF = 0 / / Borrar la bandera de interrupción TMR2 / / incrementa la variable de mS mS = mS + mS_Inc Si mS = 1000 Entonces mS = 0 sWDT = sWDT + 1 Si sWDT = 30 Entonces IDLEN = 1 / / Colocar el PIC en el modo SLEEP RC_IDLE en

SCS1 = 1 / / SCS0 = 0 / / TRISA = $ FF / / Hacer que todas las E / S de las entradas de alta impedancia TRISB = $ FF TRISC = $ FF TRISD = $ FF TMR2ON = 0 / / Desactivar TMR2 / / Configurar oscilador 31kHz para OSCCON = OSCCON y % 10001111 sueño EndIf EndIf / / / / / /

/ Botón Debounces / Asegura que el botón ha sido activado antes de realizar un rebote. / por alarma, el usuario tiene X mS entre pulsaciones de botón. / Evita prensas y dobles y minimizar la posibilidad de chasquido del interruptor. / La rutina de sub 'CheckButtons' controla el estado de diversas banderas aquí. / comprueba si el botón izquierdo requiere comprobar si el botón derecho requiere

comprobar si el botón de rotación requiere comprobar si el botón de abajo requiere Gestor de Eventos - Caída de objetos / / Una vez cada 800 ms, se establece un indicador para iniciar la caída siguiente objeto. / / Esta es una de las pocas características clásicas del tetris Si mS = 800 Entonces DropObject = 1 End Si

/ / / /

/ Muestra el contenido de 64 LEDs a través de la multiplexación / Asegúrese de multiplexación está habilitado. / Esto es vital para proteger a las variables compartidas como ObjectData y BackgroundData. / Cada vez que una escritura en tanto se realiza fuera de la interrupción, la multiplexación debe ser desactivada. Si UpdateScreen = 1 entonces / / desactivar TODOS eje x PORTA = PORTA O $ 0F PORTB = PORTB O $ F0 / / llenar y habilitar un eje x (la correcta para actual eje Y) Si CurrentX < 4 Entonces Porta. pedacitos ( CurrentX ) = 0 Else PORTB. pedacitos ( CurrentX ) = 0 EndIf

/ / incrementa eje x, listo para el próximo multiplex Inc ( CurrentX ) Si CurrentX = 8 Entonces CurrentX = 0 EndIf / / una bandera de propósito general para inidcate la realización de una interrupción InterruptComplete = 1 EndIf EndIf Restore Fin de interrupción / / bucle hasta que se produce una interrupción. / / Útil para los semáforos - permite que los recursos compartidos para ser utilizado con poco (no) impacto sobre el calendario Sub WaitForInterrupt ( ) InterruptComplete = 0 Repita hasta InterruptComplete = 1 End Sub / / Esta es la rutina semáforo primaria. Si el programa utiliza los recursos compartidos, esta rutina se llama. Sub PauseMultiplexing ( ) WaitForInterrupt UpdateScreen = 0 'TMR2IE = 0 End Sub / / Habilita la multiplexación para reanudar Sub ResumeMultiplexing ( ) 'TMR2IE = 1 UpdateScreen = 1 End Sub / / borra el pasado variedad de tipos de Word Sub ClearArray ( ByRef pArray ( ) Como Word ) Dim i como Byte Para

i = 0 Para Bound ( pArray ) pArray ( i ) = $ 0,000 Siguiente Final Sub / / seleccionar un objeto aleatorio basado en el número de objetos definidos Sub SelectNextObject ( ByRef pTarget ( ) Como Word ) Dim RndSelection Como Byte Dim i como Byte Dim Contador, Selección Como Byte / / crear un número aleatorio de 0 a 255 RndSelection = RandGen. Rand / / hacer una selección basada en el número aleatorio creado Contador = 0 Selección = 0

Repita contador = contador + RndWindow Selection = selección + 1 Hasta contador >

declaración más, sólo en el caso (prefiero no hacerlo, pero Combinar dos conjuntos con el modo seleccionado / / 0 - Sobrescribir / / 1 Mover un eje y objetos en pDirection / / 0 - objeto se mueven hacia abajo / / 1 - Mover objeto hacia arriba Sub MoveObjectY ( ByRef pObject ( )

como

Word ,

Mover objetos de un eje x en pDirection / / 0 - objeto decisión correcta / / 1 - objeto mover a la izquierda Sub MoveObjectX ( ByRef pObject ( ) como Word , comprobar el objeto que se pasa a ver si se ha llegado al fondo / / return true si comprobar el objeto pasado para ver si está contra la pared izquierda ya / / return true si comprobar el objeto pasado para ver si está contra la pared de la derecha ya / / return true si comparar la fuente y el objetivo pasa por una colisión / / return true si

Una forma extremadamente rápida para girar los objetos 90 / -90 grados. / / / / Notas: . / / Calcula el centro del bloque (para ser utilizado como un punto de pivote), es decir, el centro de la forma de bloqueo de llamadas que ( px, py). / / Cada ladrillo que forma la forma de bloque girará en torno a ese punto. Para cada ladrillo, se puede aplicar el siguiente cálculo. / / ¿Dónde ancho cada ladrillo y la altura es q, la ubicación actual del ladrillo (de la esquina superior izquierda) es (x1, y1) y la ubicación de ladrillo nuevo (x2, y2): / / x2 = (y1 + px - py) / / y2 = (px + py - x1 - q) / / Para girar la dirección opuesta: / / x2 = (px + py - y1 - q) / / y2 = (x1 + py - px) / / / / Sobre la base de una matriz afín 2D

comprobar si las rotaciones son objeto actual para discapacitados Si LimitedRotation = 2 Entonces para X1 = 0 a 7 pTarget ( X1 ) = Pfuente ( X1 )

Siguiente demás / / definir el origen objeto PX = OriginX PY = OriginY / / definir Q Q = 0

/ / borrar la matriz de destino Para X1 = 0 a 7 pTarget ( X1 ) = 0 Siguiente / / si el objeto está limitado por rotación, luego invierta rotaciones / / 1 y 3. Esto hará que el objeto a su vez de este modo / / CW, CCW, CW, CCW Si LimitedRotation = 1 Entonces Si CurrentRotation = 1 Entonces pDirection = CCW EndIf EndIf / / analizar cada píxel (5x5 trabajando con

GetIndexX (Int (X2))) = 1 EndIf EndIf Fin Si Siguiente Next EndIf End Sub / / Cuenta la cantidad de píxeles que la igualdad "1". Estándar operadores bit a bit no se adaptaba / / Esta rutina como píxeles podría muy bien terminar en cualquier lugar después de un

Deje caer el objeto en incrementos Y uno. Devuelve 0 si no. Función MoveObjectDown ( ByRef pObject ( ) Como Word ) Como Byte Resultado = 1 / / Semaphore, para proteger a las variables compartidas PauseMultiplexing / / comprobar si hay una colisión con la parte inferior de la pantalla si CheckForBottom ( pObject ) = 1 entonces / / ... si lo tiene - tiempo para salvarlo hay Resultado = 0 / / o el objeto en el fondo MergeObjects ( pObject, BackgroundData, 1 ) / / obtener un nuevo objeto hacia arriba y hacia funcionamiento SelectNextObject ( pObject )

/ / comprueba las nuevas líneas CheckForNewLines = 1 lo demás / / Mover el objeto hacia abajo MoveObjectY ( pObject, 0 , 1 ) / / comprobar si hay una colisión con el fondo Si CollisionDetect ( pObject, BackgroundData ) = 1 entonces / / El objeto golpeó algo en el fondo. El objeto debe ser / / movido copia de seguridad y guardar en el fondo. Resultado = 0 / / para mover el objeto hasta una MoveObjectY ( pObject, 1 , 1 ) / / mover el objeto al fondo (o más) MergeObjects ( pObject, BackgroundData, 1 ) / / Obtiene un nuevo objeto hacia arriba y corriendo SelectNextObject ( ObjectData ) / / comprueba si el objeto ha colisionado con el fondo ya. Si es así, entonces / / el juego es más. Si CollisionDetect ( pObject, BackgroundData ) = 1 Entonces Resultado = 0 EndOfGame = 1 EndIf / / que siempre es posible que las nuevas líneas se haya hecho ya CheckForNewLines = 1 EndIf / / reanudar recursos de multiplexación, compartidos se hacen con EndIf ResumeMultiplexing End Función / / Comprobar el estado de cada botón. Debido a que esta rutina se llama a menudo, las posibilidades de perder sólo pulsar un botón / / son muy poco probables. Sub CheckButtons ( ) / / comprueba si el botón izquierdo pulsado Si Izquierda = 0 Y Left_Debounce = 0 Entonces / / semáforo - variables compartidas están a punto de ser visitada PauseMultiplexing / / asegurar que el objeto no es ya contra la pared de la izquierda Si CheckForLeftWall ( ObjectData ) = 0 Entonces / / mover el objeto a un búfer temporal MergeObjects ( ObjectData, tmpObjectData, 0 ) / / Disminuir el eje x MoveObjectX ( tmpObjectData, 1 ) / / asegurar que no hay colisiones con el fondo Si CollisionDetect ( tmpObjectData, BackgroundData ) = 0 entonces / / todo ha ido bien, combinar la matriz en la memoria intermedia de trabajo MergeObjects ( tmpObjectData, ObjectData, 0 ) / / activar el temporizador antirrebote (evita que se pulse dobles etc) Left_Delay = DebounceDelay Left_Debounce = 1 / / siempre la posibilidad de que una nueva línea se hizo sólo CheckForNewLines = 1 EndIf EndIf ResumeMultiplexing EndIf / / comprueba si el botón derecho se pulsa

/ / NOTA: ESTOS COMENTARIOS son casi las mismas que el anterior, excluidos por eso si Derecha = 0 Y Right_Debounce = 0 Entonces / / semáforo - variables compartidas están a punto de acceder PauseMultiplexing / / asegurar que no se encuentra en el derecho

garantizar que no se colisiones con comprobar si se pulsa el botón Rotar Si Rotate = 0 Y Rotate_Debounce = 0 Entonces / / semáforo - variables compartidas están a punto de ser visitada PauseMultiplexing / / Método nueva rotación, nombrado en consecuencia, mas allá NewRotation ( ObjectData, tmpObjectData, CW ) ResumeMultiplexing / / asegurar que nada se ha caído debido a las rotaciones cerca de paredes Si PixelCount ( ObjectData ) = PixelCount ( tmpObjectData ) Entonces / / cheque por objeto colisión debido a la rotación Si CollisionDetect ( tmpObjectData, BackgroundData ) = 0 Entonces / / Por último, si se pone aquí, entonces, Todo fue bien. / / buffer temporal se fusionó con tampón de trabajo PauseMultiplexing MergeObjects ( tmpObjectData, ObjectData, 0 ) ResumeMultiplexing / / actualizar el ángulo actual (0 = 0, 1 = 90, 2 = 180, comprobar si se presiona hacia abajo Si Abajo = 0 Y Down_Debounce = 0 Entonces Down_Delay = DebounceDelay Down_Debounce = 1 / / mueve el objeto actual directamente a la parte inferior Repetir Hasta MoveObjectDown ( ObjectData ) = 0 EndIf End Sub / / eliminar la línea en la ubicación pY Sub RemoveLine ( ByRef pObject ( ) como Dim X, Y, LineaActual Como Byte

Word ,

ByRef

/ / cambiar cada línea

borrar la línea superior para X = 0 a 7 pObject ( X ) . Bits ( 0 ) Next End Sub

=

0

/ / quitar las TERMINADOS y devolver el número de líneas Y ) NumberOfLines EndIf píxeles = 0 Next

=

NumberOfLines

+

1

pY

Como

Byte )

End

Sub

/ / inicializar TMR2 privadas Sub Initialise_TMR2 ( ) TMR2ON = 0 / / Desactivar TMR2 TMR2IE = 0 / / Apagar TMR2 interrumpe mS = 0 / / Inicia mS PR2 = 199 / / TMR2 Período de registro PR2 T2CON = % 00100011 / / T2CON 0:1 = preescala / / 00 = preescalador es de 1:1 / / 01 = preescalador es de 1:4 / / 1x = preescalador es 1:16 / / 03:06 = Postscale / / 0000 = 1:1 postscale / / 0001 = 1:2 postscale / / 0010 = 1:3 postscale ... / / 1111 = uno y dieciséis postscale TMR2 = 0 TMR2IE = 1 TMR2ON = 1 Enable ( TMR2_Interrupt ) End Sub

/ / Reset TMR2 Valor / / Habilitar TMR2 interrumpe / / Habilitar TMR2 para incrementar

/ / Inicia el programa Sub InitialiseProgram ( ) / / hacer todas las entradas digitales Utils. SetAllDigital / / configurar E / S TRISB = $ 0F PORTB = $ 00 TRISC = $ 00 PORTC = $ 00 TRISD = $ 00 PORTD = $ 00 TRISA = $ 00 PORTA = $ 11 / / habilitar weakpullups PORTB INTCON2. 7 = 0 / / intialise

inicializar eventos DropObject = 0 EndOfGame = 0 CheckForNewLines = sWDT = 0

0

/ / inicializar

semáforo - variables compartidas están a punto de ser visitada PauseMultiplexing Para

i

=

0

a

7

semáforo - variables compartidas están a punto de acceder PauseMultiplexing / / borrar toda gráfico

tmpObjectData ) / / cambiar el resultado hacia abajo, dependiendo de índice Seleccione i Caso 2 MoveObjectY ( tmpObjectData, 0 , 5 ) Caso 3 MoveObjectY ( tmpObjectData, 0 , 10 ) End Select / / o resultado con objeto gráfico MergeObjects ( tmpObjectData, ObjectData, 1 ) Siguiente ResumeMultiplexing / / esperar a que "hacia abajo" para ser presionado / / realizar botón anti-rebote Repita DelayMS ( 10 ) Hasta Abajo = 1 / / esperar a que se presione el botón Repeat Hasta Abajo = 0 / / realizar botón

Este es el bucle principal del juego de Tetris Sub MainGameLoop ( ) / / inicializa pantalla y las variables InitialiseProgram / / activar la pantalla del temporizador de multiplexación y otras funciones UpdateScreen = 1 Initialise_TMR2 / / mostrar la pantalla del flash SplashScreen / / Mostrar puntuación más alta de la EEPROM último ReadHighScore / / reinicializar la pantalla y variables (pantalla de inicio y puntuaciones más altas puede haber alterado cosas ..) PauseMultiplexing InitialiseProgram Initialise_TMR2 ResumeMultiplexing

/ / seleccionar un objeto y colocarlo en ObjectData SelectNextObject ( ObjectData ) Repetir / / comprobar si la bandera caída de objeto se ha establecido (invocado produce por la interrupción "TimerObjectDrop") Si DropObject = 1 Entonces DropObject = 0 MoveObjectDown ( ObjectData ) EndIf / / comprobar si hay líneas completas. cualquier rutina que se mueve un objeto debe habilitar esta opción. Si CheckForNewLines = 1 Then CheckForLines ( BackgroundData ) EndIf / / botones de escaneado y acciones como necesarias CheckButtons ( ) / watch / reset software temporizador perro sWDT = 0 / / bucle infinito, o hasta que el evento EndOfGame se establece verdadero Hasta EndOfGame = 1 / / escribir la puntuación más alta en la EEPROM WriteHighScore ( ) / / mostrar el resultado! ShowScore ( NumberOfLines ) End Sub

/ / main programa de inicio / / semilla randgen módulo RandGen. Inicialice ( $ 77 ) Si bien Verdadero / / entrar en el programa principal del juego, se quedará allí hasta que se produce un evento END MainGameLoop Wend

Esquemático Algunas consideraciones con este esquema: 

He utilizado dos cátodo común 8x8 LED matriz. No he incluido ninguna disposición de las patillas para ellos en el pinout varía tanto entre los fabricantes. Usted tendrá que comprobar la hoja de datos para su matriz específica.



Las conexiones Y son el lado positivo de los LED.



Las conexiones X son los aspectos negativos de los LEDs.



Resistencias podría ser cualquier valor por debajo de 200ohms (menos hasta que tenga el brillo deseado - Solía 80ohms).



Por favor, intente una "Blinky", programa en el PIC no debe despedir a su circuito y trabajar por primera vez. Te puedo garantizar que esta disposición funciona, he utilizado la lista de conexiones desde este mismo schyematic para desarrollar mi PCB.



El símbolo de un triángulo con una línea atravesada significa Vdd (5V). Tal ULN2803 Pin 10. Otros consejos:



Para ánodo común pantallas LED de tipo, tendrá que modificar el código fuente. Usted tendrá que cambiar el ULN2803 para un controlador de orígenes de los 8-Channel como UDN2803A .

Haga clic aquí para enarlge la imagen. Nota: He utilizado la variante de baja tensión de los anteriores Micro PIC, su número de parte es 18LF4520.

El PCB Debido a petición popular, también estoy compartiendo los archivos Gerber para el PCB se muestra a continuación:

Nombre: Osberto Rene Estrada Baches Grado: 5to bachiller industrial y perito en Electronica digital y microprocesadores

Fecha: 12/3/2013.-

Trabajo: Ante proyecto Tretis con Pic 18LF4520 y display de 8x8

Catedraticos: Juan Escobar Ruben Arbizu

Catedras: Tecnologia Y Taller Digital Tecnologia y Taller Analoga