ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED
Componentes y suministros
| Microchip ATtiny85 | × | 1 | |
| OLED Gráfico 128x64 | × | 1 | |
| SparkFun microB USB Breakout | × | 1 | |
| Arduino Nano R3 | × | 1 | Para programar el ATtiny85 |
Herramientas necesarias
- Soldador (genérico)
- Impresora 3D (genérica)
Aplicaciones y servicios en línea
- Autodesk Fusion 360
- Arduino IDE
Sobre este proyecto
Inspiración y proyecto anterior
En diciembre de 2017 creé una consola Arduino Pong portátil con Arduino Nano, pantalla OLED y dos botones.
Era funcional pero demasiado grande. Ahora quiero recrear proyectos pasados haciendo una consola minúscula para jugar a Snake.
Componentes elegidos
Para lograr tamaño mínimo, no use placa Arduino de desarrollo, sino un ATtiny85.
Tiene suficientes I/O: dos pines ADC, puerto I2C y un GPIO. Usé un joystick analógico de 2 ejes con pulsador, fácil de interfazar y solo necesita 3 pines de señal.
Para la pantalla, elegí la OLED 128x64 de DFRobot por su tamaño reducido y buena resolución.
Soldando el sistema
- Soldé un ATtiny85 en un adaptador SOP-8 a DIP-8 y luego en una pequeña placa perforada.
- Añadí dos headers: uno para programación y otro para la pantalla.
- Conecté los pines del joystick analógico a la placa y cableé entsprechend.
- Finalmente, cableé una placa breakout micro USB para alimentación.
Diseñando la carcasa
La carcasa se diseñó en Fusion 360. Creé y coloqué los componentes reales y luego modelé la carcasa alrededor. Quería imitar una máquina arcade de los 80 manteniendo tamaño minúsculo. Aquí algunos renders:
Programando el juego
Snake es fácil de programar. Longitud máxima 30 segmentos para ahorrar RAM (gana al comer 29 píxeles). Uso un array 2D que almacena pares ordenados para cada segmento.
Cuando la cabeza se mueve, las posiciones anteriores se desplazan hacia abajo. Al comer, aparece un nuevo segmento en punto aleatorio. Colisiones: itero coordenadas de cada segmento comparando con la cabeza. Golpear paredes también pierde.
Jugando a Snake
Enciendo la consola, espero a que cargue la comida y el primer segmento. Luego piloto la serpiente moviendo el joystick. Es divertido y mata el aburrimiento en un paquete diminuto.
Código
- Código ATTiny85
Código ATTiny85 C/C++
Instale primero la librería U8g2lib
//#include <TinyWireM.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g(U8G2_R0, /* clock=*/ 2, /* data=*/ 0, /* reset=*/ U8X8_PIN_NONE);
#define MAX_LENGTH 30
#define X 0
#define Y 1
#define JOYSTICK_X 2
#define JOYSTICK_Y 3
#define DIR_THRESH 300
uint8_t segmentPositions[MAX_LENGTH][2];
uint8_t headPosition[2] = {63, 31};
uint8_t foodPosition[2];
uint8_t tempPosition0[2];
uint8_t tempPosition1[2];
int segmentLength = 1;
void gameUpdate();
enum DIRECTIONS { RIGHT, DOWN, LEFT, UP } currentDirection;
void setup() {
//TinyWireM.begin();
u8g.begin();
u8g.setPowerSave(0);
pinMode(JOYSTICK_X, INPUT);
pinMode(JOYSTICK_Y, INPUT);
randomSeed(analogRead(0));
beginGame();
}
void loop() {
u8g.firstPage();
do {
gameUpdate();
u8g.setColorIndex(1);
} while(u8g.nextPage());
}
void beginGame(){
currentDirection = RIGHT;
spawnFood();
delay(1000);
}
bool checkCollisions(){
for(int i=1; i<segmentLength; i++){
if(segmentPositions[i][X] == headPosition[X]){
if(segmentPositions[i][Y] == headPosition[Y]){
return 1;
}
}
}
if(headPosition[X] <= 0 || headPosition[X] >= 128) return 1;
else if(headPosition[Y] <= 0 || headPosition[Y] >= 64) return 1;
return false;
}
void spawnFood(){
int randomX = random(5, 123);
int randomY = random(5, 60);
foodPosition[X] = randomX;
foodPosition[Y] = randomY;
}
void checkFoodEaten(){
if(headPosition[X] == foodPosition[X] || headPosition[Y] == foodPosition[Y]){
segmentLength += 1;
spawnFood();
}
}
void updateDirection(){
int joy_x_val = analogRead(JOYSTICK_X);
int joy_y_val = analogRead(JOYSTICK_Y);
if(joy_x_val <= DIR_THRESH) currentDirection = LEFT;
else if(joy_x_val >= 1023-DIR_THRESH) currentDirection = RIGHT;
else if(joy_y_val <= DIR_THRESH) currentDirection = UP;
else if(joy_y_val >= 1023-DIR_THRESH) currentDirection = DOWN;
}
void displaySegments(){
for(int segment=0; segment < segmentLength; segment++){
u8g.drawPixel(segmentPositions[segment][X], segmentPositions[segment][Y]);
}
u8g.drawPixel(foodPosition[X], foodPosition[Y]);
}
void gameUpdate(){
updateDirection();
tempPosition0[X] = headPosition[X];
tempPosition0[Y] = headPosition[Y];
switch(currentDirection){
case UP: headPosition[Y] -= 1; break;
case DOWN: headPosition[Y] += 1; break;
case LEFT: headPosition[X] -= 1; break;
case RIGHT: headPosition[X] += 1; break;
}
for(int segment=1; segment < segmentLength; segment+= 2){
tempPosition1[X] = segmentPositions[segment][X];
tempPosition1[Y] = segmentPositions[segment][Y];
segmentPositions[segment][X] = tempPosition0[X];
segmentPositions[segment][Y] = tempPosition0[Y];
tempPosition0[X] = segmentPositions[segment+1][X];
tempPosition0[Y] = segmentPositions[segment+1][Y];
segmentPositions[segment+1][X] = tempPosition1[X];
segmentPositions[segment+1][Y] = tempPosition1[Y];
}
displaySegments();
checkFoodEaten();
if(checkCollisions()) endGame();
if(segmentLength >= MAX_LENGTH) endGame();
delay(50);
}
void endGame(){
segmentLength = 1;
headPosition[0] = 63;
headPosition[1] = 31;
beginGame();
}
Piezas personalizadas y envoltorios
(Archivos STL no incluidos en el original)
Esquemáticos

Proceso de manufactura
- Detector de idiomas TinyML con Edge Impulse en Arduino Nano 33 BLE Sense
- Construye un Juego Giroscópico en Tiempo Real con Arduino Nano y Sensor MPU-6050
- Proyecto Dados Digitales Arduino: Construye tu Propio Generador de Números Aleatorios con LCD
- Construye tu Propio Juego de Ruleta de 37 LEDs con Arduino Nano
- Detector de Rango Portátil – Kit DIY Arduino Nano con HC-SR04, Batería 18650 y Carcasa Impresa en 3D
- Construir una lámpara de escritorio reactiva al audio con Arduino Nano
- Proyecto de electroplacado de cobre: Construye un sistema inteligente con Arduino UNO
- Pong Neón en Matriz NeoPixel con Arduino Nano
- Crea Secuencias de Luz Impactantes con Arduino y Registro de Desplazamiento
- Enchufe Inteligente: Toma 120 V Basada en Arduino con Reloj Tiempo Real
- Sistema de seguridad Arduino: Detección de movimiento inteligente y alerta