Pianola con Arduino

Ciao a tutti...
Mi presento... Sono Francesco, studente di elettronica appena approcciato al mondo della programmazione.
Ho deciso di realizzare un progetto di una pianola tramite Arduino come uno dei primi passi.
Ho però riscontrato dei problemi e mi chiedevo se col vostro aiuto magari potevo risolverlo.

Allora il codice che ho scritto è il seguente:

int Buzzer=13; //Collego il Buzzer al pin D13
int Do=12; //Collego il pulsante Do al pin D12
int Re=11; //Collego il pulsante Re al pin D11
int Mi=10; //Collego il pulsante Mi al pin D10
int Fa=9; //Collego il pulsante Fa al pin D9
int Sol=8; //Collego il pulsante Sol al pin D8
int La=7; //Collego il pulsante La al pin D7
int Si=6; //Collego il pulsante Si al pin D6

int ValueDo; //Valore del pulsante Do
int ValueRe; //Valore del pulsante Re
int ValueMi; //Valore del pulsante Mi
int ValueFa; //Valore del pulsante Fa
int ValueSol; //Valore del pulsante Sol
int ValueLa; //Valore del pulsante La
int ValueSi; //Valore del pulsante Si

void setup() //Azioni da eseguire solo all'avvio
{
  pinMode(Buzzer,OUTPUT); //Imposto in uscita il pin D13
  pinMode(Do,INPUT); //Imposto in ingresso il pin D12
  pinMode(Re,INPUT); //Imposto in ingresso il pin D11
  pinMode(Mi,INPUT); //Imposto in ingresso il pin D10
  pinMode(Fa,INPUT); //Imposto in ingresso il pin D9
  pinMode(Sol,INPUT); //Imposto in ingresso il pin D8
  pinMode(La,INPUT); //Imposto in ingresso il pin D7
  pinMode(Si,INPUT); //Imposto in ingresso il pin D6
}

void loop() //Azioni da ripetere all'infinito
{
  ValueDo=digitalRead(Do); //Associo al valore del pulsante Do la lettura al pin D12
  ValueRe=digitalRead(Re); //Associo al valore del pulsante Re la lettura al pin D11
  ValueMi=digitalRead(Mi); //Associo al valore del pulsante Mi la lettura al pin D10
  ValueFa=digitalRead(Fa); //Associo al valore del pulsante Fa la lettura al pin D9
  ValueSol=digitalRead(Sol); //Associo al valore del pulsante Sol la lettura al pin D8
  ValueLa=digitalRead(La); //Associo al valore del pulsante La la lettura al pin D7
  ValueSi=digitalRead(Si); //Associo al valore del pulsante Si la lettura al pin D6
  
  while(ValueDo=HIGH) //Mentre il valore del pulsante Do è alto...
  {
    tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
  }
   
  while(ValueRe=HIGH) //Mentre il valore del pulsante Re è alto...
  {
    tone(Buzzer,294); //...fai suonare il Buzzer a 294Hz
  }
  
  while(ValueMi=HIGH) //Mentre il valore del pulsante Mi è alto...
  {
    tone(Buzzer,330); //...fai suonare il Buzzer a 330Hz
  }
  
  while(ValueFa=HIGH) //Mentre il valore del pulsante Fa è alto...
  {
    tone(Buzzer,349); //...fai suonare il Buzzer a 349Hz
  }
  
  while(ValueSol=HIGH) //Mentre il valore del pulsante Sol è alto...
  {
    tone(Buzzer,392); //...fai suonare il Buzzer a 392Hz
  }
  
  while(ValueLa=HIGH) //Mentre il valore del pulsante La è alto...
  {
    tone(Buzzer,440); //...fai suonare il Buzzers a 440Hz
  }
  
  while(ValueSi=HIGH) //Mentre il valore del pulsante Si è alto...
  {
    tone(Buzzer,494); //...fai suonare il Buzzers a 349Hz
  }
}

Prelevo il segnale del pulsante tra l'uscita di quest'ultimo e la resistenza da 10Kohm come in figura:

E infine collego il Buzzer tra il pin D13 e GND.

Il risultato che ottengo appena il programma parte è il suono continuo (credo il Do a 262Hz) senza premere alcun pulsante.

Spero che qualcuno mi riesca a trovare l'errore perchè l'ho controllato più e più volte senza cavare il ragno dal buco.

Grazie in anticipo a tutti...

Non capisco una cosa ma hai 7 pulsanti giusto?

Ad ogni modo il problema sono i while.

Supponiamo che poni Do ad HIGH

esegui questo while

while(ValueDo=HIGH) //Mentre il valore del pulsante Do è alto...
{
tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
}

e non ne esci più perchè non aggiorni il ValueDo a LOW

Inoltre credo (ma non sono sicuro al 100%) che sia buona norma inserire dei delay anche di un 1ms tra un digital read ed un'altro.

P.S. per fixare il tuo codice sostituisci gli while con degli if

Si, i pulsanti sono 7, uno per ogni nota. Scusa non lo avevo precisato.

Comunque il ValueDo si pone automaticamente a LOW dal momento che rilascio il pulsante Do e il digitalRead registra tale azione, se non vado errato.

Il problema è che il tuo codice non tornerà mai ad eseguire l'istruzione di digitalRead()!

Il tuo codice, una volta letto un bottone in HIGH, non uscirà mai dal ciclo

  while(ValueDo=HIGH) //Mentre il valore del pulsante Do è alto...
  {
    tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
  } //qui il valore di ValueDo è sempre alto! E eseguirà questo while all'infinito

Soluzione

void loop(){

valueDo = digitalRead(Do); //aggiorna il valore del Do

 if(ValueDo=HIGH) //Se il valore del pulsante Do è alto...
  {
    tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
  } 
 
//riparte dall'inizio del loop e quindi aggiorna anche lo stato del bottone
}

Fidati e sostituisci tutti gli while con degli if, vedrai che funziona.

Edit: inizializzare le variabili come doValue a false, potrebbe essere una buona idea in modo che non portano con valori casuali. E' solo un accorgimento tuttavia può essere utile per non avere rumori indesiderati in accensione

+1 per la questione dei while. Il tuo codice non uscità mai da un ciclo in cui la variabile usata come test per l'ingresso nel ciclo non viene poi modificata all'interno dello stesso.

Ho sostituito tutti i while con if ed è sorto un ulteriore problema... Ora sembra che suonino tutti insieme (un casino assurdo)... Mi è venuto in mente che potrei aver sbagliato il cablaggio dei pulsanti, così ho impostato tutti in LOW come prova del nove (siccome ho dei pulsanti con quattro piedini, due normalmente chiusi, e due normalmente aperti), ma ancora nulla... Ho anche provato a inserire tutta questa parte:

ValueDo=digitalRead(Do); //Associo al valore del pulsante Do la lettura al pin D12
  ValueRe=digitalRead(Re); //Associo al valore del pulsante Re la lettura al pin D11
  ValueMi=digitalRead(Mi); //Associo al valore del pulsante Mi la lettura al pin D10
  ValueFa=digitalRead(Fa); //Associo al valore del pulsante Fa la lettura al pin D9
  ValueSol=digitalRead(Sol); //Associo al valore del pulsante Sol la lettura al pin D8
  ValueLa=digitalRead(La); //Associo al valore del pulsante La la lettura al pin D7
  ValueSi=digitalRead(Si); //Associo al valore del pulsante Si la lettura al pin D6

dopo ogni nota pensando che così ricontrolla ogni volta il digitalRead... Ma niente... Scusate se sono così impacciato ma sono davvero ancora alle prime armi...

Inserisci dei delay tra un read e l'altro così:

  ValueDo=digitalRead(Do); //Associo al valore del pulsante Do la lettura al pin D12
  delayMicroseconds(10);
  ValueRe=digitalRead(Re); //Associo al valore del pulsante Re la lettura al pin D11
  delayMicroseconds(10);  
  ValueMi=digitalRead(Mi); //Associo al valore del pulsante Mi la lettura al pin D10
  delayMicroseconds(10);
  ValueFa=digitalRead(Fa); //Associo al valore del pulsante Fa la lettura al pin D9
  delayMicroseconds(10);
  ValueSol=digitalRead(Sol); //Associo al valore del pulsante Sol la lettura al pin 
  delayMicroseconds(10);
  ValueLa=digitalRead(La); //Associo al valore del pulsante La la lettura al pin D7
  delayMicroseconds(10);
  ValueSi=digitalRead(Si); //Associo al valore del pulsante Si la lettura al pin D6
  delayMicroseconds(10);

Il sistema ha bisogno di tempo tra una lettura e l'altra. Facci sapere com'è andata :wink:

Niente da fare... Sembra ancora che si sentano tutti assieme...

Potresti postare il tuo attuale codice?

int Buzzer=13; //Collego il Buzzer al pin D13
int Do=12; //Collego il pulsante Do al pin D12
int Re=11; //Collego il pulsante Re al pin D11
int Mi=10; //Collego il pulsante Mi al pin D10
int Fa=9; //Collego il pulsante Fa al pin D9
int Sol=8; //Collego il pulsante Sol al pin D8
int La=7; //Collego il pulsante La al pin D7
int Si=6; //Collego il pulsante Si al pin D6

int ValueDo; //Valore del pulsante Do
int ValueRe; //Valore del pulsante Re
int ValueMi; //Valore del pulsante Mi
int ValueFa; //Valore del pulsante Fa
int ValueSol; //Valore del pulsante Sol
int ValueLa; //Valore del pulsante La
int ValueSi; //Valore del pulsante Si

void setup() //Azioni da eseguire solo all'avvio
{
  pinMode(Buzzer,OUTPUT); //Imposto in uscita il pin D13
  pinMode(Do,INPUT); //Imposto in ingresso il pin D12
  pinMode(Re,INPUT); //Imposto in ingresso il pin D11
  pinMode(Mi,INPUT); //Imposto in ingresso il pin D10
  pinMode(Fa,INPUT); //Imposto in ingresso il pin D9
  pinMode(Sol,INPUT); //Imposto in ingresso il pin D8
  pinMode(La,INPUT); //Imposto in ingresso il pin D7
  pinMode(Si,INPUT); //Imposto in ingresso il pin D6
}

void loop() //Azioni da ripetere all'infinito
{
  ValueDo=digitalRead(Do); //Associo al valore del pulsante Do la lettura al pin D12
  delayMicroseconds(10); //Aspetta 10us
  ValueRe=digitalRead(Re); //Associo al valore del pulsante Re la lettura al pin D11
  delayMicroseconds(10); //Aspetta 10us
  ValueMi=digitalRead(Mi); //Associo al valore del pulsante Mi la lettura al pin D10
  delayMicroseconds(10); //Aspetta 10us
  ValueFa=digitalRead(Fa); //Associo al valore del pulsante Fa la lettura al pin D9
  delayMicroseconds(10); //Aspetta 10us
  ValueSol=digitalRead(Sol); //Associo al valore del pulsante Sol la lettura al pin D8
  delayMicroseconds(10); //Aspetta 10us
  ValueLa=digitalRead(La); //Associo al valore del pulsante La la lettura al pin D7
  delayMicroseconds(10); //Aspetta 10us
  ValueSi=digitalRead(Si); //Associo al valore del pulsante Si la lettura al pin D6
  delayMicroseconds(10); //Aspetta 10us
  
  if(ValueDo=HIGH) //Se il valore del pulsante Do è alto...
  {
    tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
  }
   
  if(ValueRe=HIGH) //Se il valore del pulsante Re è alto...
  {
    tone(Buzzer,294); //...fai suonare il Buzzer a 294Hz
  }
  
  if(ValueMi=HIGH) //Se il valore del pulsante Mi è alto...
  {
    tone(Buzzer,330); //...fai suonare il Buzzer a 330Hz
  }
  
  if(ValueFa=HIGH) //Se il valore del pulsante Fa è alto...
  {
    tone(Buzzer,349); //...fai suonare il Buzzer a 349Hz
  }
  
  if(ValueSol=HIGH) //Se il valore del pulsante Sol è alto...
  {
    tone(Buzzer,392); //...fai suonare il Buzzer a 392Hz
  }
  
  if(ValueLa=HIGH) //Se il valore del pulsante La è alto...
  {
    tone(Buzzer,440); //...fai suonare il Buzzers a 440Hz
  }
  
  if(ValueSi=HIGH) //Se il valore del pulsante Si è alto...
  {
    tone(Buzzer,494); //...fai suonare il Buzzers a 349Hz
  }
}

Prova a rivedere il codice così:

void loop() //Azioni da ripetere all'infinito
{
    if(digitalRead(Do) = HIGH) //Se il valore del pulsante Do è alto...
  {
    tone(Buzzer,262); //...fai suonare il Buzzer a 262Hz
    delayMicroseconds(10); //Aspetta 10us
}
}

se non funziona così, è il caso che posti una foto dei collegamenti :slight_smile:

mi sa che l'errore è l'utilizzo di = per comparare. devi usare ==.

quindi:
if(digitalRead(Do) == HIGH)

a questo punto, visto che Do e tutte le altre sono dei valori boolean (o Vero o Falso), è uno spreco usare le 'int'. dichiarali come boolean ( boolean - Arduino Reference ).

Davide.

dab77:
mi sa che l'errore è l'utilizzo di = per comparare. devi usare ==.

E' vero, non ci avevo fatto caso neanch'io :wink:

a questo punto, visto che Do e tutte le altre sono dei valori boolean (o Vero o Falso), è uno spreco usare le 'int'. dichiarali come boolean (

Oppure un byte, tanto anche il boolean occupa comunque 1 byte in memoria.

leo72:

dab77:
mi sa che l'errore è l'utilizzo di = per comparare. devi usare ==.

E' vero, non ci avevo fatto caso neanch'io :wink:

a questo punto, visto che Do e tutte le altre sono dei valori boolean (o Vero o Falso), è uno spreco usare le 'int'. dichiarali come boolean (

Oppure un byte, tanto anche il boolean occupa comunque 1 byte in memoria.

ma dai! questa non la sapevo, pensavo stupidamente che potesse occupare solo un bit.. quindi è così perchè non si può indirizzare un solo bit, o perchè insieme al bit del valore viene registrato dell'altro?

dab77:

leo72:
Oppure un byte, tanto anche il boolean occupa comunque 1 byte in memoria.

ma dai! questa non la sapevo, pensavo stupidamente che potesse occupare solo un bit.. quindi è così perchè non si può indirizzare un solo bit, o perchè insieme al bit del valore viene registrato dell'altro?

Il resto del byte è inutilizzato. Per questo spesso si consiglia di utilizzare gli operatori sui bit se si devono memorizzare più flag che devono avere solo il valore 1 o 0.

leo72:

dab77:

leo72:
Oppure un byte, tanto anche il boolean occupa comunque 1 byte in memoria.

ma dai! questa non la sapevo, pensavo stupidamente che potesse occupare solo un bit.. quindi è così perchè non si può indirizzare un solo bit, o perchè insieme al bit del valore viene registrato dell'altro?

Il resto del byte è inutilizzato. Per questo spesso si consiglia di utilizzare gli operatori sui bit se si devono memorizzare più flag che devono avere solo il valore 1 o 0.

Giusto, così non si spreca spazio..
Francesco, potrebbe essere l'occasione per imparare una cosa nuova! registri le 7 note come sette bit di un byte, e controlli i singoli valori dei byte. non cambia niente come risultato, ma utilizzi un metodo molto più elegante. io ci proverei.

Interessante lo sviluppo che ha preso la discussione.
Bravo dab77 per aver beccato l'errore sul while!

Allora... Ho sostituito gli = con == e adesso suona :% Però la nota non torna mai bassa. Se premo il Do questo suona finchè non premo un'altra nota che a sua volta farà lo stesso. Ho prova a mettere dopo ogni nota:

else
{
   noTone(Buzzer);
}

...ma peggio che prima. Ho ottenuto delle frequenze altissime senza spiegarmi il perchè.

Per quanto riguarda quello che ha detto dab77, come faccio a registrare le note come bit?