This is an old revision of the document!


Pian digital - Vlaicu Vlad

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.

⠀⠀Scopul principal al proiectului nostru este de a oferi o alternativă modernă și ușor de utilizat la pianul tradițional. Dorim să aducem muzica în viața oamenilor, indiferent de nivelul lor de experiență în muzică sau de spațiul disponibil pentru un pian convențional.

⠀⠀Ideea noastră a pornit de la dorința de a face muzica mai accesibilă și mai distractivă. Am observat că mulți oameni ar dori să învețe să cânte la pian, dar se simt descurajați de complexitatea și costul unui pian tradițional. Am vrut să oferim o soluție inovatoare și portabilă, care să permită oamenilor să se bucure de experiența de a cânta la pian fără constrângerile obișnuite.

⠀⠀Credem că proiectul nostru este util pentru alții și pentru noi în mai multe feluri. Pentru începători, pianul digital oferă un mod intuitiv și accesibil de a învăța și de a se familiariza cu muzica și tehnica pianistică. Pentru muzicieni experimentați, este o opțiune practică și portabilă pentru a-și exersa și a compune muzică. În plus, piano digital oferă o gamă variată de sunete și opțiuni de ritm, permițându-le utilizatorilor să-și exploreze creativitatea și să experimenteze cu diferite stiluri muzicale.

⠀⠀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

Lista piese

  • 2 placi Arduino
  • interfata I2C LCD 1602
  • ecran LCD 1602
  • 2 buzzers
  • 2 potentiometre
  • 10 butoane

Schema electrica

Componenta software

A fost implementat protocolul I2C intre cele doua placi Arduino, placa Slave primeste inputul de la butoane si transmite mai departe catre placa Master unde se afla logica principala a automatului

Mod de functionare: placa Slave primeste input de la utilizator. Daca utilizatorul apasa pe butoanele destinate clapelor de pian, atunci placa va emite sunetul corespunzator. Daca utilizatorul apasa pe butoanele de comanda, comanda respectiva este pastrata pana cand va fi ceruta de placuta Master. Placa Master cere comenzi de la placa Slave. Cu aceste comenzi, utilizatorul poate naviga prin meniul cu ritmuri de unde poate selecta un anumit ritm folosind butoanele de BACK si NEXT. Acest lucru este realizat ci ajutorul LCD-ului care afiseaza itemul curent din meniu. Cand utilizatorul apasa PLAY, functia pentru ritmul respectiv este apelata, iar placa Master emite notele respective prin Speakerul sau. Daca utilizatorul alege sa apese din nou butonul PLAY, functia se va opri, iar utilizatorul va reveni in meniul cu ritmuri. Daca utilizatorul alege sa apese butoanele de BACK sau NEXT, atunci tempo-ul ritmului va incetini sau va accelera. Totodata in momentul apelarii functiei metronome, timer-ul va inregistra un nou punct de start, iar daca utilizatorul nu va opri metronomul in timpul alocat, acesta se va opri de unul singur, iar programul se va intoarce la meniul de selectie a ritmurilor. Pentru a demonstra aceasta functionalitate, timul alocat a fost setat pentru 10 secunde.

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()

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()

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()

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 Script Files can be find here

Bibliografie

pm/prj2023/fstancu/digitalpiano.1684904586.txt.gz · Last modified: 2023/05/24 08:03 by vlad_gabriel.vlaicu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0