This shows you the differences between two versions of the page.
pm:prj2025:vstoica:teodora.voicu0210 [2025/05/29 20:15] teodora.voicu0210 |
pm:prj2025:vstoica:teodora.voicu0210 [2025/05/29 21:57] (current) teodora.voicu0210 [Bibliografie/Resurse] |
||
---|---|---|---|
Line 24: | Line 24: | ||
* **Software:** | * **Software:** | ||
- | * **Citire accelerometru şi detectare „shake”. | + | * Citire accelerometru şi detectare „shake”. |
- | * **Generare numere aleatorii 1–6. | + | * Generare numere aleatorii 1–6. |
- | * **Afişare mesaje şi rezultate pe OLED. | + | * Afişare mesaje şi rezultate pe OLED. |
- | * **Iniţializare SD şi redare WAV pe buzzer | + | * Iniţializare SD şi redare WAV pe buzzer |
* **Interacţiuni:** | * **Interacţiuni:** | ||
- | 1. Utilizatorul zguduie dispozitivul → MPU-6050 transmite semnale Arduino-ului. | + | 1. Dispozitivul e zguduit → accelerometrul detecteaza miscare peste SHAKE_THRESHOLD |
- | 2. Arduino detectează gestul, generează un număr aleatoriu şi îl afişează pe LCD. | + | 2. Stare SHAKING → afiseaza “Shake!” si porneste redarea DICE.WAV pe buzzer |
- | 3. În paralel, Arduino citeşte fişierul WAV de pe cardul SD şi trimite semnalul către difuzor. | + | 3. Dupa SHAKE_TIMEOUT fara miscare → opreste WAV, genereaza doua valori random (1–6) și le afiseaza pe OLED |
- | 4. La următorul gest de „shake”, ciclul se reia. | + | 4. Dupa RESULT_HOLD → revine la “READY!” și asteapta urmatorul shake |
| | ||
{{:pm:prj2025:vstoica:image_fishu.png?300x|Diagramă Arduino UNO + MPU-605}} | {{:pm:prj2025:vstoica:image_fishu.png?300x|Diagramă Arduino UNO + MPU-605}} | ||
Line 43: | Line 43: | ||
===== Hardware Design ===== | ===== Hardware Design ===== | ||
- | Components List: | + | Lista Componente: |
* Arduino:https://www.optimusdigital.ro/ro/placi-avr/2563-placa-de-dezvoltare-compatibila-cu-arduino-uno-atmega328p-i-ch340-si-cablu-50-cm.html?search_query=arduino+uno&results=129 | * Arduino:https://www.optimusdigital.ro/ro/placi-avr/2563-placa-de-dezvoltare-compatibila-cu-arduino-uno-atmega328p-i-ch340-si-cablu-50-cm.html?search_query=arduino+uno&results=129 | ||
* Breadboard:https://www.optimusdigital.ro/ro/prototipare-breadboard-uri/13245-breadboard-750-puncte.html?search_query=breadboard&results=126 | * Breadboard:https://www.optimusdigital.ro/ro/prototipare-breadboard-uri/13245-breadboard-750-puncte.html?search_query=breadboard&results=126 | ||
Line 53: | Line 53: | ||
Functional Overview: | Functional Overview: | ||
- | * When you shake the LIS2DH12 accelerometer, it detects the motion and triggers the Arduino to generate a random number from 1 to 6. That number is drawn on the SSD1306 OLED display, while simultaneously the Arduino plays a “dice-roll” WAV file from the microSD card through the passive buzzer. | + | * Când este zguduit accelerometrul LIS2DH12, acesta detectează mișcarea și declanșează Arduino-ul să genereze doua numere aleatoare de la 1 la 6. Aceste numere sunt afisate pe ecranul OLED SSD1306, în timp ce, simultan, Arduino-ul redă un fișier WAV cu sunet de zaruri de pe cardul microSD prin buzzerul pasiv. |
{{:pm:prj2025:vstoica:digital_dice_electrical.png?800x|Circuit}} | {{:pm:prj2025:vstoica:digital_dice_electrical.png?800x|Circuit}} | ||
+ | |||
+ | |||
+ | |||
+ | * **OLED SSD1306 (I²C)** | ||
+ | * 3.3 V → VCC | ||
+ | Sursa de alimentare a circuitului intern şi a driver-ului display-ului. | ||
+ | * GND → GND | ||
+ | Reţeaua de masă comună. | ||
+ | * A4 → SDA | ||
+ | Linia de date I²C: aici circulă octeţi de la Arduino către pixelii OLED-ului. | ||
+ | * A5 → SCL | ||
+ | Linia de ceas I²C: sincronizează transferul de date pe SDA. | ||
+ | |||
+ | De ce OLED? | ||
+ | – Afișează mesaje şi rezultatul zarurilor într-un format grafic compact, cu consum redus de energie. | ||
+ | |||
+ | |||
+ | * **Modul SD-card (SPI)** | ||
+ | * 5 V → VCC | ||
+ | Alimentează convertorul de nivel şi interfaţa SPI. | ||
+ | * GND → GND | ||
+ | Referinţa de masă pentru comunicaţia SPI. | ||
+ | * D10 → CS (Chip Select) | ||
+ | Selectează modulul SD pe magistrala SPI (când e LOW, modulul răspunde). | ||
+ | * D11 → MOSI (Master Out Slave In) | ||
+ | Trimite datele din Arduino spre SD (de exemplu, comenzi de citire). | ||
+ | * D12 → MISO (Master In Slave Out) | ||
+ | Primeşte datele de la SD spre Arduino (conţinutul fişierului WAV). | ||
+ | * D13 → SCK (Serial Clock) | ||
+ | Ceasul pentru sincronizarea transferului de biţi MOSI/MISO. | ||
+ | |||
+ | De ce SD-card? | ||
+ | – Permite stocarea fişierului WAV de sunet de zaruri, fără să încarce memoria internă a plăcii. | ||
+ | |||
+ | |||
+ | * **Buzzer pasiv** | ||
+ | * D6 (PWM) → S | ||
+ | Pinul PWM generează semnalul audio propriu-zis (tonuri variabile conform valorilor citite din WAV). | ||
+ | * 5 V → + | ||
+ | Redă amplitudinea semnalului PWM către buzzer. | ||
+ | * GND → – | ||
+ | Întoarcerea curentului şi referinţa de masă. | ||
+ | |||
+ | Ce face PWM? | ||
+ | – Pulse Width Modulation modulează lăţimea impulsurilor pentru a crea frecvenţe audio perceptibile ca sunet. | ||
+ | |||
+ | |||
+ | * **Modul LIS2DH12 (I²C)** | ||
+ | * 3.3 V → VCC | ||
+ | Alimentează senzorul cu tensiune stabilă de 3.3 V. | ||
+ | * GND → GND | ||
+ | Stabilirea referinţei zero pentru măsurări. | ||
+ | * A4 → SDA | ||
+ | Linia de date I²C: transmite valorile brute de acceleraţie. | ||
+ | * A5 → SCL | ||
+ | Linia de ceas I²C pentru sincronizarea transferului de date. | ||
+ | * 5 V → SDO/SA0 | ||
+ | Configurează adresa I²C la 0x19 (pull-up intern), astfel evitând conflicte pe bus. | ||
+ | * (neconectat) → CS | ||
+ | CS rămâne HIGH; senzorul rămâne mereu activ pe I²C. | ||
+ | |||
+ | De ce accelerometru LIS2DH12? | ||
+ | – Detectează gestul de „shake” cu precizie, fără butoane suplimentare, şi are consum redus. | ||
+ | |||
===== Software Design ===== | ===== Software Design ===== | ||
+ | <code> | ||
+ | /* | ||
+ | * DIGITAL DICE - Arduino UNO | ||
+ | * — Shake → pornește DICE.WAV pe pin 9 | ||
+ | * — Stop Shake → afișează două numere pe OLED | ||
+ | * | ||
+ | * HARDWARE: | ||
+ | * LIS2DH12 (I²C) | SDA/SCL = A4/A5 | ||
+ | * SSD1306 OLED 128×64 | SDA/SCL = A4/A5 | ||
+ | * Micro-SD (SPI) | CS = 10 | ||
+ | * Buzzer pasiv | pin 9 (Timer1 PWM) | ||
+ | */ | ||
- | <note tip> | + | #include <Wire.h> // permite comunicarea I2C |
- | Descrierea codului aplicaţiei (firmware): | + | #include "SparkFun_LIS2DH12.h" // driverul pentru accelerometru |
- | * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) | + | #include <SPI.h> // pentru SD (comunicarea SPI) |
- | * librării şi surse 3rd-party (e.g. Procyon AVRlib) | + | #include <SD.h> // pt citire/scrie fisiere pe cardul SD |
- | * algoritmi şi structuri pe care plănuiţi să le implementaţi | + | #include <TMRpcm.h> // redarea fisierelor WAV mono printr-un PWM pe buzzer |
- | * (etapa 3) surse şi funcţii implementate | + | #include <U8g2lib.h> // desene pe OLED |
- | </note> | + | |
- | ===== Rezultate Obţinute ===== | + | #define SD_CS_PIN 10 // chip select pt modulul SD |
+ | #define SPEAKER_PIN 9 // buzzerul pasiv conectat pe pinul 9 (pwm timer) | ||
- | <note tip> | + | #define SHAKE_THRESHOLD 2000 // daca diferenta de citiri depaseste pragul e considerat shake |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | #define SHAKE_TIMEOUT 300 // ms fără miscare = aruncare terminata |
- | </note> | + | #define RESULT_HOLD 1500 // ms pastram rez pe ecran inainte sa schimbam iar la Ready |
- | ===== Concluzii ===== | + | const char WAV_NAME[] = "DICE.WAV"; |
- | ===== Download ===== | + | SPARKFUN_LIS2DH12 accel; // cream accelerometrul |
+ | TMRpcm audio; // playerul care genereaza pwm ul pt a reda fisierul wav pe buzzer | ||
+ | U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // obiectul care controleaza ecranul | ||
- | <note warning> | + | enum class Stare : uint8_t { GATA, SHAKING, REZULTAT }; // logicile posibile |
- | 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ă ;-). | + | Stare stareCurenta = Stare::GATA; // starea de start |
- | 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**. | + | unsigned long tStartStare; // mom cand s-a schimbat ultima data starea |
- | </note> | + | int16_t lastX, lastY, lastZ; // valorile de pe fiecare axa a accelerometrului |
- | ===== Jurnal ===== | ||
- | <note tip> | + | // primeste un sir si un font, si scrie acel text centrat orizontal la linia y pe ecran |
- | Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. | + | void drawCentered(const char* text, uint8_t y, const uint8_t* font) { |
- | </note> | + | u8g2.setFont(font); // font select |
+ | int w = u8g2.getStrWidth(text); // latime txt | ||
+ | u8g2.firstPage(); do { u8g2.drawStr((128 - w) / 2, y, text); } while (u8g2.nextPage()); // plaseaza incep in centrul ecranului | ||
+ | } | ||
+ | |||
+ | void setup() { | ||
+ | // Serial.begin(9600); // pt debug | ||
+ | if (!accel.begin()) while (1); // start accelerometru si se blocheaza daca lipseste | ||
+ | u8g2.begin(); // initializeaza ecranul | ||
+ | drawCentered("READY!", 32, u8g2_font_ncenB14_tr); // afis ready pt inceput | ||
+ | |||
+ | audio.speakerPin = SPEAKER_PIN; // spune playerului pe ce pin scoate semnal pwm catre buzzer | ||
+ | audio.CSPin = SD_CS_PIN; // ce pin e chipselect pt sd | ||
+ | |||
+ | if (!SD.begin(SD_CS_PIN)) while (1); // stop dacă SD fail | ||
+ | if (!SD.exists(WAV_NAME)) while (1); // stop dacă lipseste DICE.wav | ||
+ | |||
+ | audio.setVolume(5); // 0-6, 5 a fost optim | ||
+ | audio.quality(1); // pt sunet mai clar | ||
+ | |||
+ | randomSeed(analogRead(A0)); // foloseste zgomot de pe pinul A0 ca baza pt generarea numerelor aleatoare | ||
+ | lastX = accel.getRawX(); lastY = accel.getRawY(); lastZ = accel.getRawZ(); // citeste si salveaza primele valori de la accelro | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | int16_t x = accel.getRawX(), y = accel.getRawY(), z = accel.getRawZ(); // cit acceleratia pe fiec axa | ||
+ | int16_t dX = abs(x - lastX), dY = abs(y - lastY), dZ = abs(z - lastZ); // dif fata de ultima data | ||
+ | lastX = x; lastY = y; lastZ = z; // actualizare valori | ||
+ | |||
+ | switch (stareCurenta) { // algem ce stare urm in fct de starea curenta | ||
+ | |||
+ | case Stare::GATA: | ||
+ | if (dX > SHAKE_THRESHOLD || dY > SHAKE_THRESHOLD || dZ > SHAKE_THRESHOLD) { // am detectat miscarea | ||
+ | stareCurenta = Stare::SHAKING; // deci trecem in starea shaking | ||
+ | tStartStare = millis(); | ||
+ | drawCentered("Shake!", 32, u8g2_font_ncenB14_tr); // afisam shake | ||
+ | audio.play(WAV_NAME); // si redam sunetul DICE | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | case Stare::SHAKING: | ||
+ | if (dX > SHAKE_THRESHOLD || dY > SHAKE_THRESHOLD || dZ > SHAKE_THRESHOLD) { // daca ince se scturua accelreo | ||
+ | tStartStare = millis(); // resetam timeoutul | ||
+ | } | ||
+ | if (millis() - tStartStare > SHAKE_TIMEOUT) { // daca de la ultima miscare a trecut mai mult de shake timeout | ||
+ | audio.stopPlayback(); // oprim sunetul | ||
+ | uint8_t d1 = random(1,7), d2 = random(1,7); // afisam 2 nre random | ||
+ | char buf[6]; snprintf(buf, sizeof(buf), "%d %d", d1, d2); | ||
+ | drawCentered(buf, 50, u8g2_font_logisoso32_tn); | ||
+ | |||
+ | stareCurenta = Stare::REZULTAT; // trecem la starea de result | ||
+ | tStartStare = millis(); | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | case Stare::REZULTAT: | ||
+ | if (millis() - tStartStare > RESULT_HOLD) { // daca a trecut timpul de cat tb tinut rez pe ecran | ||
+ | drawCentered("READY!", 32, u8g2_font_ncenB14_tr); // afisam din nou starea de ready pt urmatoare miscare si | ||
+ | stareCurenta = Stare::GATA; // actualizam si starea | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | delay(5); // pauza pt CPU | ||
+ | } | ||
+ | </code> | ||
+ | ==== Biblioteci externe utilizate ==== | ||
+ | * ‘‘Wire.h’’ | ||
+ | comunicare I²C cu accelerometrul şi OLED | ||
+ | * ‘‘SparkFun_LIS2DH12.h’’ | ||
+ | driver pentru citirea acceleraţiilor de la senzorul ‘‘LIS2DH12’’ | ||
+ | * ‘‘SPI.h’’ | ||
+ | suport hardware ‘‘SPI’’ pentru modulul SD | ||
+ | * ‘‘SD.h’’ | ||
+ | acces la sistemul de fişiere ‘‘FAT’’ de pe cardul micro-SD | ||
+ | * ‘‘TMRpcm.h’’ | ||
+ | redare fişiere ‘‘WAV’’ mono prin ‘‘PWM’’ (Timer1) pe buzzerul pasiv | ||
+ | * ‘‘U8g2lib.h’’ | ||
+ | comandă şi desen pe ‘‘OLED SSD1306’’ 128×64 | ||
+ | |||
+ | ==== Componente ale codului ==== | ||
+ | Codul este împărţit în mai multe componente: | ||
+ | * interfaţare cu hardware-ul, acoperind: | ||
+ | iniţializare şi citire continuă a accelerometrului ‘‘LIS2DH12’’ | ||
+ | * control ‘‘SPI/SD’’ pentru verificarea şi deschiderea fişierului ‘‘DICE.WAV’’ | ||
+ | * generare ‘‘PWM’’ audio pe pinul buzzer-ului | ||
+ | * control ‘‘I²C’’ pentru desenul pe OLED | ||
+ | * State machine, ce include: | ||
+ | |||
+ | ‘‘GATA’’ – aşteaptă un shake şi afişează “READY!” | ||
+ | ‘‘SHAKING’’ – redă sunetul şi afişează “Shake!” cât timp mişcarea continuă | ||
+ | ‘‘REZULTAT’’ – generează două valori aleatorii, le afişează pe OLED, apoi revine la ‘‘GATA’’ | ||
+ | |||
+ | * funcţii auxiliare: | ||
+ | |||
+ | ‘‘randomSeed(analogRead(A0))’’ pentru entropie la pornire | ||
+ | ‘‘random(1,7)’’ pentru fiecare zar | ||
+ | ‘‘drawCentered(text, y, font)’’ – calculează lăţimea textului şi îl plasează centrat | ||
+ | |||
+ | ==== Fluxul aplicaţiei ==== | ||
+ | -> La pornire, ‘‘setup()’’ iniţializează senzorul, OLED-ul, SD-ul, audio şi RNG-ul, apoi pe ecran apare “READY!”. | ||
+ | |||
+ | -> În ‘‘loop()’’ se citesc acceleraţiile şi se calculează delta faţă de ultima citire. Dacă ‘‘delta > SHAKE_THRESHOLD’’, starea trece în ‘‘SHAKING’’. | ||
+ | |||
+ | -> În ‘‘SHAKING’’ se porneşte ‘‘audio.play(“DICE.WAV”)’’ şi se afişează “Shake!”. La fiecare citire de mişcare, timer-ul este resetat. | ||
+ | |||
+ | -> După ‘‘SHAKE_TIMEOUT’’ ms fără mişcare, ‘‘audio.stopPlayback()’’. Se generează două numere (1–6) şi se afişează cu font mare; starea devine ‘‘REZULTAT’’. | ||
+ | |||
+ | -> După ‘‘RESULT_HOLD’’ ms, ecranul revine la “READY!” iar starea revine în ‘‘GATA’’, aşteptând un nou shake. | ||
+ | |||
+ | ==== Detalii de implementare ==== | ||
+ | -> Praguri configurabile: | ||
+ | * ‘‘SHAKE_THRESHOLD = 2000’’ – sensibilitate la mişcare | ||
+ | * ‘‘SHAKE_TIMEOUT = 300 ms’’ – interval fără mişcare înainte de oprire | ||
+ | * ‘‘RESULT_HOLD = 1500 ms’’ – cât timp rămâne afişat rezultatul | ||
+ | |||
+ | -> Audio: | ||
+ | * ‘‘audio.setVolume(5)’’ – volum optim fără distorsiuni | ||
+ | * ‘‘audio.quality(1)’’ – oversampling 2× pentru claritate | ||
+ | |||
+ | -> Desen pe OLED: | ||
+ | * re-desenările sunt minimizate – textul este redesenat doar la tranziţii de stare | ||
+ | |||
+ | -> Random seed: | ||
+ | * folosirea unui pin analog “flotant” pentru a evita secvenţe pseudo-aleatoare repetitive | ||
+ | |||
+ | ==== Optimizări ==== | ||
+ | * Maşina de stări izolează logica de desen şi audio pe blocuri distincte, eliminând ‘‘redraw’’-uri inutile | ||
+ | * Actualizare ‘‘I²C’’ minimală – apeluri ‘‘drawCentered()’’ doar la tranziţii de stare | ||
+ | * Sincronizare audio–I²C – ‘‘audio.stopPlayback()’’ este apelat înainte de ‘‘drawCentered()’’ pentru a evita blocaje pe magistrala comună | ||
+ | * Delay mic – ‘‘delay(5)’’ menţine CPU-ul liber pentru ISR-ul audio şi reduce consumul inutil | ||
+ | |||
+ | |||
+ | ===== Used labs ===== | ||
+ | |||
+ | Lab0: GPIO | ||
+ | * controlul pinilor digitali: | ||
+ | * D9 – ieșire PWM către buzzer | ||
+ | * D10 – Chip Select pentru modulul SD | ||
+ | * LED-uri/Serial (opțional) pentru depanare | ||
+ | |||
+ | Lab3: Timere & PWM | ||
+ | * biblioteca TMRpcm folosește Timer1 în modul PWM pentru a genera semnalul audio necesar redării fișierului WAV pe buzzerul pasiv. | ||
+ | |||
+ | Lab5: SPI | ||
+ | * protocolul SPI asigură comunicația cu cardul micro-SD: | ||
+ | * D11 → MOSI, D12 → MISO, D13 → SCK, D10 → CS | ||
+ | * biblioteca SD.h gestionează sistemul de fișiere FAT și citirea fișierului DICE.WAV. | ||
+ | |||
+ | Lab6: I²C (TWI) | ||
+ | * magistrala I²C este partajată de: | ||
+ | * LIS2DH12 – trimite datele brute de accelerație (detectarea shake-ului) | ||
+ | * SSD1306 OLED – primește comenzile de desen (mesajele și rezultatul zarurilor) | ||
+ | * linii comune: A4 → SDA, A5 → SCL. | ||
+ | |||
+ | Lab1: USART | ||
+ | * Serial.begin(9600) este prezent pentru diagnostic; când este decommentat, permite trimiterea de mesaje de debug în Serial Monitor. | ||
+ | |||
+ | |||
+ | ===== Rezultate Obţinute ===== | ||
+ | |||
+ | [[https://github.com/teodora-voicu/Digital_Dice|GitHub Repository]] | ||
+ | |||
+ | [[https://www.youtube.com/watch?v=ZkLngqv25lI|Demo Video]] | ||
+ | |||
+ | {{:pm:prj2025:vstoica:IMG_1878.png?300x|Shake}} | ||
+ | |||
+ | {{:pm:prj2025:vstoica:IMG_1880.png?300x|dice_res}} | ||
+ | ===== Concluzii ===== | ||
+ | |||
+ | Acest proiect a reprezentat o ocazie excelentă de a vedea în practică conceptele teoretice şi de a le pune în aplicare pentru a crea ceva distractiv. | ||
===== Bibliografie/Resurse ===== | ===== Bibliografie/Resurse ===== | ||
- | <note> | + | [[https://www.cirkitstudio.com/|Cirkit Studio]] |
- | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | |
- | </note> | + | [[https://www.arduino.cc/|Pagina oficială Arduino]] |
+ | |||
+ | [[https://learn.adafruit.com/|Adafruit Learning System]] | ||
<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> | ||