Snake Game on 8x8 LED Matrix

Autor: STAMATIE Mihai-Robert, 333CA

Introducere

Proiectul reprezinta o implementare hardware a jocului clasic Snake pe o matrice de LED-uri 8×8, avand ca microcontroller o placa Arduino Leonardo (ATmega32U4 @ 16 MHz). Jucatorul controleaza sarpele cu ajutorul unui joystick analogic, iar butonul integrat al joystick-ului (SW — apasarea in jos a manetei) permite resetarea jocului in orice moment.

Firmware-ul este scris in C bare-metal (avr-libc + avr-gcc), fara framework-ul Arduino, cu acces direct la registrele microcontrollerului — abordare care permite control fin asupra timpilor si folosirea eficienta a resurselor disponibile pe ATmega32U4.

Logica jocului implementeaza:

  • generarea aleatorie a pozitiei hranei pe matrice (LFSR pe 16 biti, seed-uit din zgomotul ADC);
  • cresterea progresiva a sarpelui la fiecare hrana consumata;
  • detectia coliziunilor cu propriul corp;
  • wrap-around la marginile matricei (sarpele “iese” pe o margine si apare pe partea opusa);
  • cresterea progresiva a vitezei pe masura ce scorul avanseaza;
  • afisarea scorului direct pe matricea de LED-uri la finalul partidei (font 3×5 pixeli);
  • salvarea high-score-ului in EEPROM, persistent intre resetari;
  • animatii pentru boot, death si high-score nou.

Motivatia: mi-am dorit un proiect care sa combine partea de I/O analogic (joystick, citire ADC) cu o componenta de afisare controlata printr-un protocol serial (SPI software, prin MAX7219) si cu stocare persistenta (EEPROM), pentru a acoperi cat mai multe notiuni din curs intr-un singur proiect. In plus, Snake este un joc cu logica simpla dar captivanta, iar provocarea de a-l face sa ruleze pe doar 64 de pixeli este parte din distractie.

Descriere generala

Sistemul este compus din trei parti functionale principale:

  • Input: joystick-ul analogic furnizeaza doua semnale analogice (axele X si Y) citite de ADC-ul pe 10 biti al microcontrollerului, plus un semnal digital (SW) folosit pentru reset, conectat la PD1 cu pull-up intern.
  • Procesare: placa Arduino Leonardo (ATmega32U4 @ 16 MHz) ruleaza logica jocului — citeste input-ul, actualizeaza pozitia sarpelui in memorie, genereaza aleator coordonatele hranei, detecteaza coliziuni, calculeaza scorul si gestioneaza stocarea high-score-ului in EEPROM.
  • Output: matricea de LED-uri 8×8, controlata prin driver-ul MAX7219 via SPI software (bit-banging), afiseaza in timp real starea jocului: pozitia sarpelui, hrana (cu efect de blink), scorul final si animatiile de stare.

Alimentarea se face de la portul micro-USB al PC-ului (5V), care serveste simultan si ca interfata de programare prin USB-ul nativ al ATmega32U4.

snake_game_2026pm-project.png

Hardware Design

Lista de piese (Bill of Materials)

Nr. Componenta Cantitate Descriere / Rol
1 Placa Arduino Leonardo 1 Microcontroller ATmega32U4 @ 16 MHz
2 Matrice LED 8×8 cu driver MAX7219 (LED Dot Matrix Display, Red) 1 Display-ul propriu-zis al jocului
3 Modul joystick analogic (Generic, ex. KY-023) 1 Control directie X/Y + buton SW integrat pentru restart
4 Breadboard mic (Solderless Breadboard Half Size) 1 Suport pentru cablaj
5 Fire dupont tata-mama (Female/Female Jumper Wires) ~10 Conexiuni Arduino — module
6 Fire dupont generice (Jumper wires generic) ~5 Conexiuni pe breadboard
7 Cablu micro-USB 1 Programare si alimentare

Conexiuni

Componenta Pin componenta Pin Arduino Leonardo Port / Pin AVR
Joystick VCC 5V
Joystick GND GND
Joystick VRX A0 PF7 (ADC7)
Joystick VRY A1 PF6 (ADC6)
Joystick SW (buton integrat) D2 PD1 (pull-up intern, active LOW — folosit pentru restart)
Matrice MAX7219 VCC 5V
Matrice MAX7219 GND GND
Matrice MAX7219 DIN D11 PB7
Matrice MAX7219 CS D10 PB6
Matrice MAX7219 CLK D13 PC7

Nota despre SPI pe Leonardo: pinii hardware SPI ai placii Leonardo (MOSI / MISO / SCK) sunt expusi doar pe header-ul ICSP, nu pe D11/D12/D13 ca la UNO. In proiect este folosit SPI software (bit-banging direct pe registrele PORTB / PORTC), asa ca alegerea pinilor D10 / D11 / D13 este pur conventionala. Pinul D13 este partajat cu LED-ul on-board, dar acest lucru nu afecteaza comunicatia cu MAX7219.

Schema electrica

Schema electrica - cablaj breadboard

Schema de mai sus prezinta cablajul complet realizat pe breadboard: joystick-ul analogic conectat la pinii A0 (VRX), A1 (VRY) si D2 (SW pentru restart), iar matricea LED 8×8 cu driver MAX7219 conectata la pinii D11 (DIN), D10 (CS), D13 (CLK). Alimentarea de 5V este distribuita prin rail-urile breadboard-ului direct de la pinii Arduino.

Software Design

Mediu de dezvoltare

  • Toolchain: avr-gcc + avr-libc + avr-objcopy
  • Flashing: avrdude (protocol avr109 pentru Leonardo, baud 57600)
  • Build system: Makefile clasic (vezi sectiunea Download)
  • Limbaj: C pur (C99), fara framework Arduino — acces direct la registrele MCU

Arhitectura codului

Codul este organizat modular in mai multe grupuri de functii, toate in main.c:

  • Driver MAX7219 (SPI software): spi_init(), spi_tx(), mx_wr(), mx_init() — toggle direct pe PORTB / PORTC pentru DIN, CS, CLK.
  • Framebuffer: fb_clr(), fb_dot(), fb_push() — un array uint8_t fb[8] tine starea matricei (un byte per linie, fiecare bit = un LED). Push pe matrice se face cu mx_wr(r+1, fb[r]).
  • Driver ADC: adc_init(), adc_rd(ch) — citire pe canalele ADC6 / ADC7 (A1 / A0), prescaler 128.
  • Driver buton: btn_init(), btn_rst() — pull-up intern pe PD1, debounce software 30 ms.
  • EEPROM: ee_load(), ee_save() — high-score-ul e salvat la adresa 0x00, cu un byte “guard” (0xD4) la adresa 0x01 pentru a detecta EEPROM neinitializat la primul boot.
  • Logica joc: read_joy() (citeste joystick + previne intoarcerea pe directia opusa), game_step() (actualizeaza pozitia cu wrap-around la margini, detecteaza coliziuni, mananca hrana), place_apple() (random pana se gaseste o celula libera), cur_steps() (calculeaza viteza curenta in functie de scor).
  • Rendering: draw() (deseneaza sarpe + hrana blinking), show_score() (afiseaza scorul cu font 3×5), anim_boot() / anim_dead() (animatii).

Algoritmi si structuri principale

  • Reprezentarea sarpelui: array de coordonate Pt snake[MAXLEN], unde MAXLEN = 64. Capul e snake[0]. La fiecare pas, toate elementele sunt shift-uite cu o pozitie si capul nou e scris la index 0.
  • Detectia coliziunilor: se parcurge snake[] si se verifica daca noul cap se suprapune cu vreun segment existent.
  • Random (LFSR): generator pseudo-aleator pe 16 biti cu polinom 0xB400, seed-uit la boot din zgomotul ADC al ambelor axe — nu necesita hardware suplimentar.
  • Anti-reverse: input-ul de la joystick e filtrat pentru a nu permite intoarcerea direct pe directia opusa (ar duce la coliziune instant).
  • Viteza adaptiva: cur_steps() returneaza numarul de tick-uri (de 20 ms fiecare) intre deplasari — scade liniar cu scorul, de la 14 (start) la 4 (rapid).
  • Font scor: DIG[10][5] — fiecare cifra ocupa 3×5 pixeli, codificata ca 5 byti (low 3 biti activi per linie).

Concluzii

Proiectul a fost finalizat cu succes — jocul Snake este complet functional pe placa Arduino Leonardo, ruleaza fluid pe matricea LED 8×8 si raspunde rapid la input-ul de la joystick. Implementarea in C bare-metal s-a dovedit a fi o alegere potrivita pentru acest tip de proiect, oferind control direct asupra timpilor de executie si o intelegere mai profunda a modului de functionare a microcontrollerului ATmega32U4 la nivel de registre.

Aspecte care au functionat bine

  • Driver-ul SPI software pentru MAX7219 s-a dovedit suficient de rapid si stabil pentru rate-ul de refresh dorit, fara a fi necesar SPI hardware (care oricum nu este disponibil pe pinii D11/D12/D13 pe Leonardo).
  • Generatorul LFSR pe 16 biti, seed-uit din zgomotul ADC al ambelor axe la pornire, ofera o distributie rezonabila a pozitiilor hranei fara a necesita hardware suplimentar (timer extern, RTC).
  • Salvarea high-score-ului in EEPROM cu un byte de guard (0xD4) previne afisarea de valori reziduale la primul boot dupa flashing.
  • Wrap-around-ul la marginile matricei face jocul mai accesibil decat varianta clasica cu coliziuni la pereti, fiind o decizie de design care creste durata medie a partidelor.
  • Folosirea butonului SW integrat in joystick (in loc de un buton extern separat) reduce numarul de componente si simplifica cablajul.

Provocari intampinate

  • Maparea pinilor pe ATmega32U4 difera semnificativ de ATmega328P (Arduino UNO) — in special faptul ca SPI hardware nu este pe pinii digitali standard, ci doar pe header-ul ICSP. Solutia adoptata (SPI software) este insa mai flexibila si independenta de placa folosita.
  • Calibrarea zonelor moarte ale joystick-ului (JOY_LO = 300, JOY_HI = 700) a necesitat experimentare — prea mica genereaza schimbari de directie false, prea mare face controlul lent si imprecis.
  • Vitezele de joc (STEPS_SLOW = 14, STEPS_FAST = 4) au necesitat ajustare pentru un gameplay placut: prea rapid in faza incipienta, jocul devine frustrant; prea lent, devine plictisitor.

Posibile extensii viitoare

  • Adaugarea unui buzzer pasiv pentru efecte sonore (PWM via timer hardware) la consumarea hranei si la game over.
  • Implementarea unui meniu de selectie a dificultatii initiale (slow / normal / hard).
  • Optimizarea consumului prin utilizarea modurilor sleep ale MCU intre tick-uri.
  • Portare pe alta placa AVR (Mega, Uno, Nano) cu modificari minime la nivel de pini.

Download

Arhiva contine varianta finala a proiectului, gata de compilat si rulat pe Arduino Leonardo. Include sursele complete (main.c), Makefile pentru build si flash, plus un fisier README cu instructiuni de utilizare.

Pentru a rula proiectul:

  1. Conectati placa Arduino Leonardo prin micro-USB
  2. Dezarhivati snake_game.zip
  3. In folder-ul dezarhivat, rulati make pentru a compila
  4. Rulati make flash (sau scriptul flash.ps1 pe Windows) pentru a incarca firmware-ul

Bibliografie/Resurse

Resurse Hardware

Resurse Software

pm/prj2026/victor.stoica0203/mihai.stamatie.txt · Last modified: 2026/05/24 08:23 by mihai.stamatie
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0