This shows you the differences between two versions of the page.
pm:prj2024:azamfir:ana_maria.toader02 [2024/05/23 21:09] ana_maria.toader02 [Bibliografie/Resurse] |
pm:prj2024:azamfir:ana_maria.toader02 [2024/05/27 03:27] (current) ana_maria.toader02 [Rezultate Obţinute] |
||
---|---|---|---|
Line 10: | Line 10: | ||
* un board (solvable) randomizat este generat pentru fiecare nou joc | * un board (solvable) randomizat este generat pentru fiecare nou joc | ||
* un buzzer emite sunete la realizarea unei mișcări greșite sau la câștigarea jocului | * un buzzer emite sunete la realizarea unei mișcări greșite sau la câștigarea jocului | ||
+ | * fiecare joc are o limită de timp de 5 minute; la expirarea timpului, jocul este pierdut | ||
Scopul proiectului este realizarea unui joc entertaining. | Scopul proiectului este realizarea unui joc entertaining. | ||
===== Descriere generală ===== | ===== Descriere generală ===== | ||
Line 35: | Line 36: | ||
| Fire tată-tată | [[https://www.optimusdigital.ro/ro/fire-fire-mufate/885-set-fire-tata-tata-10p-10-cm.html|Set fire tată-tată]] | 2 | 2,85 lei | | | Fire tată-tată | [[https://www.optimusdigital.ro/ro/fire-fire-mufate/885-set-fire-tata-tata-10p-10-cm.html|Set fire tată-tată]] | 2 | 2,85 lei | | ||
^ Cost total: 150,87 lei |||| | ^ Cost total: 150,87 lei |||| | ||
+ | |||
+ | **Cablaj final:**\\ | ||
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:cablaj_final.jpeg?500|}} | ||
+ | |||
+ | |||
===== Software Design ===== | ===== Software Design ===== | ||
==== Setup ==== | ==== Setup ==== | ||
Line 48: | Line 54: | ||
==== Implementare ==== | ==== Implementare ==== | ||
+ | **Logica jocului**\\ | ||
+ | Tabla de joc este definită ca un array bidimensional în care fiecare celulă poate lua una dintre valorile predefinite ce simbolizează elementele de joc //(BLANK, BOMB, RED_BOMB, FLAG, EMPTY, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT)//. | ||
+ | <code cpp>extern unsigned int board[ROWS][COLUMNS];</code> | ||
+ | Pentru implementarea logicii jocului am scris funcții pentru diverse funcționalități: | ||
+ | * inițializarea bombelor în poziții random pe grid (tabla este randomizată la fiecare joc nou) | ||
+ | * indicarea poziției pe grid prin highlight-ul unei celule | ||
+ | * input handling pentru acțiunile jucătorului (apăsarea butoanelor, mișcarea joystick-ului sau apăsarea switch-ului de pe joystick) | ||
+ | * descoperirea unei singure celule ce conține un număr sau a tuturor celulelor libere adiacente în cazul unei celule goale | ||
+ | * amplasarea de flag-uri | ||
+ | * afișarea unui timer care se actualizează la interval fix de o secundă | ||
+ | * resetarea jocului la apăsarea switch-ului de pe joystick (cu reinițializarea tuturor parametrilor jocului, a timer-ului și randomizarea tablei) | ||
+ | * verificarea condițiilor de win / lose și în funcție de caz: | ||
+ | * afișarea mesajelor specifice (GAME OVER sau CONGRATULATIONS) | ||
+ | * emiterea unor sunete distinctive acționând buzzer-ul | ||
+ | * la finalul jocului singura acțiune care mai este responsive este apăsarea switch-ului de pe joystick care duce la începerea unui joc nou | ||
+ | \\ | ||
+ | **Grafică**\\ | ||
+ | Pentru a crea imaginile distinctive jocului pentru fiecare celulă posibilă am desenat imagini de 20x20px pe care le-am convertit folosind un [[https://javl.github.io/image2cpp/|tool]] online în bitmap-uri grayscale de 8biți per pixel. Le-am afișat la poziții corespunzătoare pe ecran folosind funcția ''**void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)**'' din biblioteca **Adafruit_GFX**. Am adăugat culori prin setarea //foreground color//. \\ | ||
+ | |||
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:bomb.png?130 |}}<code c> | ||
+ | const unsigned char bomb[] PROGMEM = { | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xf0, 0x00, 0x0b, 0xfd, 0x00, 0x07, | ||
+ | 0xfe, 0x00, 0x16, 0x7e, 0x80, 0x0e, 0x7f, 0x00, 0x0f, 0xff, 0x00, 0x1f, 0xff, 0x80, 0x1f, 0xff, | ||
+ | 0x80, 0x0f, 0xff, 0x00, 0x0f, 0xff, 0x00, 0x17, 0xfe, 0x80, 0x07, 0xfe, 0x00, 0x0b, 0xfd, 0x00, | ||
+ | 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
+ | }; | ||
+ | </code> | ||
+ | \\ | ||
+ | **Buzzer**\\ | ||
+ | La sfârșitul jocului, buzzer-ul emite sunete distinctive. Am ales două melodii din [[https://github.com/robsoncouto/arduino-songs|arduino-songs]] pentru cazurile de victorie / înfrângere.\\ | ||
+ | \\ | ||
**Timer**\\ | **Timer**\\ | ||
Microcontroller-ul **//ATmega328p//** conține 3 unități de timer, două pe 8 biți (//Timer0// și //Timer2//) și unul pe 16 biți (//Timer1//). \\ | Microcontroller-ul **//ATmega328p//** conține 3 unități de timer, două pe 8 biți (//Timer0// și //Timer2//) și unul pe 16 biți (//Timer1//). \\ | ||
Line 96: | Line 133: | ||
} | } | ||
</code> | </code> | ||
+ | \\ | ||
+ | |||
+ | **Întreruperi**\\ | ||
+ | La inițializare, am activat mecanismul de întreruperi prin activarea bitului **//I//** din registrul **//SREG//**. | ||
+ | <code cpp> | ||
+ | /* Activate interrupts */ | ||
+ | sei(); | ||
+ | </code> | ||
+ | Am definit două rutine pentru tratarea întreruperilor externe (pentru apăsarea butoanelor și pentru apăsarea butonului de la joystick) și una pentru tratarea întreruperilor interne folosind Timer1. \\ | ||
+ | |||
+ | **Configurarea componentelor care vor trimite întreruperi:** | ||
+ | * cele două butoane sunt conectate la același pin **//BUTTON_INTERRUPT//** pentru întreruperi | ||
+ | <code cpp> | ||
+ | /* initialize button pins */ | ||
+ | pinMode(BLUE_BUTTON, INPUT); | ||
+ | pinMode(RED_BUTTON, INPUT); | ||
+ | |||
+ | pinMode(BUTTON_INTERRUPT, INPUT); | ||
+ | attachInterrupt(digitalPinToInterrupt(BUTTON_INTERRUPT), ISR_button, RISING); | ||
+ | </code> | ||
+ | Am folosit funcția ''attachInterrupt'' pentru a atașa rutina **//ISR_button//** evenimentelor de pe pinul corespunzător butoanelor. Parametrul ''RISING'' definește momentul în care va fi declanșată întreruperea - atunci când valoarea pinului trece de la LOW la HIGH (la apăsarea unuia dintre butoane). \\ | ||
+ | * pinul **//SW//** al joystick-ului este conectat la pinul **//JOYSTICK_INTERRUPT//** de pe plăcuță, căruia i-am asociat rutina **//ISR_joystick//** | ||
+ | <code cpp> | ||
+ | /* initialize joystick pins */ | ||
+ | pinMode(JOYSTICK_X, INPUT); | ||
+ | pinMode(JOYSTICK_Y, INPUT); | ||
+ | |||
+ | pinMode(JOYSTICK_INTERRUPT, INPUT); | ||
+ | digitalWrite(JOYSTICK_INTERRUPT, HIGH); | ||
+ | attachInterrupt(digitalPinToInterrupt(JOYSTICK_INTERRUPT), ISR_joystick, RISING); | ||
+ | </code> | ||
+ | |||
+ | Toate variabilele care vor fi modificate într-o rutină de tratare a întreruperilor trebuie marcate ca **''volatile''** pentru a indica compilatorului să nu treacă variabila prin cache. Orice acces la o variabilă **''volatile''** se va face prin RAM. | ||
+ | <code c> | ||
+ | /* Initialize volatile variables used with button interrupts */ | ||
+ | volatile bool blueButtonFlag = false; | ||
+ | volatile bool redButtonFlag = false; | ||
+ | |||
+ | volatile unsigned long lastPressRed = 0; | ||
+ | volatile unsigned long lastPressBlue = 0; | ||
+ | |||
+ | volatile bool joystickButtonFlag = false; | ||
+ | </code> | ||
+ | |||
+ | **Definirea rutinelor de tratare a întreruperilor:** | ||
+ | * pentru **butoane** - declanșarea întreruperii are loc la apăsarea unuia dintre butoane, moment în care se verifică care dintre butoane a fost apăsat și se setează flagul corespunzător acestuia (**//blueButtonFlag//** sau **//redButtonFlag//**. Pentru a trata existența zgomotului, am implementat debouncing software pentru butoane. | ||
+ | <code cpp> | ||
+ | void ISR_button() { | ||
+ | buttonPressTime = millis(); | ||
+ | if (digitalRead(BLUE_BUTTON) && buttonPressTime - lastPressBlue > debounceTime) { | ||
+ | lastPressBlue = buttonPressTime; | ||
+ | blueButtonFlag = true; | ||
+ | |||
+ | } else if (digitalRead(RED_BUTTON) && buttonPressTime - lastPressRed > debounceTime) { | ||
+ | lastPressRed = buttonPressTime; | ||
+ | redButtonFlag = true; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | * pentru **joystick** - declanșarea întreruperii are loc la apăsarea switch-ului, iar rutina de tratare a acesteia setează flag-ul **//joystickButtonFlag//** care va fi folosit în logica programului | ||
+ | <code cpp> | ||
+ | void ISR_joystick() { | ||
+ | joystickButtonFlag = true; | ||
+ | } | ||
+ | </code> | ||
+ | * pentru **Timer1** - întreruperea este declanșată la intervale fixe de o secundă; în rutina de tratare se resetează registrul counter la zero pentru a putea relua numărătoarea, se decrementează valoarea timer-ului și se setează flag-ul corespunzător **timerFlag** pentru marcarea faptului că a avut loc întreruperea în fluxul principal al programului | ||
+ | <code cpp> | ||
+ | ISR(TIMER1_COMPA_vect){ | ||
+ | TCNT1 = 0; /* Reset counter register */ | ||
+ | |||
+ | timer--; | ||
+ | timerFlag = true; | ||
+ | } | ||
+ | </code> | ||
+ | Parametrul **TIMER1_COMPA_vect** indică faptul că se face Compare Match cu pragul A al timerului. | ||
===== Rezultate Obţinute ===== | ===== Rezultate Obţinute ===== | ||
+ | * inițializarea jocului, cu setarea timer-ului la 5 minute | ||
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:init.gif?700|}} | ||
- | <note tip> | + | * eliberarea unui grup de celule |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | {{:pm:prj2024:azamfir:ana_maria.toader02:clear_multiple_cells.gif?700|}} |
- | </note> | + | |
- | ===== Concluzii ===== | + | * sfârșitul jocului |
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:game_won.gif?700|}} | ||
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:game_over.gif?700|}} | ||
- | ===== Download ===== | + | * resetarea jocului la apăsarea switch-ului de pe joystick, cu resetarea timer-ului la 5 minute |
+ | {{:pm:prj2024:azamfir:ana_maria.toader02:reset.gif?700|}} | ||
- | <note warning> | + | ===== Concluzii ===== |
- | O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). | + | Un proiect interesant, mă bucur că am obținut ceva funcțional. |
- | Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:prj20??:c?:nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin, 331CC -> **:pm:prj2009:cc:dumitru_alin**. | + | Deși am ales un proiect simplu, cu puține componente hardware (pentru a nu avea mari bătăi de cap :-)) am avut mari bătăi de cap m( încercând să fac display-ul să funcționeze la tensiunea de alimentare de 3v3. |
- | </note> | + | ===== Download ===== |
+ | [[https://github.com/anatoad/Minesweeper-Arduino|Github repo]] | ||
===== Jurnal ===== | ===== Jurnal ===== | ||
+ | * 01/05/2024 - alegere temă proiect | ||
* 04/05/2024 - finalizarea documentației + schema bloc\\ | * 04/05/2024 - finalizarea documentației + schema bloc\\ | ||
* 07/05/2024 - testarea componentelor hardware\\ | * 07/05/2024 - testarea componentelor hardware\\ | ||
* 12/05/2024 - finalizare hardware design\\ | * 12/05/2024 - finalizare hardware design\\ | ||
+ | * 17/05/2024 - Milestone 2 (hardware) \\ | ||
+ | * 21/05/2024 - start code development \\ | ||
+ | * 24/05/2024 - Milestone 3 (software) \\ | ||
Probleme întâmpinate: | Probleme întâmpinate: | ||
- | * Alimentarea modulului LCD funcționează la tensiunea de 3.3V, iar tensiunea de funcționare a plăcii de dezvoltare este de 5V. De aceea, am încercat inițial să folosesc un translator de nivel logic. După mult timp pierdut (și un display ars :-\) nu am reușit să îl fac să funcționeze. În urma indicațiilor laborantului, am ales să introduc în circuit rezistențe de 10kΩ. | + | * Plăcuța de dezvoltare Arduino UNO R3 are doar doi pini digitali ce suportă întreruperi externe (D2, D3). Aveam nevoie să configurez 3 componente pentru a folosi întreruperi (două butoane și un joystick), dar doar doi pini disponibili. Am folosit două diode pentru a multiplexa butoanele pe același pin. |
+ | * Alimentarea modulului LCD funcționează la tensiunea de 3.3V, iar tensiunea de funcționare a plăcii de dezvoltare este de 5V. Am încercat inițial să folosesc un translator de nivel logic. După mult timp pierdut (și un display ars :-\) nu am reușit să îl fac să funcționeze. În urma indicațiilor laborantului, am ales să introduc în circuit rezistențe de 10kΩ. | ||
+ | * Active buzzer module pe care intenționam să îl folosesc inițial nu funcționa, l-am înlocuit cu un buzzer pasiv de 5V. | ||
===== Bibliografie/Resurse ===== | ===== Bibliografie/Resurse ===== | ||
[[https://docs.arduino.cc/resources/datasheets/A000066-datasheet.pdf|Datasheet Arduino UNO R3]]\\ | [[https://docs.arduino.cc/resources/datasheets/A000066-datasheet.pdf|Datasheet Arduino UNO R3]]\\ | ||
[[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf|Datasheet ATmega328P]]\\ | [[https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf|Datasheet ATmega328P]]\\ | ||
- | [[https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf|Datasheet ILI9341]] | + | [[https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf|Datasheet ILI9341]]\\ |
+ | [[https://github.com/adafruit/Adafruit-GFX-Library|Adafruit GFX Library]]\\ | ||
+ | [[https://github.com/robsoncouto/arduino-songs|arduino-songs]] | ||
<html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | ||