Problemas en un codigo de piano

Hola!
Tengo este código que descargue exacto de un video en youtube para un piano arduino, pero cuando lo uso, ademas de las notas que se presionan, suena una nota constante en el fondo, y el resto de notas solo funcionan en orden (si no es en orden no suenan). La persona del video no tuvo estos problemas, y no cambie el código, alguien puede identificar que pasa?

video: https://www.youtube.com/watch?v=CvZ-SGJ8fGo

codigo:

#define NOTE_C 262
#define NOTE_D 294
#define NOTE_E 330
#define NOTE_F 349
#define NOTE_G 392
#define NOTE_A 440
#define NOTE_B 493

#define ACTIVATED LOW 

const int PIEZO = 11;
const int LED = 13;

const int BUTTON_C = 10;
const int BUTTON_D = 9;
const int BUTTON_E = 8;
const int BUTTON_F = 7;
const int BUTTON_G = 6;
const int BUTTON_A = 5;
const int BUTTON_B = 4;



void setup()
{
  pinMode(LED, OUTPUT);
  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);
  
  digitalWrite(LED,LOW);
}

void loop()
{
  while(digitalRead(BUTTON_C) == ACTIVATED)
  {
    tone(PIEZO,NOTE_C);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_D) == ACTIVATED)
  {
    tone(PIEZO,NOTE_D);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_E) == ACTIVATED)
  {
    tone(PIEZO,NOTE_E);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_F) == ACTIVATED)
  {
    tone(PIEZO,NOTE_F);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_G) == ACTIVATED)
  {
    tone(PIEZO,NOTE_G);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_A) == ACTIVATED)
  {
    tone(PIEZO,NOTE_A);
    digitalWrite(LED,HIGH);
  }

  while(digitalRead(BUTTON_B) == ACTIVATED)
  {
    tone(PIEZO,NOTE_B);
    digitalWrite(LED,HIGH);
  }

  noTone(PIEZO);
  digitalWrite(LED,LOW);

}

TItulo editado por Moderador ante la falta de respuesta el autor

Por favor edita tu post y adjunta el código de acuerdo a las Normas del Foro.

Más allá que no me guste la forma en que está escrito el código, dentro de lo básico que es, funciona.
Los sonidos que escuchas (y no deberían sonar) se deben a los rebotes de los pulsadores.
Te dejo la simulación, los 3 botones de la derecha generan rebotes (como cualquier pulsador normal) y suena el sonido indeseado.
Los otros 4 no generan rebotes y el sonido es limpio.
Pero fuera de eso, funciona "bien".

Moderador:

  1. Lee las normas del foro
  2. Edita el código posteado usando etiquetas
    Ve a edición, luego selecciona todo el código que has publicado, lo cortas y click en <CODE/>
  3. Edita tu título, usa uno que no tenga justamente lo que se considera un título inútil.
    Ver en las normas punto 5.
    En particular "Ayuda para encontrar..."

Y no será que los sonidos se deben más a que las entradas están "flotando" y no tienen un nivel lógico estable al no tener resistencia PULL UP.???

No porque las entradas tienen las R pull-up activadas, recordá que

pinMode(pin, INPUT);
digitalWrite(pin, HIGH);

es lo mismo que

pinMode(pin, INPUT_PULLUP);

porque al escribir un HIGH en un pin en modo entrada activa su resistencia pull-up (al menos en los AVR).

Sí, a mí se me hace extraño esa posibilidad, casi da a confusión. Veo mucho más claro

pinMode(pin, INPUT_PULLUP);

y con una sola línea de código.
También es curioso esos ruidos (al menos en el simulador), pero creo que no puede ser sólo por los rebotes de los pulsadores ya que rebotes habrá en todos los pulsadores. Tal vez sea que por lo que sea los rebotes en esas frecuencias altas producen glitch audibles que no se producen a más bajas frecuencias.
No sé cómo funciona la librería tone pero imagino que siempre cortará la nota en un paso por cero para que no se produzcan glitch. Los rebotes de los pulsadores darán inicios y finales de los tonos que no podrá hacerlos todos a su paso por cero. Pero vamos, que no llego a entender del todo por qué sólo se producen en las notas altas (suponiendo que no sólo lo haga el simulador).

Pues es la forma en que trabaja el micro, se setea el modo entrada y luego se activa la resistencia pull-up.
INPUT_PULLUP es una macro que existe para facilitarnos la vida (y escribir una línea menos).

No se lo que imaginarás pero te puedo explicar lo que ocurre (aunque algo has ya entendido).
Todos los pulsadores generan rebotes, o sea, cambios rápidos de estado entre abierto y cerrado hasta que queda en un estado estable (ya sea abierto o cerrado).
El código presentado lee los pulsadores sin aplicar ningún filtro antirrebotes entonces es sensible a los mismos.
Suponte que un pulsador genera 5 rebotes en un lapso de 20 mseg y que los 5 rebotes tienen la misma duración, entonces se va a ejecutar tone() seguido casi inmediatamente de noTone() cada 4 mseg.
Se está generando un tren de pulsos que, en este caso, sería de 250Hz y totalmente audible.
Luego al quedar estable el contacto sonaría el tono programado hasta que se suelte el pulsador y otra vez se produzcan rebotes.

Y en la simulación solo ocurre con las notas "altas" por esto:

sencillamente porque wokwi permite elegir si se quiere o no simular rebotes (lo cual se agradece) y resulta perfecto para aplicarlo en este caso y que se note el efecto de los rebotes.

La memoria falla, la mia digo.

Para comprobar si son simple rebotes que ponga unos condensadores en paralelo al pulsador ( cerámicos de 100nF ). Así se puede ver si es cosa del código u otra cosa.

Que el micro trabaja así está claro.

Ah, vale, está seleccionado en el simulador que sólo haga rebotes en esos 3 pulsadores.

Sobre los ruidos entiendo lo de los rebotes. Lo que me refiero es que esos ruidos no son simplemente de oirse un tono y cortarse en un tiempo muy corto. Esos ruidos son muy característicos y se llaman glitch y se producen no exactamente por activar y desactivar en un tiempo muy corto si no por cortar la señal cuando no pasa por cero. Imagino que la función tone() en condiciones de tiempo normales hará siempre el final en el siguiente paso por cero tras haber desactivado tone(). Pero si tras un noTone() se vuelve a dar un tone() esa función comienza a generar de nuevo el tone() sin que haya dejado pasar el tiempo suficiente hasta el siguiente paso por cero y cortar entonces produciéndose en ese caso el glitch.
Un tono de mucha duración que terminara cortándose cuando la señal no pasa por cero también produciría un glitch.

Te entendí perfectamente y es muy probable que haya algunos glitchs pero no tengo osciloscopio para comprobarlo, de todos modos lo que se escucha se debe a la "modulación" provocada por el rebote de cada pulsador independiente de que se produzca algún glitch.
Una simple rutina antirrebotes (o capacitores como le gusta a @victorjam ) y fin del problema.

En resumen, el código (con sus defectos) funciona como se espera y no presenta los fallos que describe @alex_520 (salvo la sobre modulación).

Activated esta defina como low , por lo tanto van comportase diferente si la entrada es pull dow o pull up . Si la entrada fuera pul down
se comportara como describe. una nota de fondo y solo se activaran en secuencia . Por tanto hace falta el diagrama de cableado.

No entiendo...
Las entradas están definidas INPUT _PULLUP, dónde ves el conflicto (más allá de que adjunté la simulación funcional)?

es solo una suposición.Depende del cableado del botón si recibe siempre un low o high sin estar presionado, aunque declares la entrada pull up. Fíjate que si el programa esta recibiendo low sin estar presionado , se comportara como lo esta describiendo, que seria igual a que cabiaras tu simulación #define ACTIVATED HIGH

perdón un high sin estar presionado

No me gusta nada el programa ya que bloquea la ejecución del código. Evitando poder hacer otras cosas. Además de que no controla el posible "ruido" del rebote de los contactos de los pulsadores. Aquí tienen mi propuesta con cierto control "anti rebote" y no bloqueante. Con lo que el Arduino podría hacer otras cosas además de "tocar" el piano. Eso sí, lo he cambiado a mi estilo de programación. Respetando los valores de las definiciones de los pines y las frecuencias de las notas.

///////////////////////////////
// Definición de constantes //
/////////////////////////////

const uint8_t pinPiezo = 11;                 // Pin al que se conecta el piezoelectrico.
const uint8_t pinLed = 13;                   // Pin al que se conecta el led.
const uint8_t valorLedEncendido = HIGH;      // Valor de la salida para encender el led.
const uint8_t valorTeclaPulsada = LOW;       // Valor de lectura cuando se pulsa la tecla asociada a la nota.
const unsigned long tiempoAntiRebote = 25UL; // Tiempo en milisegundos para suprimir los rebotes. Siendo este el tiempo mínimo que sonará la nota y que durará el silencio. El UL es para indicar que se un entero largo sin signo.

// Estructura para asignar cada pin y la frecuencia de su nota.
struct PinNota {
  uint8_t pin;         // Pin al que está conectada la tecla (pulsador).
  uint16_t frecuencia; // Frecuencia de la nota que ha de sonar.
};

// Pines asignados a las teclas y frecuencias de las notas.
const PinNota Teclas[] = {
  {10, 262},   // Pin y frecuencia de la nota C.
  { 9, 294},   // Pin y frecuencia de la nota D.
  { 8, 330},   // Pin y frecuencia de la nota E.
  { 7, 349},   // Pin y frecuencia de la nota F.
  { 6, 392},   // Pin y frecuencia de la nota G.
  { 5, 440},   // Pin y frecuencia de la nota A.
  { 4, 493}    // Pin y frecuencia de la nota B.
};

//////////////////////////////////////////////////////////////////
// Constantes calculadas a partir de las constantes anteriores //
////////////////////////////////////////////////////////////////

#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))        // Macro para calcular el número total de elementos de un array.
const size_t cantidadTeclas = SIZEOF(Teclas);       // Cantidad total de notas/teclas de las que se dispone.
const size_t noHayTeclaPulsada = cantidadTeclas;    // Cuando no hay tecla pulsada el valor es el mismo que el número total de teclas.
const uint8_t valorLedApagado = !valorLedEncendido; // Valor de la salida para apagar el led (el contrario de valorLedEncendido).

/////////////////////////
// Variables globales //
///////////////////////

size_t teclaValida = noHayTeclaPulsada;          // Para saber cual es la tecla que ha de sonar.
unsigned long instanteDetectadoNuevaTecla = 0UL; // Guarda en que momento se detectó la nueva tecla pulsada.

void setup()
{
  // Bucle para inicializar como entrada y con resistencia PULL UP todos los pines de las teclas.
  for (size_t i = 0; i < cantidadTeclas; i++) {
    pinMode(Teclas[i].pin, INPUT_PULLUP);
  }
  pinMode(pinLed, OUTPUT);               // Configuramos como salida el pin del led.
  digitalWrite(pinLed, valorLedApagado); // Nos aseguramos de que el led esté apagado.
  noTone(pinPiezo);                      // Nos aseguramos que no se está emitiendo ningún sonido.
}

void loop()
{
  unsigned long instanteActual = millis(); // Obtenemos el instante actual.
  if ((instanteActual - instanteDetectadoNuevaTecla) >= tiempoAntiRebote) { // Vemos si ha pasado tiempo suficiente desde que se detectó una tecla pulsada. No se hará nada mientras no haya pasado ese tiempo.
    size_t teclaDetectada = 0; // Para averiguar qué tecla está pulsada en este momento. Es importante no declarar esta variable dento del siguiente for para que su valor sea accesible después del for.
    for ( ; teclaDetectada < cantidadTeclas; teclaDetectada++) { // Téngase en cuenta que no se define el primer componente del for porque se ha definido justo en la línea anterior. Este bulcle verifica una por una las teclas buscando la primera que se encuentre pulsada.
      if (digitalRead(Teclas[teclaDetectada].pin) == valorTeclaPulsada) { // Si se detecta una tecla pulsada...
        break; // Salimos del bucle sin haber llegado al final.
      }
    }
    if (teclaValida != teclaDetectada) {            // Si la tecla detectada es distinta a la tecla validada por última vez...
      teclaValida = teclaDetectada;                 // La tecla válida pasa a ser la tecla detectada.
      instanteDetectadoNuevaTecla = instanteActual; // Guardamos este tiempo para esperar y evitar los rebotes.
      if (teclaValida == noHayTeclaPulsada) {  // Si no hay tecla válida pulsada.
        noTone(pinPiezo);                      // Apagamos el sonido.
        digitalWrite(pinLed, valorLedApagado); // Apagamos el led.
      }
      else {                                             // Hay una nueva tecla válida pulsada.
        tone(pinPiezo, Teclas[teclaValida].frecuencia); // Hacemos sonar el tono asignado a la tecla pulsada.
        digitalWrite(pinLed, valorLedEncendido);         // Encendemos el led.
      }
    }
  }
}

En esta propuesta, entre otras cosas, en lugar de tener un código que se repite una y otra vez por cada tecla y nota a controlar, lo que hago es utilizar un array de una estructura que contiene información del pin asignado a la tecla (pulsador) y de la frecuencia de la nota que ha de sonar. De esta forma es fácil añadir o quitar notas al programa. Se trabaja con el índice del elemento del array que pertenece a la tecla pulsada. Si el valor de este índice es igual al número de elementos del array, significa que no hay ninguna tecla pulsada. Porque el índice de la primera tecla del array es el cero.

Se recorre el array para hacer el recorrido de la búsqueda de una tecla pulsada. Si se llega al final del recorrido sin encontrar ninguna tecla pulsada, entonces el valor de la variable del bucle es igual al número de elementos del array. Como ya he dicho, esto significa que no hay tecla pulsada.

Dejo enlace al montaje que puso @MaximoEsfuerzo en Wokwi con el programa que propongo. Se puede verificar que ya no hace el ruidito en los tres botones de la derecha ya que tiene un pequeño control anti rebote.

Saludos.