This shows you the differences between two versions of the page.
|
pm:prj2023:abirlica:music_player [2023/05/03 00:52] gabriel.orzata created |
pm:prj2023:abirlica:music_player [2023/05/25 23:12] (current) gabriel.orzata [Rezultate Obţinute] |
||
|---|---|---|---|
| Line 11: | Line 11: | ||
| <note tip> | <note tip> | ||
| - | {{ :pm:prj2023:abirlica:diagrama.png?direct&300 |}} | + | {{ :pm:prj2023:abirlica:diagrama.png?350 |}} |
| </note> | </note> | ||
| Line 18: | Line 17: | ||
| <note tip> | <note tip> | ||
| + | **Lista de piese:** | ||
| + | - Arduino UNO | ||
| + | - Led RGB | ||
| + | - Rezistente 1k | ||
| + | - Condesator | ||
| + | - Fire tata-tata | ||
| + | - Fire mama-tata | ||
| + | - Modul de card SD | ||
| + | - Card SD | ||
| + | - Difuzor | ||
| + | - Amplificator | ||
| + | - Butoane | ||
| + | - Ecran LCD | ||
| + | - Breadboard | ||
| + | - Difuzor SparkFun | ||
| + | |||
| </note> | </note> | ||
| + | |||
| + | ===== Schema cablaj ===== | ||
| + | |||
| + | |||
| + | {{ :pm:prj2023:abirlica:screenshot_from_2023-05-25_18-59-52.png?450 |}} | ||
| + | |||
| + | |||
| ===== Software Design ===== | ===== Software Design ===== | ||
| Line 24: | Line 46: | ||
| <note tip> | <note tip> | ||
| + | Bibliotecile folosite sunt: | ||
| + | - SD.h | ||
| + | - LiquidCrystal_I2C.h | ||
| + | - SPI.h | ||
| + | |||
| + | |||
| + | **Cod** | ||
| + | |||
| + | #include <LiquidCrystal_I2C.h> | ||
| + | #include "SD.h" | ||
| + | #include "SPI.h" | ||
| + | #define Rpin1 10 | ||
| + | #define Gpin1 9 | ||
| + | #define Bpin1 8 | ||
| + | #define Rpin2 14 | ||
| + | #define Gpin2 15 | ||
| + | #define Bpin2 16 | ||
| + | #define Rpin3 17 | ||
| + | #define Gpin3 18 | ||
| + | #define Bpin3 19 | ||
| + | |||
| + | uint8_t signal_values[] = {250, 240, 230, 220, 210, 200, 190, 180, 170, 160, 150, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10}; | ||
| + | // Set the LCD address to 0x27 for a 16 chars and 2 line display | ||
| + | LiquidCrystal_I2C lcd(0x27, 16, 2); | ||
| + | File myFile; | ||
| + | // change this to make the song slower or faster | ||
| + | uint16_t tempo = 110; | ||
| + | uint8_t buzzer = 7; | ||
| + | short int melody[120]; | ||
| + | uint8_t len = 0; | ||
| + | uint8_t notes; | ||
| + | volatile uint8_t song = 0, prev_song = 0; | ||
| + | unsigned long lastDebounceTime1 = 0, lastDebounceTime2 = 0, debounceDelay = 500; | ||
| + | |||
| + | |||
| + | void RGBColor(uint8_t red, uint8_t green, uint8_t blue) | ||
| + | |||
| + | analogWrite(Rpin1, red); | ||
| + | analogWrite(Gpin1, green); | ||
| + | analogWrite(Bpin1, blue); | ||
| + | |||
| + | analogWrite(Rpin2, red); | ||
| + | analogWrite(Gpin2, green); | ||
| + | analogWrite(Bpin2, blue); | ||
| + | |||
| + | analogWrite(Rpin3, red); | ||
| + | analogWrite(Gpin3, green); | ||
| + | analogWrite(Bpin3, blue); | ||
| + | |||
| + | |||
| + | void lights(uint8_t signal) | ||
| + | |||
| + | if (signal >= signal_values[0]) { | ||
| + | // blue | ||
| + | RGBColor(0, 0, 255); | ||
| + | } else if (signal >= signal_values[1]) { | ||
| + | // Azure | ||
| + | RGBColor(0, 255, 255); | ||
| + | } else if (signal >= signal_values[2]) { | ||
| + | // Cyan | ||
| + | RGBColor(0, 127, 255); | ||
| + | } else if (signal >= signal_values[3]) { | ||
| + | // Aqua marine | ||
| + | RGBColor(0, 255, 127); | ||
| + | } else if (signal >= signal_values[4]) { | ||
| + | // Green | ||
| + | RGBColor(0, 255, 0); | ||
| + | } else if (signal >= signal_values[5]) { | ||
| + | // Yellow | ||
| + | RGBColor(255, 255, 0); | ||
| + | } else if (signal >= signal_values[6]) { | ||
| + | // Magenta | ||
| + | RGBColor(255, 0, 255); | ||
| + | } else if (signal >= signal_values[7]) { | ||
| + | // Rose | ||
| + | RGBColor(255, 0, 127); | ||
| + | } else if (signal >= signal_values[8]) { | ||
| + | // Orange | ||
| + | RGBColor(255, 127, 0); | ||
| + | } else if (signal >= signal_values[9]) { | ||
| + | // Red | ||
| + | RGBColor(255, 0, 0); | ||
| + | } else if (signal >= signal_values[9]) { | ||
| + | // Purple | ||
| + | RGBColor(128, 0, 128); | ||
| + | } else if (signal >= signal_values[10]) { | ||
| + | // Gold | ||
| + | RGBColor(255, 215, 0); | ||
| + | } else if (signal >= signal_values[11]) { | ||
| + | // Spring green | ||
| + | RGBColor(0, 250, 154); | ||
| + | } else if (signal >= signal_values[12]) { | ||
| + | // Turquoise | ||
| + | RGBColor(64, 224, 208); | ||
| + | } else if (signal >= signal_values[13]) { | ||
| + | // Indigo | ||
| + | RGBColor(75, 0, 130); | ||
| + | } else if (signal >= signal_values[14]) { | ||
| + | // Pink | ||
| + | RGBColor(255, 192, 203); | ||
| + | } else if (signal >= signal_values[15]) { | ||
| + | // Lavender | ||
| + | RGBColor(230, 230, 250); | ||
| + | } else if (signal >= signal_values[16]) { | ||
| + | // Chocolate | ||
| + | RGBColor(210, 105, 30); | ||
| + | } else if (signal >= signal_values[17]) { | ||
| + | // Sea green | ||
| + | RGBColor(46, 139, 87); | ||
| + | } else if (signal >= signal_values[18]) { | ||
| + | // Olive | ||
| + | RGBColor(128, 128, 0); | ||
| + | } else if (signal >= signal_values[19]) { | ||
| + | // Maroon | ||
| + | RGBColor(128, 0, 0); | ||
| + | } else if (signal >= signal_values[20]) { | ||
| + | // Midnight blue | ||
| + | RGBColor(25, 25, 112); | ||
| + | } else if (signal >= signal_values[21]) { | ||
| + | // Medium violet red | ||
| + | RGBColor(199, 21, 133); | ||
| + | } else if (signal >= signal_values[22]) { | ||
| + | // Orchid | ||
| + | RGBColor(218, 112, 214); | ||
| + | } else if (signal >= signal_values[23]) { | ||
| + | // Steel blue | ||
| + | RGBColor(70, 130, 180); | ||
| + | } else if (signal >= signal_values[24]) { | ||
| + | // Coral | ||
| + | RGBColor(255, 127, 80); | ||
| + | } else { | ||
| + | // White | ||
| + | RGBColor(255,255,255); | ||
| + | } | ||
| + | |||
| + | |||
| + | void button1Pressed() | ||
| + | |||
| + | unsigned long current = millis(); | ||
| + | if(millis() - lastDebounceTime1 > debounceDelay){ | ||
| + | lastDebounceTime1 = current; | ||
| + | Serial.println(song); | ||
| + | song++; | ||
| + | song = song % 2; | ||
| + | } | ||
| + | |||
| + | |||
| + | void button2Pressed() | ||
| + | |||
| + | unsigned long current = millis(); | ||
| + | if(current - lastDebounceTime2 > debounceDelay){ | ||
| + | lastDebounceTime2 = current; | ||
| + | if(song != 5){ | ||
| + | prev_song = song; | ||
| + | song = 5; | ||
| + | } else if (song == 5){ | ||
| + | song = prev_song; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void readFile(char *file_name) | ||
| + | Serial.print("Init SD card..."); | ||
| + | if (!SD.begin(4)) { | ||
| + | Serial.println("init failed!"); | ||
| + | while (1); | ||
| + | } | ||
| + | Serial.println("init done."); | ||
| + | // open the file for reading: | ||
| + | myFile = SD.open(file_name); | ||
| + | if (myFile) { | ||
| + | Serial.println(file_name); | ||
| + | uint8_t i = 0; | ||
| + | // read from the file until there's nothing else in it: | ||
| + | while (myFile.available()) { | ||
| + | short int note = myFile.parseInt(); | ||
| + | melody[i] = note; | ||
| + | if (i > 120) | ||
| + | break; | ||
| + | i++; | ||
| + | } | ||
| + | len = i; | ||
| + | notes = len / 2; | ||
| + | // close the file: | ||
| + | myFile.close(); | ||
| + | } else { | ||
| + | // if the file didn't open, print an error: | ||
| + | Serial.println("error opening file"); | ||
| + | } | ||
| + | |||
| + | |||
| + | void sing(uint8_t song_id) | ||
| + | // this calculates the duration of a whole note in ms | ||
| + | int wholenote = (60000 * 4) / tempo; | ||
| + | int divider = 0, noteDuration = 0; | ||
| + | // iterate over the notes of the melody. | ||
| + | // the array is twice the number of notes (notes + durations) | ||
| + | for (uint8_t thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) { | ||
| + | if (song_id != song) { | ||
| + | return; | ||
| + | } | ||
| + | lights(abs(melody[thisNote]) % 255); | ||
| + | // calculates the duration of each note | ||
| + | divider = melody[thisNote + 1]; | ||
| + | if (divider > 0) { | ||
| + | // regular note, just proceed | ||
| + | noteDuration = (wholenote) / divider; | ||
| + | } else if (divider < 0) { | ||
| + | // dotted notes are represented with negative durations!! | ||
| + | noteDuration = (wholenote) / abs(divider); | ||
| + | noteDuration *= 1.5; // increases the duration in half for dotted notes | ||
| + | } | ||
| + | // we only play the note for 90% of the duration, leaving 10% as a pause | ||
| + | tone(buzzer, melody[thisNote], noteDuration * 0.9); | ||
| + | |||
| + | // Wait for the specief duration before playing the next note | ||
| + | delay(noteDuration); | ||
| + | // stop the waveform generation before the next note | ||
| + | noTone(buzzer); | ||
| + | } | ||
| + | |||
| + | void play(char *song_name, uint8_t song_id) | ||
| + | readFile(song_name); | ||
| + | sing(song_id); | ||
| + | |||
| + | void setup() | ||
| + | |||
| + | // Start with the LEDs off. | ||
| + | pinMode(10, OUTPUT); | ||
| + | pinMode(9, OUTPUT); | ||
| + | pinMode(8, OUTPUT); | ||
| + | pinMode(14, OUTPUT); | ||
| + | pinMode(15, OUTPUT); | ||
| + | pinMode(16, OUTPUT); | ||
| + | pinMode(17, OUTPUT); | ||
| + | pinMode(18, OUTPUT); | ||
| + | pinMode(19, OUTPUT); | ||
| + | | ||
| + | pinMode(2, INPUT_PULLUP); | ||
| + | attachInterrupt(digitalPinToInterrupt(2), button1Pressed, FALLING); | ||
| + | |||
| + | pinMode(3, INPUT_PULLUP); | ||
| + | attachInterrupt(digitalPinToInterrupt(3), button2Pressed, FALLING); | ||
| + | // Open serial communications and wait for port to open | ||
| + | Serial.begin(9600); | ||
| + | while (!Serial) { | ||
| + | // wait for serial port to connect | ||
| + | } | ||
| + | // initialize the LCD | ||
| + | lcd.begin(); | ||
| + | // Turn on the blacklight and print a message. | ||
| + | lcd.backlight(); | ||
| + | |||
| + | |||
| + | void loop() | ||
| + | |||
| + | lcd.clear(); | ||
| + | switch(song) { | ||
| + | case 0: | ||
| + | lcd.clear(); | ||
| + | lcd.print("Game of thrones"); | ||
| + | play((char*)"got.txt", 0); | ||
| + | break; | ||
| + | case 1: | ||
| + | lcd.clear(); | ||
| + | lcd.print("Fur Elise-"); | ||
| + | lcd.setCursor(3,1); | ||
| + | lcd.print("Beethoven"); | ||
| + | play((char*)"furelise.txt", 1); | ||
| + | break; | ||
| + | default: | ||
| + | break; | ||
| + | } | ||
| + | |||
| </note> | </note> | ||
| Line 30: | Line 325: | ||
| <note tip> | <note tip> | ||
| + | Link catre demo: https://www.youtube.com/shorts/H1VGBhJymu8 | ||
| + | {{ :pm:prj2023:abirlica:poza.jpg?650 |}} | ||
| </note> | </note> | ||
| ===== Concluzii ===== | ===== Concluzii ===== | ||
| + | <note tip> | ||
| + | Am dorit inițial să implementez un media player care să redea fișiere audio .wav de pe un card SD și să adauge un efect luminos pentru a sincroniza culorile cu notele muzicale, insa din motive necunoscute, am întâmpinat dificultăți în redarea fișierelor .wav de pe cardul SD utilizând biblioteca TMRpcm. | ||
| + | Ca soluție alternativă, am decis să stochez mai multe fișiere .txt pe card, fiecare conținând notele corespunzătoare unei melodii. Am citit notele din fișierul selectat într-un vector și le-am redat folosind funcția "note" din Arduino IDE. | ||
| + | |||
| + | Am implementat un buton pentru schimbarea melodiilor și un alt buton pentru a pune pauza redarii unei melodii. În timpul redarii, cele 3 LED-uri își schimbă culorile în funcție de nota redată în prezent de difuzor. | ||
| + | |||
| + | Am încercat să îmbunătățesc procesul de eliminare a rezonanțelor provocate de contactele imperfecte ale butonului prin adăugarea unui condensator în serie cu fiecare buton. Cu toate acestea, butoanele tot nu functionau corespunzator, asadar, am adaugat o metoda de debouncing pentru a detecta o singura apasare de buton. | ||
| + | |||
| + | Am fost nevoit să folosesc o lista restransa de melodii, deoarece adaugarea ecranului LCD, si implicit a bibliotecii "LiquidCrystal_I2C", supraincarca memoria placii Arduino si componentele nu mai funcționau corect.\\ | ||
| + | Dupa ce erau citite doua melodii de pe cardul SD, memoria se incarca si programul se bloca la citirea urmatoarei melodii. | ||
| + | |||
| + | Din punct de vedere hardware, versiunea finală a proiectului a suferit câteva modificări. Am economisit pini prin adăugarea a încă 2 LED-uri RGB și am optat pentru un LCD cu interfață I2C în locul celui standard. De asemenea, am adăugat un amplificator LM386 pentru a amplifica sunetul unui difuzor SparkFun de 0.5W. | ||
| + | |||
| + | Dezvolatarea acestui proiect nu a fost una usoara. Pe parcusului acesteia am intampinat probleme in ceea ce priveste constructia hardware-ului cat si dezvoltarea corecta a software-ului, insa rezultatul final, desi este unul mai simplu decat mi-am propus initial, este unul complet functional. | ||
| + | </note> | ||
| ===== Download ===== | ===== Download ===== | ||
| + | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">PDF Proiect</a></html> | ||
| ===== Jurnal ===== | ===== Jurnal ===== | ||
| <note tip> | <note tip> | ||
| - | 3 mai - documentatie initiala | + | 3 mai - documentatie initiala\\ |
| + | 14 mai - hardware\\ | ||
| + | 25 mai - software | ||
| </note> | </note> | ||
| Line 46: | Line 361: | ||
| <note> | <note> | ||
| - | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | Diagrama bloc - https://app.diagrams.net \\ |
| + | Schema cablaj - https://fritzing.org \\ | ||
| + | LCD I2C - https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library \\ | ||
| + | SD library - https://github.com/arduino-libraries/SD \\ | ||
| </note> | </note> | ||
| - | |||
| - | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">PDF Proiect</a></html> | ||