Captura de Tela 2026 04 06 as 17.50.22 Saravati

Projeto: Jogo Tetris com ESP32 e Display Matrix MAX7219

Neste projeto vamos construir um jogo Tetris utilizando um ESP32 e quatro matrizes de LED MAX7219.
O jogo roda totalmente no microcontrolador, e utilizaremos botões para mover as peças para a esquerda e direita.

Este projeto é excelente para aprender:

  • Programação embarcada
  • Matrizes de LED
  • Comunicação SPI
  • Lógica de jogos
  • Manipulação de coordenadas
  • Estruturas de dados
  • Controle por botões

Materiais Necessários

Ligações dos Displays MAX7219

MAX7219ESP32
VCC5V
GNDGND
DIND23
CLKD18
CSD5

Os displays devem ser ligados em cascata:

  • DOUT do display 1 → DIN do display 2
  • DOUT do display 2 → DIN do display 3
  • DOUT do display 3 → DIN do display 4

Os displays devem ficar empilhados na vertical, onde:

  • Display 1 = topo
  • Display 4 = chão do Tetris

Ligações dos Botões

BotãoESP32Outro lado
esquerdaD19GND
direitaD21GND

Os pinos serão configurados como INPUT_PULLUP, então não precisa resistor externo.

Funcionamento do Jogo

O jogo funciona da seguinte forma:

  1. Uma peça aparece no topo
  2. A peça desce automaticamente
  3. Botões movem esquerda/direita
  4. Quando a peça encosta, ela fixa
  5. Linhas completas são apagadas
  6. Nova peça aparece
  7. O jogo continua

O display total possui:

  • 8 colunas
  • 32 linhas
  • Total: 8×32 pixels

Código do Projeto – Tetris ESP32 + MAX7219

#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 5

#define BTN_LEFT  19
#define BTN_RIGHT 21

MD_MAX72XX mx(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

const int W = 8;
const int H = 32;

bool board[H][W];

int pieceX, pieceY;
int pieceType;
int rot;

unsigned long lastFall = 0;
unsigned long lastMove = 0;
int fallDelay = 250;
int moveDelay = 120;

const uint16_t pieces[7][4] = {
 {0x0F00,0x2222,0x00F0,0x4444},
 {0x6600,0x6600,0x6600,0x6600},
 {0x4E00,0x4640,0x0E40,0x4C40},
 {0x6C00,0x4620,0x06C0,0x8C40},
 {0xC600,0x2640,0x0C60,0x4C80},
 {0x8E00,0x6440,0x0E20,0x44C0},
 {0x2E00,0x4460,0x0E80,0xC440}
};

bool cell(int type, int rot, int x, int y)
{
 uint16_t m = pieces[type][rot];
 int bit = 15 - (y * 4 + x);
 return (m >> bit) & 1;
}

// Mapeamento vertical correto
void drawPixelGame(int x, int y, bool state)
{
 if (x < 0 || x >= W || y < 0 || y >= H) return;

 int module = y / 8;
 int localY = y % 8;

 localY = 7 - localY;

 int row = 7 - x;
 int col = (MAX_DEVICES - 1 - module) * 8 + localY;

 mx.setPoint(row, col, state);
}

void clearBoard()
{
 for (int y = 0; y < H; y++)
   for (int x = 0; x < W; x++)
     board[y][x] = false;
}

bool collision(int nx, int ny, int r)
{
 for (int py = 0; py < 4; py++)
 for (int px = 0; px < 4; px++)
 {
   if (!cell(pieceType, r, px, py)) continue;

   int bx = nx + px;
   int by = ny + py;

   if (bx < 0 || bx >= W || by >= H) return true;
   if (by >= 0 && board[by][bx]) return true;
 }
 return false;
}

void mergePiece()
{
 for (int py = 0; py < 4; py++)
 for (int px = 0; px < 4; px++)
 {
   if (!cell(pieceType, rot, px, py)) continue;

   int bx = pieceX + px;
   int by = pieceY + py;

   if (by >= 0 && bx >= 0 && bx < W && by < H)
     board[by][bx] = true;
 }
}

void clearLines()
{
 for (int y = H - 1; y >= 0; y--)
 {
   bool full = true;

   for (int x = 0; x < W; x++)
     if (!board[y][x]) full = false;

   if (full)
   {
     for (int yy = y; yy > 0; yy--)
       for (int x = 0; x < W; x++)
         board[yy][x] = board[yy - 1][x];

     for (int x = 0; x < W; x++)
       board[0][x] = false;

     y++;
   }
 }
}

void newPiece()
{
 pieceType = random(0, 7);
 rot = random(0, 4);
 pieceX = random(0, W - 3);
 pieceY = -1;
}

void draw()
{
 mx.clear();

 for (int y = 0; y < H; y++)
 for (int x = 0; x < W; x++)
   if (board[y][x])
     drawPixelGame(x, y, true);

 for (int py = 0; py < 4; py++)
 for (int px = 0; px < 4; px++)
 {
   if (!cell(pieceType, rot, px, py)) continue;

   int bx = pieceX + px;
   int by = pieceY + py;

   drawPixelGame(bx, by, true);
 }
}

void setup()
{
 mx.begin();
 mx.control(MD_MAX72XX::INTENSITY, 5);
 mx.clear();

 pinMode(BTN_LEFT, INPUT_PULLUP);
 pinMode(BTN_RIGHT, INPUT_PULLUP);

 randomSeed(micros());
 clearBoard();
 newPiece();
}

void loop()
{
 if (millis() - lastMove > moveDelay)
 {
   lastMove = millis();

   if (digitalRead(BTN_LEFT) == LOW)
     if (!collision(pieceX - 1, pieceY, rot))
       pieceX--;

   if (digitalRead(BTN_RIGHT) == LOW)
     if (!collision(pieceX + 1, pieceY, rot))
       pieceX++;
 }

 if (millis() - lastFall > fallDelay)
 {
   lastFall = millis();

   if (!collision(pieceX, pieceY + 1, rot))
     pieceY++;
   else
   {
     mergePiece();
     clearLines();
     newPiece();
   }
 }

 draw();
}

O que você aprendeu com esse projeto

Esse projeto envolve vários conceitos importantes:

  • Comunicação SPI
  • Matrizes de LED
  • Coordenadas X e Y
  • Arrays bidimensionais
  • Detecção de colisão
  • Estrutura de jogo
  • Leitura de botões
  • Programação embarcada
  • Estruturas de dados
  • Lógica de rotação de peças
  • Sistemas embarcados

Esse tipo de projeto é exatamente o tipo de coisa que forma um profissional de eletrônica e sistemas embarcados.

Saiba mais sobre a parceria Saravati e Sara Educação

Este “Guia de Montagem” é uma colaboração especial entre a Saravati e a Sara Educação, criado pelo Professor Felipe Rosa. Nosso objetivo é enriquecer a comunidade de entusiastas da eletrônica, IoT e automação com recursos educacionais de alta qualidade. Através dessa parceria, buscamos inspirar e capacitar criadores em seus projetos, disponibilizando esses guias em nosso blog e nas redes sociais.

@saravatirobotica no Instagram e Tiktok

@sara.educacao no Instagram e Tiktok