Machaca-topos casero

Contenidos

  1. Introducción
  2. Material utilizado y costes
  3. Pasos realizados
    • Planificación y diseño inicial
    • Parte hardware
    • Parte software
    • Pruebas y retoques finales
  4. Vídeo de demostración
  5. Autora

1.Introducción 

El objetivo de este proyecto era la creación de algún sistema que hiciera uso de una placa Arduino Uno. En mi caso, ese sistema ha sido un juego de machaca-topos casero.  

El juego consiste en usa serie de topos formados por un led y un botón. Si un led está iluminado, significa que ese es el topo que hay que golpear y, para golpearlo, basta con pulsar su botón. 

Estos topos irán cambiando con el tiempo o con los golpes del jugador de forma aleatoria, pero siempre habrá sólo uno activo. 

El jugador irá sumando o restando puntos (según si acierta al topo activo o no) mientras dure la partida (30 segundos). Tras lo cual, el juego se desactivará hasta que se inicie una nueva partida (pulsando el botón de inicio). 

En resumen, se trata de un juego de luces donde hay que darle a la luz encendida en cada momento para sumar la mayor cantidad de puntos posibles. Un juguete capaz de entretener a los pequeños e incluso a los no tan pequeños. 

2.Material utilizado y costes 

Para el desarrollo de este proyecto he utilizado los siguientes materiales: 

-1 placa Arduino Uno R3: es el controlador central del sistema. Se encarga de leer los botones, procesar los datos y actuar sobre los leds y la pantalla. 

-1 placa protoboard de 830 puntos: en ella se conectan todos los componentes del sistema (menos el lcd i2c). Se puede usar otra de distinto tamaño, pero si es muy pequeña podrían ser necesarias dos en lugar de una. 

-1 pantalla lcd i2c: es la encargada de mostrar los puntos conseguidos por el jugador y el tiempo de partida restante. 

-1 registro de desplazamiento IC 74HC595: permite contrarrestar el problema de pocos pines en la placa Arduino explicado posteriormente. 

-8 leds: luz del topo. Cada led corresponde a un topo, por lo que el número varía en función del número de topos del juego (en este caso, 8). 

-9 pulsadores de cuatro pines: 1 para poder iniciar el juego y 8 para los topos. 

-17 resistencias (de 1 y 2 k ohm): necesarias para proteger los leds y los botones. Los leds aceptan resistencias en el rango 150 ohmios a 1k ohm. Cuanto mayor sea el valor de la resistencia, menos brillo tendrá el led, pero también habrá menos riesgo de estropear el led, por lo que durará más. Los botones, en cambio, aceptan resistencias entre 1k ohm y 50k ohm. 

-Un puñado de cables: necesarios para conectar todo el sistema. 

Tabla de precios: 

Material Cantidad Precio/unidad Precio total del material 
Placa Arduino Uno R3 20€ 20€ 
Kit (leds, botones, resistencias, cables, ic, placa) 15,59€ 15,59€ 
Pantalla lcd i2c 8.95€ 8.95€ 
Total   44.54€ 

Algunos de estos materiales pueden ser sustituidos por otros, pero eso se explicará más en detalle en los siguientes apartados, junto con sus ventajas y desventajas. 

Cabe destacar también que los precios presentados son los que se pueden encontrar a abril de 2025 en Amazon. Dependiendo de dónde se compren los materiales, los precios podrían variar. 

3.Pasos realizados 

3.1.Planificación y diseño inicial 

El primer paso para la elaboración de este proyecto fue la creación de un diseño inicial del funcionamiento del sistema, de su hardware y de su software. 

-Diagrama de flujo con el comportamiento esperado del sistema:  

El diagrama presentado a continuación, aunque sea el inicial, también es el final, ya que no tuve que quitarle nada de funcionalidad de la pensada inicialmente ni decidí al final añadirle más funciones. El comportamiento del sistema se ha mantenido igual durante todo el proceso de desarrollo. 

Una vez hecho este diagrama, se podía empezar a diseñar una lista de necesidades del hardware y del software preliminares, surgiendo también los primeros problemas de diseño. 

-Diseño inicial de la parte hardware: 

Para empezar, se necesitaban n leds y botones, siendo n el número de topos que quisiera poner, un botón de inicio y una pantalla lcd para mostrar los puntos conseguidos y el tiempo restante. Sin embargo, al contar el número de pines necesarios (6 del lcd, 1 del botón de inicio), surge el primer problema, dado que se ve que sólo quedarían 7 pines para los topos, a repartir entre los leds y botones. Debido a esto, sólo se podrían poner tres topos, dejando un juego bastante soso. Además, aunque en su momento todavía no lo sabía, los pines 0 y 1 son problemáticos y no deberían usarse, lo que reduce aún más el número de pines disponibles y, por tanto, de topos. 

Para solucionar este problema, pensé en utilizar dos registros de desplazamiento conectados entre sí para conectarles los topos (tanto los leds como los botones), lo que me permitiría poner ocho topos (8 leds y 8 botones) gastando sólo 3 pines de la placa Arduino, que son los necesarios para conectar el primer ic (el segundo va conectado al primero). Esto seguía sin ser una solución porque presenta ciertos problemas graves, pero eso no lo sabía todavía, así que con esto di por terminado el diseño inicial de la parte hardware. 

-Diseño inicial de la parte software: 

El diseño para la parte software fue bastante escaso, ya que buena parte consistía en seguir el diagrama de comportamiento. Sin embargo, ya se podían empezar a observar algunos aspectos necesarios. 

Para empezar, tres variables para los pines del ic, un array para los 8 leds y botones, una variable para el lcd y otra para el botón de inicio. También hacían falta variables para los puntos conseguidos, el tiempo de juego restante, el número de topo escogido al azar, el tiempo restante del topo y el número de topos (para poder hacer el código más general, pudiendo cambiar rápidamente el número de topos si se quisiera). 

Sin embargo, aquí surge un nuevo problema: ¿Cómo se podían controlar los tiempos? 

La solución a esto fue sencilla: utilizar la función millis(). La función millis() devuelve el número de milisegundos que el sketch lleva cargado en la placa, por lo que, haciendo uso de esta función, de una constante intervalo con valor 1000 (1 segundo) y de dos variables llamadas previousMillis y currentMillis se pueden controlar los tiempos. El procedimiento para esto consiste en guardar el valor de millis() en currentMillis en todas las iteraciones del loop y, después, comprobar si currentMillis-previousMillis (tiempo anterior, inicialmente 0) supera el intervalo establecido (en otras palabras, ver si ha pasado un segundo desde previousMillis). Si esto no se cumple, no pasa nada, pero si, en cambio, sí se cumple, previousMillis pasa a tener el valor de currentMillis (para poder continuar buscando el siguiente segundo) y los tiempos restantes pueden disminuir en uno. 

A esto luego hubo que añadirle más cosas, pero, al contrario que en la parte hardware, la parte software del proyecto final incluye todo lo del diseño inicial. 

3.2.Parte hardware 

Dado que la parte hardware era la parte que más problemas estaba presentando, la que parecía más compleja, y era la parte con la que menos familiarizada estaba, el siguiente paso fue desarrollarla por completo. 

Para empezar, al investigar un poco más los registros de desplazamiento y su uso, me di cuenta de mi error, de que utilizar dos ic conectados no era la solución. Aparte de que sin querer estaba intentando juntar entradas y salidas en el mismo dispositivo, los registros de desplazamiento están pensados sólo para ampliar el número de salidas digitales de la placa, no sirven para ampliar las salidas también. 

Este descubrimiento me volvió a dejar con el mismo problema que al principio, el número de pines. 

Para la nueva solución, una que fuera una solución de verdad, decidí mantener uno de los registros, ya que para los leds sí que podía utilizarlo, reduciendo los 8 pines que necesitaría sin usarlo a 3. El ahorro de pines seguía siendo considerable. Sin embargo, eso seguía siendo insuficiente debido a que los pines restantes eran 4 y los pines necesarios para los botones eran 8. 

Buscando opciones que no me obligaran a quitar funcionalidad o bajar el número de topos, encontré dos buenas posibilidades: utilizar un multiplexor (con el que sí se puede hacer lo que yo estaba intentando con los ic) o cambiar la pantalla lcd por una pantalla lcd i2c. 

Las dos son igual de buenas, pero me pareció más sencilla de manejar la opción de cambiar la pantalla, dado que sólo implicaba un cambio de librería en la parte software. 

Esta pantalla es una adaptación de la anterior que permite su manejo con únicamente cuatro pines, el de 5V, el de tierra y dos pines de la parte analógica (A4 y A5 en Arduino Uno, en otras placas cambia), lo que reduce los 6 pines de la parte digital gastados en el lcd a 0. Esta liberación de 6 pines más los 4 que ya sobraban de antes permiten conectar los ocho botones que faltaban sin problemas, incluso dejando todavía 2 pines libres. 

No obstante, un problema que encontré después de haberme decidido por esta opción es que compré una pantalla lcd i2c OLED en vez de una normal pensando que serían iguales o muy parecidas en su manejo por la parte software (como en el caso del lcd y el lcd i2c). Más tarde, al intentar incluirla en el proyecto, descubrí que funcionaban de forma muy distinta. Las librerías y funciones que había que usar eran bastante distintas y, en mi opinión, algo más complejas que las del lcd i2c normal (que es muy simple). 

Aunque la versión OLED pueda ser algo más compleja de utilizar y un poco más cara, también se ve mejor, es más rápida para mostrar los cambios y permite caracteres personalizados con más facilidad. Debido a esto, aquí entran en juego las preferencias de cada uno. 

En mi caso, dado que el sistema construido no necesita caracteres especiales ni es muy exigente con la velocidad de los cambios (la versión normal los hace bien), decidí decantarme por la opción más sencilla de manejar, el lcd i2c normal. 

Con esto, el problema de los pines quedó resuelto y la parte hardware, terminada: 

Este es el diseño en tinkercad, con los elementos y sus conexiones colocados de forma que faciliten el poder visualizarlos bien (la pantalla, el ic con los leds y los botones, esas tres partes, por separado).  

El diseño físico, en cambio, está más orientado a que el juego se pueda jugar bien: botones debajo de sus respectivos leds y elementos colocados de forma que no entorpezcan al jugador para pulsar los botones o ver las luces y de forma que también se puedan ocultar bien al maquetar el sistema. 

3.3.Parte software 

Una vez finalizada la parte hardware, sólo quedaba la parte software. 

Para empezar esta parte, primero había que tener en cuenta las repercusiones de las decisiones tomadas en el hardware. 

Por un lado, los botones se declaran de forma normal, es decir, son el nombre y el número de pin, sólo que en forma de array para poder controlar mejor el tema del topo activo. 

Por otro lado, los leds conectados al ic y la pantalla lcd sí que tienen formas distintas y específicas de declararse y ser usados en software. 

Para el lcd, se necesita importar la librería LiquidCrystal_I2C.h y, de esa librería, utilizo las funciones de creación, init, clear, backlight, setCursor y print. 

La función de creación sirve para declarar el lcd y necesita tres argumentos: la dirección del lcd (se puede saber con un test de direcciones de lcd i2c subido a internet, en mi caso, 0x27), el número de columnas de la pantalla y el número de filas. La variable que devuelve es de tipo LiquidCrystal_I2C. 

Las funciones init(), clear() y backlight() las utilizo para inicializar la pantalla: inicializar la comunicación entre la placa y el lcd por i2c, eliminar cualquier texto que pudiera tener la pantalla antes y encenderla para que sea visible. 

Las funciones setCursor y print sirven para escribir en la parte que quieras de la pantalla. En mi caso las utilizo para escribir una primera vez “Puntos: 00” y “Tiempo: 00” y luego ir actualizando sólo los números en cada iteración del loop. Pongo dos ceros además para evitar que, al bajar de un número de dos cifras a uno de una, se quede el segundo número visible todavía sin tener que utilizar clear() y volver a escribir el mensaje completo. 

Para el ic y los leds, no hace falta ninguna librería adicional. En las variables se declaran los tres pines del ic (SER, RCLK y SRCLK) y un array que contenga los valores que se utilizan para cada led (1 para el led conectado a la salida 0, 2 para el led 1, 4 para el led 2, etc.). El array no es necesario para controlar los leds utilizando el ic, pero pasa lo mismo que con el de los botones, hace falta para controlar al topo activo. Los tres pines se declaran, además, como pines de salida. 

El encendido y apagado de los leds se controla con las funciones digitalWrite y shiftOut. El procedimiento consiste en: digitalWrite (RCLK, LOW) para preparar al registro para recibir datos nuevos, shiftOut (SER, SRCLK, MSBFIRST, combinación de salidas) para indicar la combinación de leds que se tienen que encender (MSBFIRST significa que se envía primero el bit más significativo y se mantiene siempre así) y digitalWrite (RCLK, HIGH) para mostrar los datos recibidos en las salidas (es decir, encender y apagar los leds previamente indicados). 

En esta fase decidí añadir dos variables más a las ya pensadas: topoNumNuevo y botonPulsado. Estas dos variables surgen como solución a dos pequeños problemas encontrados. 

Por un lado, botonPulsado sirve para saber si se ha pulsado algún topo y, por tanto, toca cambiar el topo activo. No es una variable realmente necesaria, pero sirve para hacer el código un poco más claro. 

Por otro lado, topoNumNuevo sí que soluciona un problema, que es el de los topos repetidos. Dado que la selección del siguiente topo activo se hace escogiendo un número aleatorio del 0 al 7, las probabilidades de que el siguiente topo sea el mismo que el actual son bastante altas, lo que hace que parezca que el juego funciona mal. Para corregir esto, el número del nuevo topo se guarda en esta nueva variable y luego se compara su valor con el de topoNum, que es el número del topo activo hasta el momento. De esta forma, se puede repetir la elección del número hasta que los valores sean distintos. 

La función loop del sketch se divide en varias partes que siguen el diagrama de comportamiento del proyecto, haciendo uso de todos los aspectos relacionados con el software que se han ido explicando hasta ahora. 

-Variables: 

Imagen-setup: 

-loop: 

-iniciarJuego: 

-mostrarYActualizarTiempo: 

-mostrarPuntos: 

-seleccionarTopo: 

-comprobarPuntuacionTopoYActualizar: 

-apagarTopos: 

3.4.Pruebas y retoques finales 

Por último, con las partes hardware y software terminadas, sólo quedaba juntar ambas y asegurarse de que funcionaban. En esta fase también surgieron algunos problemas. 

El primero de ellos fue la colocación de los elementos en la placa, dado que no bastaba sólo con conectar los componentes de cualquier manera. Había que hacerlo de forma que los leds y los botones pertenecientes al mismo topo estuvieran casi en la misma columna, para que se entendiera a qué led correspondía cada botón, y de forma que ningún elemento molestara a la hora de pulsar los botones, ver las luces y maquetar el sistema. 

Otro problema que ya había comentado antes pero que surgió en esta fase es la utilización de los pines digitales 0 y 1.  Estos pines son problemáticos porque interfieren con la comunicación Serial del monitor y con la programación de la placa, debido a que Arduino los utiliza para transmitir los datos de Serial y del programa.  Esto puede llevar a un comportamiento extraño del sistema si se conectan dispositivos a dichos pines. 

Aunque en las imágenes mostradas anteriormente no se refleja (dado que son las imágenes finales del proyecto, después de resolver este problema), al principio utilizaba los pines 0 y 1 en vez de los pines 9 y 10 para los dos últimos botones. Esto provocó que, al pulsar el botón de inicio para empezar una partida, se empezaran a pulsar automáticamente y todo el rato esos dos botones (comportamiento extraño del sistema mencionado antes). La solución es muy simple, no usar esos pines, y, dado que todavía me quedaban otros dos pines digitales sin usar, eso no me supuso ningún problema. 

Una vez solucionados todos los problemas, con el sistema totalmente construido y funcionando, pensé en añadir nueva funcionalidad. Las opciones que se me ocurrieron al principio fueron añadir sonidos de fin de partida o más luces que indicaran cuándo se había golpeado bien o mal a un topo. Sin embargo, no me pareció realmente necesario ya que el sistema ya tenía formas de indicar todo esto (para el fin de partida, todas las luces se apagan, y, para indicar si el topo golpeado era correcto, ya estaban los puntos conseguidos). Sólo añadiría complejidad y problemas en todas las partes para ni siquiera mejorar de verdad el juego, por lo que decidí no añadirlos. Pensando en las personas que pudieran utilizar el sistema, a veces mantener las cosas simples es mejor. 

Por último, sólo quedaba el maquetado del sistema. Todos esos cables y resistencias e incluso la placa, son cosas que al que utilice el sistema no le interesan, sólo hacen que el sistema sea más feo y fácil de estropear (si los cables están al descubierto, es muy fácil quitar alguno sin querer o que algún componente reciba algún mal golpe y se rompa). Los componentes los coloqué de forma que fuera fácil de separar la parte que tenía que ser visible de la que tenía que ser invisible, por lo que la ocultación de elementos fue relativamente sencilla. También puse una base común sobre la que se sostuvieran juntas las tres partes que iban casi separadas las unas de las otras (lcd, placa Arduino y placa protoboard con el resto de elementos), para que fuera más cómodo de manejar. Por último, decoré un poco todo con la intención de mejorar su aspecto y hacerlo más agradable para la vista, dando como resultado el sistema totalmente terminado. 

4.Vídeo de demostración

5.Autora

SEyTR_Mo Grupo 6: Zaira Ruiz Fernández.

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *