Introducere

Proiectul consta in implementarea jocului Minesweeper, folosind pentru afisare un display Nokia 3310 PCD 8854. Jocul are 6 x 7 casute si 5 bombe. Bombele sunt plasate in mod aleator pe tabela de joc. Scopul jocului este descoperirea si marcarea bombelor. Se va putea salva un joc neterminat.

Descriere generală

Urmatoarea schema bloc descrie functionarea jocului:

schema.jp.jpg

Hardware Design

Placa de baza:

placabazadiana.jpg

Pentru realizarea proiectului, am realizat o placuta suplimentara pe care sunt lipite circuitele pentru LCD si butoanele prin care se realizeaza comanda asupra jocului.

Lista de piese:

  • 5 rezistente de 2k2
  • 5 rezistente de 4k6
  • 4 diode 1N4007
  • 1 condensator 10uF
  • 7 butoane (stanga, dreapta, sus, jos, selectare, marcare, salvare joc/incarcare joc salvat)
  • LCD Nokia 3310 PCD8544

Pentru conectarea LCD-ului, am realizat o placuta imprimata cu 8 trasee. LCD-ul face contact direct cu placuta imprimata si este lipit de aceasta cu banda adeziva.

Pentru a aduce tensiunea de alimentare de la 5V oferiti de ATMega16 la 3.3V pentru LCD am folosit 4 diode 1N4007. Teoretic este nevoie de 2 diode (5V - 2 * 0.7V = 3.6V), insa microcontrollerul meu ofera 5.2V, iar diodele au o cadere de tensiune de 0.4V. Astfel, folosind 4 diode am obtinut o tensiune de alimentare de 3.7-3.8V. LCD-ul functioneaza corect.

Pentru LCD, pinout-ul este urmatorul:

  • 1 - VDD – Input Voltage
  • 2 - SCK – Serial Clock -PB7
  • 3 - SDI – Serial Data Input -PB5
  • 4 - D/C – Data/Command Input -PB0
  • 5 - SCE – Chip Select -PB1
  • 6 - GND - Ground
  • 7 - VOUT – VLCD
  • 8 - RES – Reset -PB3

Este nevoie de divizoare de tensiune pentru fiecare intrare din LCD (SCK, SDI, D/C, SCE, RES) pentru ca tensiunea sa fie de 3.3V. Divizorul este realizat cu ajutorul rezistentelor de 2k2 si 4k6.

Cele 7 butoane sunt puse pe portul C si au urmatoarea semnificatie:

  • 0 - marcare celula
  • 1 - jos
  • 2 - stanga
  • 3 - sus
  • 4 - dreapta
  • 5 - selectare celula/joc nou (dupa ce se castiga sau pierde jocul curent)
  • 6 - salvare/incarcare joc salvat

A fost montat si circuitul pentru slotul de card SD pe placa de baza.

Schema in Eagle:

Screenshot simulare in Proteus:

Software Design

Proiectul a fost realizat utilizand WinAVR.

Pentru interfatarea LCD-ului am folosit driver-ul de aici cu modificari: http://www.quantumtorque.com/content/view/32/37/

Tabela de joc cu informatiile aferente jocului este retinuta intr-o matrice unsigned char de dimensiuni 6 x 7 - table[NR_ROW][NR_COL]. In fiecare table[i][j] se retin urmatoarele informatii: in primii 3 biti se retine numarul de bombe din jurul sau (adica din cei 8 vecini), urmatorul bit este nefolosit, bitul 5 este setat daca casuta contine o bomba sau nu, bitul 6 este setat daca utilizatorul a marcat casuta respectiva ca fiind bomba si bitul 7 este setat daca casuta a fost descoperita sau nu (bitul 8 este nefolosit).

#define MINES		0x0F
#define IS_MINE	        0x10	
#define IS_MARKED	0x20
#define IS_UNCOVERED	0x40

Daca utilizatorul selecteaza o casuta pentru a o descoperi, se apeleaza functia recursiva uncover_cell. Aceasta se opreste din recursivitate cand in jurul casutei curente exista bombe.

Dupa marcarea unei celule drept bomba, in casuta respectiva va aparea semnul +. O bomba este marcata cu X.

Daca utilizatorul pierde sau castiga, se descopera toata tabla si se afiseaza un mesaj, dandu-se posibilitatea inceperii unui nou joc sau incarcarii jocului salvat din memorie.

Pentru generarea numerelor aleatoare, folosesc rand(), cu seed o variabila citita din memoria EEPROM si incrementata. Dupa aceea, scriu in memoria EEPROM noua valoare, pentru ca la urmatoarea rulare a jocului sa fie o dispunere a bombelor diferita de cele precedente. La inceput, nu se gaseste o valoare in memoria EEPROM (pentru acest lucru ar fi trebuit sa incarc si un fisier .eep, separat de fisierul .hex). Pentru a nu trebui sa incarc initial si un fisier .eep, prima data variabila seed va fi initializata cu valoarea 1, iar la urmatoarele rulari nu se va mai efectua aceasta initializare.

unsigned char EEMEM seed;

if (eeprom_read_byte((uint8_t*)E_INIT_SEED) !='T')
{
	i = 1;
	eeprom_write_byte(&seed, i); 
	eeprom_write_byte((uint8_t*)E_INIT_SEED,'T');
}
else
{
	s = eeprom_read_byte(&seed);
	if (s == 255)
		s = 0;
	else s ++;
	eeprom_write_byte(&seed, s);
}

Salvarea jocului se realizeaza in memoria EEPROM, deoarece jocul ocupa doar 42 bytes. Se salveaza matricea table.

Bufferul de afisare are dimensiunea 6×84.

static unsigned char cursor_row = 0; /* 0-5 */
static unsigned char cursor_col = 0; /* 0-83 */
static unsigned char buffer[6][84];

Pentru LCD:

void lcd_init(void);
void lcd_contrast(unsigned char contrast);
void lcd_clear(void);
void lcd_putchr(unsigned char ch);
void lcd_str(char str[14], uint8_t len);
void lcd_gotoXY(uint8_t x, uint8_t y);
void lcd_update( void );
void lcd_setpixel(unsigned char x, unsigned char y);
void lcd_clearpixel(unsigned char x, unsigned char y);
void lcd_border(void);
void dark_cell(unsigned char y, unsigned char x);
void mark_cell(unsigned char y, unsigned char x);
void unmark_cell(unsigned char y, unsigned char x);
void uncovercell(unsigned char y, unsigned char x, unsigned char value);
void uncovermine(unsigned char y, unsigned char x);	

Rezultate Obţinute

Proiectul este functional, indeplinind toate cerintele initiale.

http://www.youtube.com/watch?v=TL6B8iC_TMA

http://www.youtube.com/watch?v=VmNdeBHQaSI

Download

Concluzii

Realizarea unui astfel de proiect este o experienta interesanta. Conectarea LCD-ului este foarte anevoiasa. Deoarece nu am folosit suruburi, exista posibilitatea de departare a LCD-ului de trasee si se poate ajunge sa nu mai faca contact cu placa.

Bibliografie/Resurse

pm/prj2010/dtudose/minesweeper.txt · Last modified: 2021/04/14 17:07 (external edit)
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