This shows you the differences between two versions of the page.
pm:prj2025:mdinica:bogdan.rusu1707 [2025/05/30 02:53] bogdan.rusu1707 [Elemente de control (9 butoane INPUT_PULLUP + întreruperi)] |
pm:prj2025:mdinica:bogdan.rusu1707 [2025/05/30 03:52] (current) bogdan.rusu1707 [Bibliografie/Resurse] |
||
---|---|---|---|
Line 103: | Line 103: | ||
| 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]] | | | 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]] | | | Celule Li-Ion 18650 3.7 V | 2 | [[https://sigmanortec.ro/baterie-lithium-18650-3-7v-2600mah|18650 Li-Ion 3.7 V]] | | ||
- | | Piezo buzzer activ | 1 | – | | + | | Buzzer pasiv | 1 | – | |
| Push-buttons tactile (momentary) | 9 | – | | | Push-buttons tactile (momentary) | 9 | – | | ||
| Fire jumper (duse-întoarse) | 10 | – | | | Fire jumper (duse-întoarse) | 10 | – | | ||
Line 120: | Line 120: | ||
+ | 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 153: | 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> | + | |