This shows you the differences between two versions of the page.
pm:prj2024:iotelea:mihai.negru0025 [2024/05/19 23:06] mihai.negru0025 [Download] |
pm:prj2024:iotelea:mihai.negru0025 [2024/05/26 15:44] (current) mihai.negru0025 [Concluzii] |
||
---|---|---|---|
Line 110: | Line 110: | ||
===== Software Design ===== | ===== Software Design ===== | ||
+ | Pentru dezvoltarea proiectului din punct de vedere soft, s-a folosit, **ArduinoIDE**. | ||
- | <note tip> | + | === Structuri === |
- | 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) | + | |
- | * algoritmi şi structuri pe care plănuiţi să le implementaţi | + | |
- | * (etapa 3) surse şi funcţii implementate | + | |
- | </note> | + | |
- | ===== Rezultate Obţinute ===== | + | In sine notele vor fi tinute drept niste pini logici, si vom avea un macro care va face maparea dintre un port logic si unul hardware: |
- | <note tip> | + | <code c> |
- | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | /* Trasform a logic pin into real pin */ |
- | </note> | + | #define REAL_ID(pin) (pin + 11) |
- | ===== Concluzii ===== | + | /* |
+ | * @brief possible playing notes, mapped to logical pins | ||
+ | */ | ||
+ | typedef enum note_s { | ||
+ | DO = 0, | ||
+ | RE = 1, | ||
+ | MI = 3, | ||
+ | FA = 5, | ||
+ | SO = 4, | ||
+ | LA = 9, | ||
+ | SI = 2, | ||
+ | NO_NOTE = -1 | ||
+ | } note_t; | ||
+ | </code> | ||
- | ===== Download ===== | + | Totodata fiecare nota va avea un status, in sensul daca coarda corespunzatoare notei este apasata sau nu: |
+ | <code c> | ||
+ | /* | ||
+ | * @brief - status for a single note, either Active or Idle. | ||
+ | * Active when the chord is pressed, and Idle when it is not | ||
+ | */ | ||
+ | typedef enum note_status_s { | ||
+ | ACTIVE = 0, | ||
+ | IDLE = 1 | ||
+ | } ns_t; | ||
- | <note warning> | + | /* Status for every note either Active or Idle */ |
- | 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ă ;-). | + | ns_t notes_status[MAX_NOTES]; |
+ | </code> | ||
- | 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**. | + | === Flow Design === |
+ | |||
+ | Flow-ul general al programului tine de 3 pasi: | ||
+ | |||
+ | * Actualizeaza statusul notelor | ||
+ | * Canta notele active, atat timp cat exista buzzere libere | ||
+ | * Actualizeaza vectorul de memoizare | ||
+ | |||
+ | Astfel, bucla principala a programului este alcatuita de: | ||
+ | <code c> | ||
+ | /* Firstly update the status or each note */ | ||
+ | update_notes_status(); | ||
+ | |||
+ | /* Iterate through all notes and check their status */ | ||
+ | for (int i = 0; i < MAX_NOTES; ++i) { | ||
+ | if (notes_status[i] == ACTIVE) { | ||
+ | |||
+ | /* If note is active check if there is a tone available */ | ||
+ | int tone_idx = available_tone(notes[i]); | ||
+ | |||
+ | /* If a tone agrees to play the note, then play it. */ | ||
+ | if (tone_idx != -1) tones[tone_idx].play(notes_freq[i], 100); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* Update the memoization vector */ | ||
+ | update_tones_memoization(); | ||
+ | </code> | ||
+ | |||
+ | Vectorul de memoizare, este un simplu vector, care tine cont ce note sunt cantate la o actualizare de status, si in sine mimeaza functia de **isPlaying()**, pentru o structura **Tone**, am implementat aceasta structura de mana, fiindca aveam in sine nevoie de un **delay**, care foloseste si el un timer, insa cele 3 buzzere, folosesc si ele cate un timer aparte, deci pe ArduinoNano, exista doar 3 timere, si atunci pentru a nu sacrifica un buzzer, am sacrificat functia de delay. | ||
+ | |||
+ | Se folosesc in sine 3 buzzere, fiindca se doreste un flux cat mai asincron, adica daca in momentul cand sunt apasate 3 coarde, se doreste a fi cantate 3 note, insa pentru mai mult de 3, se vor canta primele 3 intrate pe **buss**. | ||
+ | |||
+ | <code c> | ||
+ | /* | ||
+ | * @brief Returns the tone that is available for playing | ||
+ | * | ||
+ | * @param note the note that wants to be played on the tone | ||
+ | * @return tone index if a tone agrees to play the note or | ||
+ | * -1 if all the tones are busy. | ||
+ | */ | ||
+ | int available_tone(note_t note) { | ||
+ | for (int i = 0; i < MAX_TONES; ++i) | ||
+ | if (buss[i] == note || buss[i] == NO_NOTE) { | ||
+ | buss[i] = note; | ||
+ | return i; | ||
+ | } | ||
+ | |||
+ | return -1; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Biblioteci folosite === | ||
+ | |||
+ | S-a folosit o singura biblioteca **ToneLibrary**, inclusa in core, care poate simula **square waves**, pentru frecvente diferite si pentru durate de timp diferit, folosind //PWM//, in sine cum am specificat si mai sus, se pot canta note asincron folosing functia **Tone::play()**, insa numarul de note cantate asincron este limitat de numarul de timere, din acest motiv vom putea canta simultan doar 3 note. | ||
+ | |||
+ | <note tip> | ||
+ | Codul intreb poate fi gasit la acest link https://github.com/mihai-negru/electric-harp/blob/master/electric-harp.ino | ||
</note> | </note> | ||
+ | |||
+ | |||
+ | ===== Concluzii ===== | ||
+ | |||
+ | A fost un proiect destul de interesant, si puternic vizual, cel mai complicat lucru a fost lipit-l, dat fiind faptul ca am dorit sa includ un grad mai inalt de estetica, astfel a fost nevoie de foarte fire, cum am mentionat si mai sus. In procesul de lipire am fost nevoit sa lipsesc niste piese de doua ori, fiindca in procesul de testare nu se comporta //as expected//. Dar la final a fost un proces destul de interesant. |