Intento de Creación Caja Musical [SOLUCIONADO]

Buenas a todos, os cuento estoy intentando hacer una caja musical que aparte de hacer sonar unas notas, también haga girar un motor paso a paso, (es una antigua NORIA musical, que estoy intentando modificar para mi sobrinilla)

el programa para las notas, lo tengo, el programa para el motor paso a paso lo tengo. El problema es que al unirlos el motor hace una secuencia de activación de bobinas y se activa la parte musical que al acabar las notas musicales vuelve a activar una secuencia en el motor y otra vez la música.

Mi ilusa idea era que girase el motor mientras sonaban las notas, pero estoy usando delay (Perdón, mis conocimientos no dan para más) y claro creo que ese es uno de los problemas.
el otro que veo es que si hago que el motor gire todo el tiempo de la música, no creo que pueda oir las notas digamos que al ritmo normal de la “canción”.
me podéis echar una mano?

este es el código, me serviría unas orientaciones de como tendría y que tendría que modificar y procuraría yo buscar como se hacer esos cambios. Pero sin una persona que me guíe un poco voy como un pollo sin cabeza la verdad.

/*
  Melody
 
 Plays a melody 
 
 circuit:
 * 8-ohm speaker on digital pin 8
 
 created 21 Jan 2010
 modified 30 Aug 2011
 by Tom Igoe 

This example code is in the public domain.
 
 http://arduino.cc/en/Tutorial/Tone
 
 */
 #define pulsadorPin 4
 int valorPulsador = 0;
 int estadoAC = 0;
 int estadoAN = 0;
 int Interruptor = 0;
 int contador;
 int LED = 3;
 int ValorLed;
 int thisNote;
 #include "pitches.h"

// notes in the melody:
int melody[] = {// las notas que contiene una S son las teclas negras de un piano.
 NOTE_G6, NOTE_G6,  NOTE_AS6,  NOTE_G6, NOTE_G6,  NOTE_AS6,  NOTE_G6, NOTE_AS6, NOTE_DS7,  NOTE_D7, NOTE_C7, NOTE_C7,   NOTE_AS6,  NOTE_F6,  NOTE_G6,  NOTE_GS6, NOTE_F6,  NOTE_F6, NOTE_G6, NOTE_GS6, NOTE_F6,  NOTE_GS6,  NOTE_D7, NOTE_C7, NOTE_AS6,   NOTE_D7,  NOTE_DS7};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  6,8,2.5,8,4,2,6,10,4,3,8,4,4,6,8,4,4,6,8,2.5,6,8,8,8,4,4,2,};
// AÑADIDO PARA EL MOTOR
const int activaA = 8;
const int activaB = 9;
const int activaC = 10;
const int activaD = 11;
int pausa = 30;
bool A = HIGH;
bool D = LOW; 
// HASTA AQUI ES PARA EL MOTOR


void setup() {


  pinMode(pulsadorPin, INPUT); //entrada para activar la noria
  pinMode(3,OUTPUT); // ALTAVOZ
  pinMode(2,OUTPUT); // DE MOMENTO EL LED

// AÑADIDO PARA EL MOTOR
 pinMode(activaA, OUTPUT);
   pinMode(activaB, OUTPUT);
    pinMode(activaC, OUTPUT);
     pinMode(activaD, OUTPUT);

// HASTA AQUI ES LA INSERCION PARA EL MOTOR
  }

void loop() {
  ValorLed = digitalRead(2);


 
 int valor_salida_pwm=0; 
 valor_salida_pwm =40;
 estadoAC = digitalRead(pulsadorPin);//leeremos el estado del pulsador y lo guardamos en la variable EstadoAC
 
 if(estadoAC && estadoAN ==0){ //si estado actual por estado anterior es igual a 0 se ara lo siguiente
     Interruptor = 1 - Interruptor;// 
     delay (100);
 }
estadoAN = estadoAC;   
 
 
 if(Interruptor == 1 ){
   //AÑADIDO PARA EL GIRO DEL MOTOR
//paso 1
digitalWrite(activaA, A);
digitalWrite(activaB, D);
digitalWrite(activaC, A);
digitalWrite(activaD, D);
delay(pausa);

//paso 2
digitalWrite(activaA, A);
digitalWrite(activaB, D);
digitalWrite(activaC, D);
digitalWrite(activaD, A);
delay(pausa);

//paso 3
digitalWrite(activaA, D);
digitalWrite(activaB, A);
digitalWrite(activaC, D);
digitalWrite(activaD, A);
delay(pausa);

//paso 4
digitalWrite(activaA, D);
digitalWrite(activaB, A);
digitalWrite(activaC, A);
digitalWrite(activaD, D);
delay(pausa);
   //HASTA AQUI ES PARA EL MOTOR
    digitalWrite(2, HIGH);
    analogWrite(6, valor_salida_pwm);
        if (contador <=2) {
             contador = contador + 1;
                   for (int thisNote = 0; thisNote < 27; thisNote++){ // to calculate the note duration, take one second 
                       int noteDuration = 1500/noteDurations[thisNote]; // divided by the note type.
                       tone(3, melody[thisNote],noteDuration); //e.g. quarter note = 1000 / 4, eighth note =1000/8, etc.  // to distinguish the notes, set a minimum time between them.
                        int pauseBetweenNotes = noteDuration * 1.6; // the note's duration + 30% seems to work well:
                        delay(pauseBetweenNotes);
                        noTone(3);}} // stop the tone playing:
                else{
                  noTone(3);
                   estadoAC = 0;
                    Interruptor = 0;
                     analogWrite(3, LOW);
                      digitalWrite(2, LOW);}
                    }
    else{ 
       analogWrite(3, LOW);
       estadoAC = 0;
       Interruptor = 0;
       noTone(3);
       contador=0;}}

_3Lullaby_conMotor.ino (3.69 KB)

pitches.h (1.96 KB)

Ve a Documentación => Indice de temas tutoriales => Millis() y también lee máquina de estados.

la combinación de las dos cosas resolverá tu problema pero te aseguro que tienes un buen trabajo para hacerlo.

Hay que eliminar delay() y a la vez programar considerando que el código va a fluir permanentemente y no se va a detener.
Entonces la programación lineal tal como has hecho no sirve porque no puedes hacer que el motor haga algo sino que lo haga pero mientras lo esta haciendo considera que puedes hacer otra cosa.

Es como si vieras todo como un procesamiento paralelo (que en realidad no lo es)
Ahora imagina que tu puedes digiri que hacer en determinado lapsos de tiempo.

Digamos que una secuencia será para atender la melodia.
La melodía tendra entonces pasos que dar.
El paso 1 dura X tiempo y superado ese tiempo ejecutas otra secuencia de la melodia (perdon si se dice acorde, eso si que no es mi fuerte). El tema es que asi vas armando por un lado todo el tema musical. sin pausas aparentes. Esa será una máquina de estados.

La otra es la que acciona el motor. Que tmb tendrá pasos o etapas. Y cada etapa llevará un tiempo.

Lee lo que te he sugerido y luego con esa base encaramos con otra mirada tu código.

Gracias, me pongo en ello.
miro Millis() aunque ya lo estuve mirando y no me quedo muy claro, pero lo mirare donde me comentas que hay no lo hice.
y lo de maquinas de estado, que también lo estuve mirando.
así también una librería protothear, (si no lo escribo mal). que también servía para generar “saltos” entre los programas y poder hacer los procesos seguidos.

pero uno de los problemas que me encuentro es por ejemplo

if(Interruptor == 1 ){
  //AÑADIDO PARA EL GIRO DEL MOTOR
//paso 1
digitalWrite(activaA, A);
digitalWrite(activaB, D);
digitalWrite(activaC, A);
digitalWrite(activaD, D);
delay(pausa);                          <---------- si uso millis() por lo que he entendido.

yo le pregunto a arduino si ha llegado ha un tiempo determinado. si es así, entonces ejecuta, si todavía no ha llegado a ese tiempo no lo ejecutes.
Por lo que me encuentro que si realmente, necesito que haga una espera que es para sonar la melodía con sus tempos.
Ese es uno de mis problemas no consigo ver su funcionamiento de espera, si el de “condición” para ejecutar el codigo que dependa de ese millis().

pero voy ha revisar lo que me comentas haber si me aclaro un poco

Sólo comentar que no es sustituir una función por otra. millis() o micros() sólo da el tiempo transcurrido desde que el Arduino es encendido. Por eso se necesita una variable donde almacenar el dato y hacer un if()

delay() lo que hace es detener todo el funcionamiento, por eso el fallo que tienes con los motores.

gracias a los dos, por las respuestas, de momento estoy en ello.

tengo algo en el tintero pero necesito pulir los tiempos de mantenimiento en las bobinas de los motores.
sigo trabajando cuando lo tenga algo mas avanzado os pregunto.

por ahora tengo asignadas las variables a los delays de los pasos. tengo un problema con como usando millis puedo asignarles los tiempos a cada paso sin que corran todos a la vez.

estoy mirando el tema de asignar diferentes void Paso1, void paso 2, void paso 3, void paso 4. para asignarles los tiempos de espera a cada uno. bueno es una idea haber que tal me sale.

Si la verdad, me suena a medio chino.
pero gracias, intentare buscar lo que me has comentado.
y intentare aplicarlo.
Gracias.

Bueno, fracciono el código.
Os pongo el código para mover el motor paso a paso.
no me funciona, haber si me podéis orientar con ese código.
para poder tener un ejemplo por donde empezar.
decidme por favor donde están los errores.
Y ArduMyth, si ya he visto el código con array, y es mucho mas cómodo y sencillo. pero este tiene varios temporizadores y se complica más.
Si podéis orientarme me sera mas fácil aprender donde están mis errores.

const int activaA = 8;
const int activaB = 9;
const int activaC = 10;
const int activaD = 11;
int pausa = 300;
bool A = HIGH;
bool D = LOW;                                   
int EnQuePasoEstamos =0;
long PrevioMillisPaso =250;
long TiempodeActivacion = 1000;
long ActualizadoElTiempo = millis();




void setup() {
 Serial.begin(9600);
  delay(1000);
  pinMode(activaA, OUTPUT);
   pinMode(activaB, OUTPUT);
    pinMode(activaC, OUTPUT);
     pinMode(activaD, OUTPUT);
  

}

void loop() {
 Serial.print("EnQuePasoEstamos:  ");
 Serial.print(EnQuePasoEstamos );
Serial.println();
  Serial.print("millis:  ");
 Serial.print(millis() );
Serial.println();
 Serial.print("ActualizadoElTiempo:  ");
 Serial.print(ActualizadoElTiempo );
Serial.println();
   Serial.print("PrevioMillisPaso:  ");
 Serial.print(PrevioMillisPaso );
Serial.println();
  delay (10);
 unsigned long tiempoActual = ( millis());


if (EnQuePasoEstamos = 0){
7if(tiempoActual- PrevioMillisPaso < TiempodeActivacion){
PrevioMillisPaso = tiempoActual;

//paso 1
digitalWrite(activaA, A);
digitalWrite(activaB, D);
digitalWrite(activaC, A);
digitalWrite(activaD, D);
//delay(pausa);
EnQuePasoEstamos = 1;
}
}
if (EnQuePasoEstamos = 1){
if(tiempoActual- PrevioMillisPaso < (TiempodeActivacion+20)){
  PrevioMillisPaso = tiempoActual;
//paso 2
digitalWrite(activaA, A);
digitalWrite(activaB, D);
digitalWrite(activaC, D);
digitalWrite(activaD, A);
//delay(pausa);
EnQuePasoEstamos=2;
}}
if(EnQuePasoEstamos=2){

if(tiempoActual- PrevioMillisPaso < (TiempodeActivacion+40)){
PrevioMillisPaso = tiempoActual;
//paso 3
digitalWrite(activaA, D);
digitalWrite(activaB, A);
digitalWrite(activaC, D);
digitalWrite(activaD, A);
//delay(pausa);
EnQuePasoEstamos=3;
}}
if(EnQuePasoEstamos=3){
if(tiempoActual- PrevioMillisPaso < (TiempodeActivacion+50)){
PrevioMillisPaso = tiempoActual;
//paso 4
digitalWrite(activaA, D);
digitalWrite(activaB, A);
digitalWrite(activaC, A);
digitalWrite(activaD, D);
//delay(pausa);
EnQuePasoEstamos=0;
}
}
}

Gracias, ArduMyth aplico tus consejos, veo el ahorro de memoria y una limpieza del código.

Si que queda mas organizado.

const int activaA = 8;
const int activaB = 9;
const int activaC = 10;
const int activaD = 11;
int pausa = 300;

int EnQuePasoEstamos = 0;
int PrevioMillisPaso = 0;
long TiempodeActivacion = 10;
unsigned long ActualizadoElTiempo = 0;




void setup() {
  Serial.begin(9600);
  pinMode(activaA, OUTPUT);
  pinMode(activaB, OUTPUT);
  pinMode(activaC, OUTPUT);
  pinMode(activaD, OUTPUT);


}

void loop() {
  Serial.print("EnQuePasoEstamos:  ");
  Serial.print(EnQuePasoEstamos );
  Serial.println();
  Serial.print("millis:  ");
  Serial.print(millis() );
  Serial.println();
  Serial.print("ActualizadoElTiempo:  ");
  Serial.print(ActualizadoElTiempo );
  Serial.println();
  Serial.print("PrevioMillisPaso:  ");
  Serial.print(PrevioMillisPaso );
  Serial.println();
  delay (10);
  unsigned long tiempoActual =  millis();




  if (EnQuePasoEstamos = 0) {
    if (tiempoActual - PrevioMillisPaso > TiempodeActivacion) {
      //paso 1
      digitalWrite(activaA, HIGH);
      digitalWrite(activaB, LOW);
      digitalWrite(activaC, HIGH);
      digitalWrite(activaD, LOW);
      //delay(pausa);
      EnQuePasoEstamos = 1;
      PrevioMillisPaso = tiempoActual;
    }
  }
  if (EnQuePasoEstamos = 1) {
    if (tiempoActual - PrevioMillisPaso > TiempodeActivacion + 20) {
      //paso 2
      digitalWrite(activaA, HIGH);
      digitalWrite(activaB, LOW);
      digitalWrite(activaC, LOW);
      digitalWrite(activaD, HIGH);
      //delay(pausa);
      EnQuePasoEstamos = 2;
      PrevioMillisPaso = tiempoActual;
    }
  }
  if (EnQuePasoEstamos = 2) {
    if (tiempoActual - PrevioMillisPaso > TiempodeActivacion + 40) {
      //paso 3
      digitalWrite(activaA, LOW);
      digitalWrite(activaB, HIGH);
      digitalWrite(activaC, LOW);
      digitalWrite(activaD, HIGH);
      //delay(pausa);
      EnQuePasoEstamos = 3;
      PrevioMillisPaso = tiempoActual;
    }
  }
  if (EnQuePasoEstamos = 3) {
    if (tiempoActual - PrevioMillisPaso > TiempodeActivacion + 50) {
      //paso 4
      digitalWrite(activaA, LOW);
      digitalWrite(activaB, HIGH);
      digitalWrite(activaC, HIGH);
      digitalWrite(activaD, LOW);
      //delay(pausa);
      EnQuePasoEstamos = 0;
      PrevioMillisPaso = tiempoActual;
    }
  }
}

Gracias.

Gracias ArduMyth.
veo el programa y creo saber como funciona.

pero te voy ha preguntar por este que estoy intentando montar, es una simplificación del de los pasos del motor como lo tengo montado.
es para poder entender como funciona.

una de las cuestiones que me surge es que con millis veo que no se puede buscar el numero exacto.
y en este programa se queda encendido el led 2 por justamente usar los signos <.
hay alguna forma de conseguir la exactitud en la lectura.

unsigned long time;
unsigned long t=600;
unsigned long t1=300;
unsigned long t2=0;
unsigned long t3=700;
int tiempoDeterminado = 100;
int contador = 0;

void setup() {
Serial.begin(9600); // Inicio el puerto serie
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
}

void loop() {
Serial.print("time: ");
Serial.println(time);
Serial.print("t: ");
Serial.println(t);
Serial.print("t1: ");
Serial.println(t1);  
Serial.print("t2: ");
Serial.println(t2); 
Serial.print("t3: ");
Serial.println(t3);
Serial.print("contador: ");
Serial.println(contador);  

  time=millis();
  
if (contador<3)
{
   contador = contador+1;
if (time-t < tiempoDeterminado){
    digitalWrite(2,HIGH);
    t = time+600;
  }
    
if (time-t1 < tiempoDeterminado){
    digitalWrite(3,HIGH);
    t1 = time+300;
  }
    
if (time-t2 < tiempoDeterminado){
    digitalWrite(4,HIGH);
    t2 = time;
  }
     
if (time-t3 < tiempoDeterminado){
    digitalWrite(4,LOW);
    digitalWrite(3,LOW);
    digitalWrite(2,LOW);
     t3 = time+700;
  }
     
}
}

Si, estoy de acuerdo con lo ultimo que has comentado, practica, practica y practica.

por el momento solo puedo pedirte que tengas un poco de paciencia, ya intento pillar las ideas, pero por ahora me falta info. por ejemplo.

el signo [ ? ] ¿que es?, lo busco pero no lo encuentro.

después (sizeof(x) / sizeo(x[0])) "comando" que ni conocía,
veo que es para coger los valores de la matriz, supongo que el primero es las fila y el segundo la columna, ¿verdad? .
Pero el [0] ¿como cambia de valor?.

La x no veo cuando se le asigna el valor, si veo que en la linea 10 hay un SIZE(pin) pero no se si hay se le asigna el valor a x.

Perdona pero si este es mi codigo

if (time-t < tiempoDeterminado){
    digitalWrite(2,HIGH);
    t = time+600;
  }

no es lo que me comentas o es que tendría que poner.

o es este?, porque entonces no te había entendido la primera vez.

if (contador<3)
{
   contador = contador+1;
if (time-t < tiempoDeterminado){
    digitalWrite(2,HIGH);
    t = time+600;
  }
    
if (time-t1 < tiempoDeterminado){
    digitalWrite(3,HIGH);
    t1 = time+300;
  }
    
if (time-t2 < tiempoDeterminado){
    digitalWrite(4,HIGH);
    t2 = time;
  }
     
if (time-t3 < tiempoDeterminado){
    digitalWrite(4,LOW);
    digitalWrite(3,LOW);
    digitalWrite(2,LOW);
     t3 = time+ 1000;
     contador = 0;
  }
 time=millis();    
}
}

Gracias, me lo miro ahora.

Gracias, por el tiempo prestado.
Creo que ya lo tengo solucionado.
ahora solo me falta depurar para mejorar el programa.
por lo que yo este post creo que ya puede cerrarse