This shows you the differences between two versions of the page.
pm:prj2023:fstancu:digitalpiano [2023/05/30 08:26] vlad_gabriel.vlaicu |
pm:prj2023:fstancu:digitalpiano [2023/05/30 08:28] (current) vlad_gabriel.vlaicu |
||
---|---|---|---|
Line 2: | Line 2: | ||
- | === Introducere === | + | ==== Introducere ==== |
⠀⠀Prezentarea proiectului nostru constă într-un pian digital inovator, care oferă posibilitatea de a produce sunete muzicale prin apăsarea butoanelor corespunzătoare. Acesta este echipat cu un ecran LCD și alte butoane pentru a seta diverse metronoame și ritmuri. | ⠀⠀Prezentarea proiectului nostru constă într-un pian digital inovator, care oferă posibilitatea de a produce sunete muzicale prin apăsarea butoanelor corespunzătoare. Acesta este echipat cu un ecran LCD și alte butoane pentru a seta diverse metronoame și ritmuri. | ||
Line 14: | Line 14: | ||
⠀⠀Pentru noi, acest proiect reprezintă o oportunitate de a aduce inovația în lumea muzicii și de a contribui la pasiunea oamenilor pentru acest domeniu. Ne bucurăm să aducem un instrument muzical versatil și accesibil în viețile oamenilor și să îi inspirăm să exploreze și să se exprime prin muzică. | ⠀⠀Pentru noi, acest proiect reprezintă o oportunitate de a aduce inovația în lumea muzicii și de a contribui la pasiunea oamenilor pentru acest domeniu. Ne bucurăm să aducem un instrument muzical versatil și accesibil în viețile oamenilor și să îi inspirăm să exploreze și să se exprime prin muzică. | ||
- | === Schema bloc === | + | ==== Schema bloc ==== |
{{https://ocw.cs.pub.ro/courses/_media/pm/prj2023/plan_piandigital.png?550x400}} | {{https://ocw.cs.pub.ro/courses/_media/pm/prj2023/plan_piandigital.png?550x400}} | ||
- | === Lista piese === | + | ==== Lista piese ==== |
* 2 placi Arduino | * 2 placi Arduino | ||
Line 27: | Line 27: | ||
* 10 butoane | * 10 butoane | ||
- | === Schema electrica === | + | ==== Schema electrica ==== |
{{https://ocw.cs.pub.ro/courses/_media/pm:prj2023:fstancu:pm_diagramvv.png?550x400}} | {{https://ocw.cs.pub.ro/courses/_media/pm:prj2023:fstancu:pm_diagramvv.png?550x400}} | ||
- | === Componenta software === | + | ==== Componenta software ==== |
A fost implementat protocolul I2C intre cele doua placi Arduino, placa Slave primeste inputul de la butoane si | A fost implementat protocolul I2C intre cele doua placi Arduino, placa Slave primeste inputul de la butoane si | ||
Line 50: | Line 50: | ||
Laboratoarele utilizate pentru acest proiect sunt Laboratorul 0, Laboratorul 3 si Laboratorul 6 | Laboratoarele utilizate pentru acest proiect sunt Laboratorul 0, Laboratorul 3 si Laboratorul 6 | ||
- | |||
- | ==== SLAVE: ==== | ||
- | |||
- | void setup() | ||
- | /* Definitions */ | ||
- | #define NOTE_C 1046 | ||
- | #define NOTE_D 1174 | ||
- | #define NOTE_E 1318 | ||
- | #define NOTE_F 1396 | ||
- | #define NOTE_G 1567 | ||
- | #define NOTE_A 1760 | ||
- | #define NOTE_B 1975 | ||
- | #define SLAVE_ADDR 9 | ||
- | | ||
- | /* Setup input ports */ | ||
- | const int BUZZER = 12; | ||
- | const int BUTTON_C = 11; | ||
- | const int BUTTON_D = 10; | ||
- | const int BUTTON_E = 9; | ||
- | const int BUTTON_F = 8; | ||
- | const int BUTTON_G = 7; | ||
- | const int BUTTON_A = 6; | ||
- | const int BUTTON_B = 5; | ||
- | const int BACK = 4; | ||
- | const int ENTER = 3; | ||
- | const int NEXT = 2; | ||
- | |||
- | /* Setup pin modes */ | ||
- | |||
- | pinMode(BUZZER, OUTPUT); | ||
- | pinMode(BUTTON_C, INPUT); | ||
- | digitalWrite(BUTTON_C, HIGH); | ||
- | pinMode(BUTTON_C, INPUT); | ||
- | digitalWrite(BUTTON_C, HIGH); | ||
- | pinMode(BUTTON_D, INPUT); | ||
- | digitalWrite(BUTTON_D, HIGH); | ||
- | pinMode(BUTTON_E, INPUT); | ||
- | digitalWrite(BUTTON_E, HIGH); | ||
- | pinMode(BUTTON_F, INPUT); | ||
- | digitalWrite(BUTTON_F, HIGH); | ||
- | pinMode(BUTTON_G, INPUT); | ||
- | digitalWrite(BUTTON_G, HIGH); | ||
- | pinMode(BUTTON_A, INPUT); | ||
- | digitalWrite(BUTTON_A, HIGH); | ||
- | pinMode(BUTTON_B, INPUT); | ||
- | digitalWrite(BUTTON_B, HIGH); | ||
- | pinMode(BACK, INPUT); | ||
- | digitalWrite(BACK, HIGH); | ||
- | pinMode(ENTER, INPUT); | ||
- | digitalWrite(ENTER, HIGH); | ||
- | pinMode(NEXT, INPUT); | ||
- | digitalWrite(NEXT, HIGH); | ||
- | |||
- | /* Setup I2C */ | ||
- | Wire.begin(SLAVE_ADDR); | ||
- | Wire.onRequest(getCommand); | ||
- | |||
- | void loop() | ||
- | |||
- | /* set for each button push the buzzer to play the associated note */ | ||
- | while(digitalRead(BUTTON_C) == LOW){ | ||
- | tone(BUZZER, NOTE_C); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_D) == LOW){ | ||
- | tone(BUZZER, NOTE_D); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_E) == LOW){ | ||
- | tone(BUZZER, NOTE_E); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_F) == LOW){ | ||
- | tone(BUZZER, NOTE_F); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_G) == LOW){ | ||
- | tone(BUZZER, NOTE_G); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_A) == LOW){ | ||
- | tone(BUZZER, NOTE_A); | ||
- | } | ||
- | |||
- | while(digitalRead(BUTTON_B) == LOW){ | ||
- | tone(BUZZER, NOTE_B); | ||
- | } | ||
- | |||
- | /* setup the three control buttons to change the last command value */ | ||
- | |||
- | while(digitalRead(BACK) == LOW){ | ||
- | command = 5; | ||
- | } | ||
- | |||
- | while(digitalRead(ENTER) == LOW){ | ||
- | command = 4; | ||
- | } | ||
- | |||
- | while(digitalRead(NEXT) == LOW){ | ||
- | command = 3; | ||
- | } | ||
- | | ||
- | function getCommand called by the Master to retrieve the last given command: | ||
- | |||
- | void getCommand() | ||
- | Wire.write(command); | ||
- | command = 0; | ||
- | |||
- | | ||
- | | ||
- | ==== MASTER: ==== | ||
- | | ||
- | Definitions: | ||
- | | ||
- | #define SLAVE_ADDR 9 | ||
- | |||
- | #define PLAY 4 | ||
- | #define NEXT 3 | ||
- | #define BACK 5 | ||
- | |||
- | const int BUZZER = 11; | ||
- | volatile unsigned long startTime; //variabila pentru a calcula durata | ||
- | const unsigned long countdownDuration = 10000; // metronomul se va opri dupa 10.000 ms = 10 secunde | ||
- | volatile int canPlay = 0; | ||
- | |||
- | LiquidCrystal_I2C lcd(0x27, 16, 2); //ecranul LCD reprezentat de libraria <LiquidCrystal_I2C.h> importata din Market | ||
- | int currentState = 2; | ||
- | | ||
- | Aparatul este o masina de stari prin care se sincronizeaza afisarea in LCD cu comportamentul programului, | ||
- | fie ca acesta are metronomul pornit sau nu. | ||
- | |||
- | - State 1 - Plays metronome -> press PLAY => State 2 | ||
- | - State 2 - default state = alegerea ritmului 1/4 (NEXT) => State 3, (BACK) => do Nothing, (PLAY) => State 1 | ||
- | - State 3 - default state = alegerea ritmului 2/4 (NEXT) => State 4, (BACK) => State 2, (PLAY) => State 1 | ||
- | - State 4 - default state = alegerea ritmului 4/4 (NEXT) => State 5, (BACK) => State 3, (PLAY) => State 1 | ||
- | - State 5 - default state = alegerea ritmului 1/3 (NEXT) => do Nothing, (BACK) => State 4, (PLAY) => State 1 | ||
- | |||
- | setup() | ||
- | |||
- | /* Set initial LCD messages */ | ||
- | lcd.begin(); | ||
- | lcd.print("Hello, Vlad!"); | ||
- | lcd.flush(); | ||
- | delay(3000); | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 1/4"); | ||
- | | ||
- | /* Set timer */ | ||
- | TCCR1A = 0; | ||
- | TCCR1B = (1 << WGM12) | (1 << CS12); | ||
- | OCR1A = 62500; | ||
- | TIMSK1 |= (1 << OCIE1A); | ||
- | sei(); | ||
- | | ||
- | loop() | ||
- | |||
- | /* cer comenzi de la SLAVE */ | ||
- | Wire.requestFrom(SLAVE_ADDR, 1); | ||
- | byte command = Wire.read(); | ||
- | | ||
- | /* verific pentru starea curenta ce tip de comanda a fost data si se implementeaza logica */ | ||
- | if(currentState == 2){ | ||
- | if (command == PLAY) { | ||
- | lcd.clear(); | ||
- | lcd.print("PLAY"); | ||
- | currentState = 1; | ||
- | playM14(); | ||
- | } | ||
- | if (command == NEXT){ | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 2/4"); | ||
- | currentState = 3; | ||
- | } | ||
- | command = 0; | ||
- | } | ||
- | if(currentState == 3){ | ||
- | if (command == PLAY) { | ||
- | lcd.clear(); | ||
- | lcd.print("PLAY"); | ||
- | currentState = 1; | ||
- | playM24(); | ||
- | } | ||
- | if(command == BACK){ | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 1/4"); | ||
- | currentState = 2; | ||
- | } | ||
- | if(command == NEXT){ | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 4/4"); | ||
- | currentState = 4; | ||
- | } | ||
- | command = 0; | ||
- | } | ||
- | if(currentState == 4){ | ||
- | if (command == PLAY){ | ||
- | lcd.clear(); | ||
- | lcd.print("PLAY"); | ||
- | currentState = 1; | ||
- | playM44(); | ||
- | } | ||
- | if (command == NEXT) { | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 1/3"); | ||
- | currentState = 5; | ||
- | } | ||
- | if (command == BACK){ | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 2/4"); | ||
- | currentState = 3; | ||
- | } | ||
- | command = 0; | ||
- | } | ||
- | if (currentState == 5){ | ||
- | if (command == PLAY){ | ||
- | lcd.clear(); | ||
- | lcd.print("PLAY"); | ||
- | currentState = 1; | ||
- | playM13(); | ||
- | } | ||
- | if (command == BACK){ | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 4/4"); | ||
- | currentState = 4; | ||
- | } | ||
- | command = 0; | ||
- | } | ||
- | | ||
- | /* exemplu de metronome PLAY function */ | ||
- | void playM24(){ | ||
- | startTime = millis(); //start time for the Countdown | ||
- | canPlay = 0; //variable used to stop the metronome when timeout | ||
- | byte stopFlag = 0; //flag used to stop the metronome if the user presses PLAY again | ||
- | int tempo = 0; //initial variable that can modify the tempo should the user choose to | ||
- | int bpm = 120; // bpm value for display | ||
- | lcd.setCursor(0, 1); | ||
- | lcd.print(bpm); | ||
- | lcd.print(" BPM"); | ||
- | while(stopFlag != 4 && canPlay == 0){ | ||
- | Wire.requestFrom(SLAVE_ADDR, 1); //keep asking the SALVE about new commands | ||
- | stopFlag = Wire.read(); | ||
- | if(stopFlag == BACK){ // user chose to slow down the tempo | ||
- | tempo = tempo + 12; | ||
- | bpm = bpm - 5; | ||
- | lcd.setCursor(0, 1); | ||
- | lcd.print(bpm); | ||
- | lcd.print(" BPM"); | ||
- | } | ||
- | if(stopFlag == NEXT){ // user chose to fasten the tempo | ||
- | tempo = tempo - 12; | ||
- | bpm = bpm + 5; | ||
- | lcd.setCursor(0, 1); | ||
- | lcd.print(bpm); | ||
- | lcd.print(" BPM"); | ||
- | } | ||
- | tone(BUZZER, 1400); | ||
- | delay(50); | ||
- | noTone(BUZZER); | ||
- | delay(500 + tempo); // variable tempo is used to add user control over the metronome tempo | ||
- | tone(BUZZER, 1000); | ||
- | delay(50); | ||
- | noTone(BUZZER); | ||
- | delay(500 + tempo); | ||
- | } | ||
- | lcd.clear(); | ||
- | lcd.print("Metronome 1/4"); | ||
- | currentState = 2; //when the metronome stops, the currentState goes back to the default = State 2 | ||
- | } | ||
- | | ||
- | /* Interruption timer */ | ||
- | | ||
- | ISR(TIMER1_COMPA_vect){ | ||
- | if (millis() - startTime >= countdownDuration){ // if the difference between the current time and the start Time | ||
- | // of the metronome is greater than the allocated time | ||
- | canPlay = 1; // stop the metronome | ||
- | } | ||
- | } | ||
Bibliotecile utilizate sunt LiquidCrystal_I2C.h si Tone.h care pot fi regasite in Marketplace al IDE-ului de Arduino | Bibliotecile utilizate sunt LiquidCrystal_I2C.h si Tone.h care pot fi regasite in Marketplace al IDE-ului de Arduino | ||
- | [[https://github.com/Vlad-Vlaicu/PMProjectArduinoScripts | Script Files can be find here]] | + | [[https://github.com/Vlad-Vlaicu/PMProjectArduinoScripts | Script Files can be found here]] |
- | === Download === | + | ==== Download ==== |
Line 337: | Line 60: | ||
- | === Bibliografie === | + | ==== Bibliografie ==== |
[[https://ocw.cs.pub.ro/courses/pm/prj2023/fstancu/digitalpiano|Export to PDF]] | [[https://ocw.cs.pub.ro/courses/pm/prj2023/fstancu/digitalpiano|Export to PDF]] |