This shows you the differences between two versions of the page.
pm:prj2025:mdinica:bogdan.rusu1707 [2025/05/18 03:49] bogdan.rusu1707 |
pm:prj2025:mdinica:bogdan.rusu1707 [2025/05/30 03:52] (current) bogdan.rusu1707 [Bibliografie/Resurse] |
||
---|---|---|---|
Line 20: | Line 20: | ||
===== Hardware Design ===== | ===== Hardware Design ===== | ||
+ | {{ :pm:prj2025:mdinica:ca:rusu_bogdan:schema_bogdan_pm_bb.png?300 |}} | ||
+ | ===== Placa de dezvoltare ESP32 ====== | ||
+ | <note tip> | ||
+ | Este “creierul” consolei: un microcontroller dual-core Tensilica LX6 la 240 MHz, cu 520 KB SRAM și Wi-Fi/Bluetooth integrate. Primește alimentare prin pinul VIN (5 V) sau prin USB, iar regulatorul onboard îi trimite stabil 3,3 V la nucleu. Toate perifericele (SPI, ADC, GPIO, PWM, Deep-Sleep) sunt gestionate de ESP32. | ||
+ | </note> | ||
+ | ===== TFT 2.2″ ILI9341 cu microSD ===== | ||
<note tip> | <note tip> | ||
- | Lista de piese: | + | Un display color 320×240 px care comunică prin SPI. Pe aceeași magistrală împarte datele între ecran și cardul microSD, având două CS-uri separate. Backlight-ul are un pin marcat “BL” cu “PWM SAFE” – silkscreen-ul indică faptul că placa conține intern tranzistor și rezistență de limitare, astfel încât poți aplica direct un semnal PWM din ESP32 pentru reglaj de luminozitate. |
- | * [[https://www.optimusdigital.ro/ro/placi-cu-bluetooth/4371-placa-de-dezvoltare-esp32-cu-wifi-i-bluetooth-42.html?search_query=esp32&results=28|ESP32]] | + | |
- | * [[https://www.optimusdigital.ro/ro/optoelectronice-lcd-uri/3164-display-lcd-tft-320x240-de-22-cu-slot-microsd.html?search_query=Display+LCD+TFT+320x240+de+2.2%27%27+cu+Slot+MicroSD&results=1|Display LCD TFT 320x240 2.2'']] | + | |
- | * [[https://www.optimusdigital.ro/en/3-v-step-up-power-supplies/12537-dc-dc-18v-5v-to-33v-booster-and-buck-power-modules.html?search_query=power+supply&results=1196|DC-DC 1.5-5V to 3.3V]] | + | |
- | * [[https://www.optimusdigital.ro/en/chargers/7534-incarcator-tp4056-cu-micro-usb-pt-baterie-lipo-1a-cu-protectie-pentru-circuite.html?search_query=tp4056&results=4|TP4056 charger]] | + | |
- | * [[https://www.emag.ro/card-de-memorie-maxell-micro-sdhc-4gb-class-10-ml-sdmicro-4gb-class10/pd/DVYNWQBBM/?utm_source=mobile%20app&utm_medium=ios&utm_campaign=share%20product|Micro SD card 4GB]] | + | |
- | * [[https://www.optimusdigital.ro/en/battery-holders/941-2x18650-battery-case.html?search_query=18650&results=80|Battery Case 2x18650]] | + | |
- | * | + | |
- | * Push buttons | + | |
- | * Fire | + | |
- | Aici puneţi tot ce ţine de hardware design: | + | |
- | * listă de piese | + | |
- | * scheme electrice (se pot lua şi de pe Internet şi din datasheet-uri, e.g. http://www.captain.at/electronic-atmega16-mmc-schematic.png) | + | |
- | * diagrame de semnal | + | |
- | * rezultatele simulării | + | |
</note> | </note> | ||
+ | ^ Modul Pin ^ ESP32 Pin ^ Protocol ^ Funcție ^ | ||
+ | | VCC | 3V3 | Power | Alimentare 3.3 V | | ||
+ | | GND | GND | Power | Masă comună | | ||
+ | | SCK | GPIO18 | SPI_CLK | Ceas SPI | | ||
+ | | MISO | GPIO19 | SPI_MISO | Date SPI din SD | | ||
+ | | MOSI | GPIO23 | SPI_MOSI | Date SPI către TFT/SD | | ||
+ | | CS | GPIO5 | SPI_CS | Chip-select pentru TFT | | ||
+ | | DC | GPIO2 | GPIO/SPI | Data/Command TFT | | ||
+ | | RST | GPIO16 | GPIO | Reset hardware TFT | | ||
+ | | SDCS | GPIO4 | SPI_CS | Chip-select pentru microSD | | ||
+ | | BL | GPIO15 | PWM | Reglaj backlight (PWM SAFE) | | ||
+ | |||
+ | ===== Card microSD ===== | ||
+ | <note tip> | ||
+ | Se introduce direct în slotul modulului TFT. Servește la stocarea high-score-urilor, configurațiilor și eventual a altor asset-uri (hărţi de nivel, fonturi). Accesul se face cu biblioteca FatFS prin API-ul SD.begin(SD_CS) și operaţiuni standard SD.open() | ||
+ | </note> | ||
+ | |||
+ | ===== Elemente de control (9 butoane INPUT_PULLUP + întreruperi) ===== | ||
+ | <note tip> | ||
+ | Butoane (9×, INPUT_PULLUP + întreruperi) | ||
+ | |||
+ | * 4× direcţionale (D-pad) pentru navigare în joc. | ||
+ | |||
+ | * 2× A/B pentru acţiuni principale şi secundare. | ||
+ | |||
+ | * Start/Select pentru control de meniu și pauză. | ||
+ | |||
+ | * Power pentru deep-sleep/wake. | ||
+ | |||
+ | * Fiecare e configurat ca pinMode(..., INPUT_PULLUP) și declanșează ISR pe front FALLING, asigurând reacţie instantă fără polling. | ||
+ | </note> | ||
+ | ^ Funcție ^ GPIO Pin ^ Config ^ Interrupție ^ | ||
+ | | D-pad Sus | GPIO32 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | D-pad Jos | GPIO33 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | D-pad Stânga | GPIO25 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | D-pad Dreapta | GPIO26 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | Buton A | GPIO27 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | Buton B | GPIO14 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | Sound| GPIO21 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | Menu| GPIO22 | INPUT_PULLUP | FALLING (apăsare) | | ||
+ | | Power | GPIO12 | INPUT_PULLUP + WAKE | FALLING (deep-sleep wake) | | ||
+ | |||
+ | ===== Monitorizare nivel baterie ===== | ||
+ | <note tip> | ||
+ | Două rezistoare (100kΩ/100 kΩ) formează un divizor care aduce maxim 4,2 V de la BAT+ la ~2,1 V, sigur pentru ADC-ul ESP32. Se conecteaza punctul de măsură la GPIO35 (ADC1_CH7) cu atenuare de 11 dB și măsori nivelul bateriei în cod, transformând valoarea ADC invers la tensiunea reală a pachetului. | ||
+ | </note> | ||
+ | ^ Divizor node ^ ESP32 Pin ^ Protocol ^ Descriere ^ | ||
+ | | Între R1 și R2 | GPIO35 | ADC1_CH7 (ADC_11db) | Măsurare tensiune baterie (factor 2×) | | ||
+ | |||
+ | ===== Alimentare și încărcare baterie ===== | ||
+ | <note tip> | ||
+ | Două celule Li-Ion Samsung 25R (3,7 V nominal, 2 500 mAh fiecare) montate paralel într-un holder “go-bare”. În paralel se obtin ~5 000 mAh și tensiune constantă de 3,7 V, cu curent disponibil de zeci de amperi pentru perioade scurte. | ||
+ | |||
+ | Încărcător CC/CV pentru o singură celulă Li-Ion, alimentat la 5 V (micro-USB sau boost). Conține circuit de protecție la supraîncărcare, scurt-circuit și sub-tensiune. Pinii B+/B– se conectează la baterii, iar OUT+/OUT– livrează tensiunea protejată către consolă. | ||
+ | </note> | ||
+ | |||
+ | * TP4056 VIN (+) → 5 V de la boost/USB | ||
+ | |||
+ | * TP4056 GND (–) → GND comun | ||
+ | |||
+ | * TP4056 B+ / B– → suportul 2×18650 (celule în paralel) | ||
+ | |||
+ | * TP4056 OUT+ / OUT– → rail de alimentare (spre VIN al ESP32) | ||
+ | ===== Bill of materials ===== | ||
+ | <note tip> | ||
+ | ^ Nume piesă ^ Cantitate ^ Link ^ | ||
+ | | Placă de dezvoltare ESP32 cu WiFi & Bluetooth 4.2 | 1 | [[https://www.optimusdigital.ro/ro/placi-cu-bluetooth/4371-placa-de-dezvoltare-esp32-cu-wifi-i-bluetooth-42.html?search_query=esp32&results=28|ESP32]] | | ||
+ | | Display LCD TFT 320×240 2.2″ cu slot microSD | 1 | [[https://www.optimusdigital.ro/ro/optoelectronice-lcd-uri/3164-display-lcd-tft-320x240-de-22-cu-slot-microsd.html?search_query=Display+LCD+TFT+320x240+de+2.2%27%27+cu+Slot+MicroSD&results=1|Display TFT 2.2″]] | | ||
+ | | Modul DC-DC 1.5–5 V → 3.3 V | 1 | [[https://www.optimusdigital.ro/en/3-v-step-up-power-supplies/12537-dc-dc-18v-5v-to-33v-booster-and-buck-power-modules.html?search_query=power+supply&results=1196|DC-DC 1.5–5 V→3.3 V]] | | ||
+ | | Modul încărcător TP4056 LiPo 1 A cu protecție | 1 | [[https://www.optimusdigital.ro/en/chargers/7534-incarcator-tp4056-cu-micro-usb-pt-baterie-lipo-1a-cu-protectie-pentru-circuite.html?search_query=tp4056&results=4|TP4056 charger]] | | ||
+ | | Card de memorie MicroSDHC 4 GB, Class 10 | 1 | [[https://www.emag.ro/card-de-memorie-maxell-micro-sdhc-4gb-class-10-ml-sdmicro-4gb-class10/pd/DVYNWQBBM/?utm_source=mobile%20app&utm_medium=ios&utm_campaign=share%20product|MicroSD card 4 GB]] | | ||
+ | | Suport baterii 2×18650 | 1 | [[https://www.optimusdigital.ro/en/battery-holders/941-2x18650-battery-case.html?search_query=18650&results=80|Battery holder 2×18650]] | | ||
+ | | Celule Li-Ion 18650 3.7 V | 2 | [[https://sigmanortec.ro/baterie-lithium-18650-3-7v-2600mah|18650 Li-Ion 3.7 V]] | | ||
+ | | Buzzer pasiv | 1 | – | | ||
+ | | Push-buttons tactile (momentary) | 9 | – | | ||
+ | | Fire jumper (duse-întoarse) | 10 | – | | ||
+ | | Rezistoare 100 kΩ | 2 | – | | ||
+ | </note> | ||
+ | ===== Proof of concept ===== | ||
+ | {{ :pm:prj2025:mdinica:ca:rusu_bogdan:power.jpg?300 |}} | ||
+ | {{ :pm:prj2025:mdinica:ca:rusu_bogdan:sdok.jpg?300 |}} | ||
+ | {{ :pm:prj2025:mdinica:ca:rusu_bogdan:baterie.jpg?300 |}} | ||
===== Software Design ===== | ===== Software Design ===== | ||
+ | Link proiect Github: https://github.com/Bogdan-Rusu17/Retro_Games_Console | ||
+ | |||
+ | Link video cu demo: https://youtu.be/d9HI2PYjIhI | ||
+ | |||
+ | |||
+ | Cateva fragmente de cod interesante: | ||
+ | ===== Cum se reprezinta piesele de tetris? ===== | ||
<note tip> | <note tip> | ||
- | Descrierea codului aplicaţiei (firmware): | + | |
- | * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) | + | |
- | * librării şi surse 3rd-party (e.g. Procyon AVRlib) | + | <code cpp> |
- | * algoritmi şi structuri pe care plănuiţi să le implementaţi | + | |
- | * (etapa 3) surse şi funcţii implementate | + | const int8_t shapes[7][4][4][2] = { |
+ | // I-piece | ||
+ | { // 0° 90° 180° 270° | ||
+ | {{-2,0},{-1,0},{0,0},{1,0}}, //orizontal | ||
+ | {{0,-2},{0,-1},{0,0},{0,1}}, // vertical | ||
+ | {{-2,-1},{-1,-1},{0,-1},{1,-1}},// orizontal | ||
+ | {{-1,-2},{-1,-1},{-1,0},{-1,1}} // vertical | ||
+ | }, | ||
+ | //... | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | * formele in coordonate carteziene pentru piesele de tetris | ||
+ | * se porneste de la o forma fixa pentru fiecare piesa | ||
+ | * si cel mai simplu mod de a obtine coordonatele pentru o rotatie | ||
+ | * e sa inmultim cu matricea de rotatie 90 de grade: | ||
+ | { | ||
+ | {cos(pi / 2), sin(pi / 2)}, | ||
+ | {cos(pi / 2), -sin(pi / 2)} | ||
+ | } | ||
</note> | </note> | ||
+ | ===== Intreruperi pe butoane ===== | ||
+ | <note tip> | ||
- | ===== Rezultate Obţinute ===== | + | <code cpp> |
+ | void IRAM_ATTR onBtn(volatile uint32_t &lastTime, uint32_t debounce, volatile bool &flag) { | ||
+ | uint32_t now = micros(); | ||
+ | if (now - lastTime > debounce) flag = true; | ||
+ | lastTime = now; | ||
+ | } | ||
+ | </code> | ||
+ | * helper de ISR pt butoane ca sa nu am cod duplicat | ||
+ | * verific la debounce sa fi trecut un numar de secunde ca sa iau apasarea in considerare | ||
+ | |||
+ | |||
+ | <code cpp> | ||
+ | void IRAM_ATTR onUp() { | ||
+ | if (state == TETRIS) { | ||
+ | onBtn(lastUp, DEB_SOUND, btnUpFlag); | ||
+ | } else if (state == SNAKE) { | ||
+ | onBtn(lastUp, DEB_FAST, btnUpFlag); | ||
+ | } | ||
+ | |||
+ | onBtn(lastUp, DEB_SOUND, btnUpFlag); | ||
+ | } | ||
+ | |||
+ | // alte butoane | ||
+ | </code> | ||
+ | |||
+ | * interuperi pentru butoane cu rate custom de debounce dependent de status consola | ||
+ | * de exemplu la butonul UP cand suntem in jocul de tetris cu el rotim piesa si nu | ||
+ | * vrem sa se roteasca foarte repede ca sa controlam precizia | ||
+ | * cand suntem pe meniu vrem cam tot acelasi debounce rate | ||
+ | * dar cand suntem pe snake vrem sa avem rapiditate | ||
+ | </note> | ||
+ | |||
+ | ===== PWM pentru controlul backlight ecran ===== | ||
<note tip> | <note tip> | ||
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | |
+ | <code cpp> | ||
+ | pinMode(TFT_BL, OUTPUT); | ||
+ | analogWrite(TFT_BL, brightness); | ||
+ | |||
+ | ledcAttachChannel(BUZZER_PIN, 2000, 8, 2); | ||
+ | ledcWriteTone(BUZZER_PIN, 0); | ||
+ | //... | ||
+ | |||
+ | </code> | ||
+ | * initializez PWM-ul pe pinul capabil PWM TFT_BL pe canalul 0 pe care si-l ia implicit | ||
+ | * initializez buzzer ul pe canalul 2 de PWM ca sa nu intre in conflict cu backlight-ul | ||
+ | |||
+ | <code cpp> | ||
+ | if (digitalRead(BTN_A)==LOW && now - lastBright > BRIGHT_DEBOUNCE_MS) { | ||
+ | brightness = min(brightness + 16, 255); | ||
+ | analogWrite(TFT_BL, brightness); | ||
+ | lastBright = now; | ||
+ | } | ||
+ | if (digitalRead(BTN_B)==LOW && now - lastBright > BRIGHT_DEBOUNCE_MS) { | ||
+ | brightness = max(brightness - 16, 0); | ||
+ | analogWrite(TFT_BL, brightness); | ||
+ | lastBright = now; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Prin functia `analogWrite` cresc sau descresc factorul de umplere ca sa maresc/micsorez luminozitatea ecranului in termeni discreti pana la rezolutia maxima a timer-ului 0 pe care se bazeaza acest PWM. | ||
</note> | </note> | ||
- | ===== Concluzii ===== | + | ===== SPI pentru comunicatie eficienta prin API-ul ecranului ===== |
+ | <note tip> | ||
+ | <code cpp> | ||
+ | #define TFT_DC 2 | ||
+ | #define TFT_RST -1 // pus la 3v3 | ||
+ | #define TFT_BL 15 // pwm pt luminozitate ecran | ||
+ | #define SD_CS 4 // select la card | ||
- | ===== Download ===== | + | // instantiaza obiectul tft cu care am acces la functiile ecranului |
+ | Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST); | ||
+ | /* {...} */ | ||
+ | SPI.begin(18, 19, 23); | ||
+ | tft.begin(); | ||
+ | tft.setRotation(0); | ||
+ | </code> | ||
+ | * initializam liniile protocolului SPI specificand in ordine SCLK, MISO si MOSI | ||
+ | * setam ecranul sa functioneze in regimul de rotatie obisnuita adica cu verticala mai lunga decat orizontala | ||
+ | </note> | ||
- | <note warning> | + | ===== Cum folosesc ADC pentru a determina nivelul bateriei? ===== |
- | 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ă ;-). | + | <note tip> |
- | 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**. | + | <code cpp> |
+ | analogReadResolution(12); | ||
+ | analogSetAttenuation(ADC_11db); | ||
+ | pinMode(BAT_ADC_PIN, INPUT); | ||
+ | </code> | ||
+ | * ADC pentru baterie, 12 biti rezolutie, 11 db pt zgomot atenuare | ||
+ | |||
+ | <code cpp> | ||
+ | void drawBattery() { | ||
+ | // updateaza bateria doar odata la 1s ca sa nu fie flicker | ||
+ | int now = millis(); | ||
+ | if (now - lastBatUpdate < 1000) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | lastBatUpdate = now; | ||
+ | |||
+ | int raw = analogRead(BAT_ADC_PIN); | ||
+ | float m = (raw / 4095.0f) * 3.3f, v = m * 2.0f * BAT_CAL_FACTOR; | ||
+ | int pct = constrain(int((v - BAT_EMPTY_VOLTAGE) | ||
+ | / (BAT_FULL_VOLTAGE - BAT_EMPTY_VOLTAGE) * 100 + 0.5), 0, 100); | ||
+ | tft.fillRect(0, 0, tft.width(), 20, ILI9341_BLACK); | ||
+ | tft.setCursor(2,2); | ||
+ | tft.setTextSize(2); | ||
+ | tft.setTextColor(ILI9341_WHITE); | ||
+ | tft.print(v,2); | ||
+ | tft.print("V"); | ||
+ | tft.setCursor(tft.width()-50, 2); | ||
+ | tft.print(pct); | ||
+ | tft.print("%"); | ||
+ | } | ||
+ | </code> | ||
+ | * citeste valoarea pe 12 biti de pe pinul de ADC | ||
+ | * obtinem tensiunea la pinul ADC inmultind cu valoarea de referinta | ||
+ | * apoi obtinem valoarea reala a tensiunii din BAT+ a TP4056 inmultind cu 2 | ||
+ | * pt ca avem divizor de tensiune cu 2 rezistenta egale | ||
+ | * calculam procentul de baterie rotunjit la cel mai apropiat int | ||
</note> | </note> | ||
+ | |||
+ | |||
+ | ===== Rezultate Obţinute ===== | ||
+ | |||
+ | <note tip> | ||
+ | [[https://youtube.com/shorts/nCQ47WgPAMU?si=CRBGvuyvwzp_i7NO | Link varianta finala]] | ||
+ | </note> | ||
+ | |||
+ | ===== Concluzii ===== | ||
+ | |||
+ | Per total a fost un proiect destul de interesant de realizat in care am imbinat si cunostinte de electronica si de programare intr-un mod destul de placut si sunt destul de multumit de cum a functionat totul intr-un final. | ||
+ | |||
+ | Mi-ar fi placut in schimb sa gasesc niste fire mai bune de lipit cu care sa realizez proiectul pe perfboard intrucat ar fi aratat mult mai clean..., dar a fost interesant sa imi reamintesc cum se fac lipituri, pentru partea de baterii si la ecran (nu avea pinii pusi). | ||
===== Jurnal ===== | ===== Jurnal ===== | ||
<note tip> | <note tip> | ||
- | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | - 29 Aprilie - Alegere tema proiect |
+ | - 11 Mai - Realizare schema bloc si schema electrica in Fritzing | ||
+ | - 18 Mai - Realizarea hardware-ului in prima etapa | ||
+ | - 25 Mai - Realizarea software in prima etapa | ||
+ | - 29 Mai - Definitivarea hardware, software si a aspectului final al proiectului | ||
</note> | </note> | ||
Line 75: | Line 305: | ||
<note> | <note> | ||
- | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | [[https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf|Datasheet ESP32]] |
+ | |||
+ | [[https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html|Ledc library for PWM]] | ||
+ | |||
+ | [[https://github.com/semibran/tetromino|Inspiratie pentru reprezentarea de tetromino-uri]] | ||
+ | |||
+ | [[https://en.wikipedia.org/wiki/Tetromino|Tetromino]] | ||
+ | |||
+ | [[https://cdn-learn.adafruit.com/downloads/pdf/adafruit-gfx-graphics-library.pdf | Adafruit library for gfx]] | ||
+ | |||
+ | [[https://cdn-learn.adafruit.com/downloads/pdf/2-0-inch-320-x-240-color-ips-tft-display.pdf | Adafruit manual pentru ecran]] | ||
</note> | </note> | ||
- | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | + | |