SOLUCIONADO Dònde colocar la alarma sonora dentro del còdigo?

Hola a todos:

Esta vez les molesto pues estoy tratando de hacer un ejercicio orientado en el cual debo realizar una alarma muy rudimentaria pero que resulta muy ùtil en estos mis primeros pasos con Arduino.

La alarma consiste en controlar un interruptor magnètico o reed switch, conectado al pin D4 de Arduino, que al abrirse la puerta o la ventana debe disparar una alarma, encendiendo dos leds rojos y dos leds amarillos alternativamente.

Simultàneamente, Y AQUI ES DONDE ESTA EL PROBLEMA, un buzzer o zubador conectado el pin D11, debe sonar.

Y digo que este es el problema pues lo hace todo, solo que no simultaneamente. Es decir primero encienden los leds y luego suena la alarma.

En el ejerciciono exigen nada al respecto, pero creo que no me deberìa conformar y busar, con vuestra ayuda claro, la forma de que la alarma suene mientras estèn parpadeando los leds.

Les dejo el còdigo, que sè no es perfecto, pero hasta aquì lo hace todo, la verdad, solo que no lo hace simultàneamente.

Quizàs alguno me pueda dar una sugerencia de dònde sea mejor colocar la secuencia que hace sonar el buzzer dentro del còdigo.

Desde ya muchas gracias y buen trabajo!!!!

/*---------------------------------------------------
   PRACRICA 10, EJERCICIO 1: INTERRUPTOR MAGNETICO - LADRONES EN CASA!!!
  --------------------------------------------------
   Programa que genera una alarma visual con dos leds rojos
   y dos leds amarillos, conectados a los pines d2 y d3 respectivamente.
   
   Tambièn tendrà una Alarma sonora con un buzzer en pin d11.
   
   Se activa la alarma con un codigo de 4 dìgitos por el serial
   mostrando en pantalla "Alarma Activada", cuando detecta la intrusiòn
   (reed switch) y està activada realiza el parpadeo y la sirena, mostrado por pantalla
   "Sistema disparado", hasta que por el serial llega el còdigo de 4 dìgitos para desactivar
   mostrando en pantalla "Alarma Desactivada"
   
   ejemplo: escribe 1111 por el monitor serial, significa activar alarma
            escribe 0000 por el monitor serial, significa descativar alarma
   
   rev.2-> tratar de introdcir la parte de la alarma sonora con un buzzer en el pin 11, que 
   se debe activar durante todo el tiempo que estè "disparado el sistema"
*/

//-----------------------------------------------------
//Declarar puertos de entrada y salida, variables, etc.
//-----------------------------------------------------

int contacto = 4;            // declaro el pin d4 asociado al reed switch
int ledRojo = 2;             // declaro el pin d2, donde estaràn los leds rojos
int ledAmarillo = 3;         // declaro el pin d3, donde estaràan los led amarillos
int buzzer = 11;             // pin donde està conectado el buzzer a traves de 220ohm
int frecuencia1 = 400;       // aquì declaro el valor de la frecuencia 1 a utilizar
int frecuencia2 = 700;       // aquì declaro el valor de la frecuencia 2 a utilizar
boolean AlarmActiva = false; // declaro una bandera que serà verdadera cuando el user active la alarma
boolean intruso = false;     // declaro una bandera para la toma de decisiones mas tarde
String leer;                 // declaro una cadena de caracteres para almacenar el còdigo act o desact

//------------------------------------
//Funciòn principal o de configuraciòn
//------------------------------------

void setup()
{
  pinMode(contacto, INPUT);    // declaro el pin d4, donde està el reed switch, como entrada
  pinMode(ledRojo, OUTPUT);    // declaro el pin d2, donde està el led Rojo como salida
  pinMode(ledAmarillo, OUTPUT);// declaro el pin d3, donde està el led Amarillo como salida
  // pinMode (buzzer, OUTPUT); // se puede omitir en este caso pues el pin 11 ya viene para PWM
  Serial.begin(9600);          // inicializo la comunicaciòn serial a 9600 baudios
}

//--------------------
//Funciòn cìclica
//--------------------

void loop()
{
  if (Serial.available() > 0);           // veo si llega algùn dato por el monitor serial
  {
    leer = Serial.readStringUntil('\r'); // leo lo q hay hasta el return
    Serial.println(leer);                // lo escribo para verlo en la pantalla
    if (leer == "1111" && !AlarmActiva) //pregunto si era el cod. para encender y que la alarma
                                        //no estuviera ya activada
    {
      AlarmActiva = true;               // cambio la bandera
      intruso = false;                  // cambio bandera, alarma activa, no intruso
      Serial.println ("Alarma Activada!!!");  // muestro por el serial q la alarma ha sido activada
    }
    else if (leer == "0000" && AlarmActiva) // si era 0000 y era activa, desactivo todo
    {
      Serial.println(leer);                // lo escribo para verlo en la pantalla
      AlarmActiva = false;                 // pongo la bandera descativada
      intruso = false;                     // reseteo intruso
      Serial.println ("Alarma Desactivada");  // muestro por el serial q la alarma ha sido Desactivada
    }
    else if (digitalRead(contacto) == LOW && AlarmActiva) // pregunto si el pin 2 se puso a 0v, por acercar el imàn
                                                          // y que sea Activa la Alarma
    {
      intruso = true;                        // se ha detectado un Intruso
      Serial.println("Sistema violado...INTRUSO...!!!");
      while (intruso == true && AlarmActiva) // mientras haya intruso y no se apague la alarma, parpadean leds
                                             // y suena la alarma
      {
        for (int i=0;i<=6;i++)
        {
          digitalWrite(ledRojo, HIGH);       // parpadea led rojo 6 veces
          delay(20);
          digitalWrite(ledRojo, LOW);
          delay(20);
         }
        for (int i=0;i<=7;i++)
        {
          digitalWrite(ledAmarillo, HIGH);       // parpadea led amarillo 6 veces
          delay(20);
          digitalWrite(ledAmarillo, LOW);
          delay(20);
         }

//-------------------------------------------------------------------------------
// ESTA ES LA PARTE DEL CODIGO QUE NO SE DONDE UBICAR 
       
        tone(buzzer, frecuencia1); // emite sonido a la frecuencia 1
        delay (1000);              // suena por un segundo
        tone(buzzer, frecuencia2);// emite sonido a la frecuencia 2
        delay (1000);             // suena por un segundo
        noTone(buzzer);          // apago el buzzer 
        
// HASTA AQUI LA PARTE QUE NO SE DONDE UBICAR DENTRO DEL CODIGO DE MANERA QUE LA 
// ALARMA SUENE MIENTRAS PARPADEAN LOS LEDS
//-----------------------------------------------------------------------------
  
        leer = Serial.readStringUntil('\r'); // vuelvo a leer lo q hay hasta el return
                                             // para ver si el usuario descativò la alarma
        if (leer == "0000")                  // pregunto si còdigo es el de desactivaciòn
        {
          AlarmActiva = false;                    //si el usuario apagò, cambio la bandera
          intruso = false;                        // cambio la bandera
          digitalWrite(ledRojo, LOW);             // mantengo rojo apagado
          digitalWrite(ledAmarillo, LOW);         // mantengo amarillo apagado
          Serial.println ("Alarma Desactivada");  // muestro por el serial q la alarma ha sido Desactivada
        }
      }
    }
  }
}
// Fin del programa

lograr que suene el Buzzer y parpadeen los leeds usando delay no es facil pero tampoco imposible.
Deberías encontrar el tiempo minimo de los dos y establecer cada cuantas veces parpadea un led y debe o no activarse el buzzer.

Esto es una tontería

for (int i=0;i<=6;i++)
        {
          digitalWrite(ledRojo, HIGH);       // parpadea led rojo 6 veces
          delay(20);
          digitalWrite(ledRojo, LOW);
          delay(20);
         }

nadie ve 20 mseg prendido o apagado un led o se ve? a mi me parece una tontería, pero tal vez juzgue mal.
De todos modos tienes que crear una máquiina de estados para hacer que todo funcione, y mas fácil sería que funcione con millis()

A ver si esto funciona

/*---------------------------------------------------
   PRACRICA 10, EJERCICIO 1: INTERRUPTOR MAGNETICO - LADRONES EN CASA!!!
  --------------------------------------------------
   Programa que genera una alarma visual con dos leds rojos
   y dos leds amarillos, conectados a los pines d2 y d3 respectivamente.
   
   Tambièn tendrà una Alarma sonora con un buzzer en pin d11.
   
   Se activa la alarma con un codigo de 4 dìgitos por el serial
   mostrando en pantalla "Alarma Activada", cuando detecta la intrusiòn
   (reed switch) y està activada realiza el parpadeo y la sirena, mostrado por pantalla
   "Sistema disparado", hasta que por el serial llega el còdigo de 4 dìgitos para desactivar
   mostrando en pantalla "Alarma Desactivada"
   
   ejemplo: escribe 1111 por el monitor serial, significa activar alarma
            escribe 0000 por el monitor serial, significa descativar alarma
   
   rev.2-> tratar de introdcir la parte de la alarma sonora con un buzzer en el pin 11, que 
   se debe activar durante todo el tiempo que estè "disparado el sistema"
*/

//-----------------------------------------------------
//Declarar puertos de entrada y salida, variables, etc.
//-----------------------------------------------------

int contacto = 4;            // declaro el pin d4 asociado al reed switch
int ledRojo = 2;             // declaro el pin d2, donde estaràn los leds rojos
int ledAmarillo = 3;         // declaro el pin d3, donde estaràan los led amarillos
int buzzer = 11;             // pin donde està conectado el buzzer a traves de 220ohm
int frecuencia1 = 400;       // aquì declaro el valor de la frecuencia 1 a utilizar
int frecuencia2 = 700;       // aquì declaro el valor de la frecuencia 2 a utilizar
boolean AlarmActiva = false; // declaro una bandera que serà verdadera cuando el user active la alarma
boolean intruso = false;     // declaro una bandera para la toma de decisiones mas tarde
String leer;                 // declaro una cadena de caracteres para almacenar el còdigo act o desact
unsigned long startLed;
unsigned long startBuzzer;
//------------------------------------
//Funciòn principal o de configuraciòn
//------------------------------------

void setup()
{
  pinMode(contacto, INPUT);    // declaro el pin d4, donde està el reed switch, como entrada
  pinMode(ledRojo, OUTPUT);    // declaro el pin d2, donde està el led Rojo como salida
  pinMode(ledAmarillo, OUTPUT);// declaro el pin d3, donde està el led Amarillo como salida
  // pinMode (buzzer, OUTPUT); // se puede omitir en este caso pues el pin 11 ya viene para PWM
  Serial.begin(9600);          // inicializo la comunicaciòn serial a 9600 baudios
}

//--------------------
//Funciòn cìclica
//--------------------

void loop()
{
  if (Serial.available() > 0);           // veo si llega algùn dato por el monitor serial
  {
    leer = Serial.readStringUntil('\r'); // leo lo q hay hasta el return
    Serial.println(leer);                // lo escribo para verlo en la pantalla
    if (leer == "1111" && !AlarmActiva) //pregunto si era el cod. para encender y que la alarma
                                        //no estuviera ya activada
    {
      AlarmActiva = true;               // cambio la bandera
      intruso = false;                  // cambio bandera, alarma activa, no intruso
      Serial.println ("Alarma Activada!!!");  // muestro por el serial q la alarma ha sido activada
    }
    else if (leer == "0000" && AlarmActiva) // si era 0000 y era activa, desactivo todo
    {
      Serial.println(leer);                // lo escribo para verlo en la pantalla
      AlarmActiva = false;                 // pongo la bandera descativada
      intruso = false;                     // reseteo intruso
      Serial.println ("Alarma Desactivada");  // muestro por el serial q la alarma ha sido Desactivada
    }
    else if (digitalRead(contacto) == LOW && AlarmActiva) // pregunto si el pin 2 se puso a 0v, por acercar el imàn
                                                          // y que sea Activa la Alarma
    {
      intruso = true;                        // se ha detectado un Intruso
      Serial.println("Sistema violado...INTRUSO...!!!");
      while (intruso == true && AlarmActiva) // mientras haya intruso y no se apague la alarma, parpadean leds
                                             // y suena la alarma
       avisoLedBuzzer(); // esto funcionará si no agregas un solo delay en el loop u otra rutina
        
        
// HASTA AQUI LA PARTE QUE NO SE DONDE UBICAR DENTRO DEL CODIGO DE MANERA QUE LA 
// ALARMA SUENE MIENTRAS PARPADEAN LOS LEDS
//-----------------------------------------------------------------------------
  
        leer = Serial.readStringUntil('\r'); // vuelvo a leer lo q hay hasta el return
                                             // para ver si el usuario descativò la alarma
        if (leer == "0000")                  // pregunto si còdigo es el de desactivaciòn
        {
          AlarmActiva = false;                    //si el usuario apagò, cambio la bandera
          intruso = false;                        // cambio la bandera
          digitalWrite(ledRojo, LOW);             // mantengo rojo apagado
          digitalWrite(ledAmarillo, LOW);         // mantengo amarillo apagado
          Serial.println ("Alarma Desactivada");  // muestro por el serial q la alarma ha sido Desactivada
        }
      }
    }
  }
}
// Fin del programa

void avisoLedBuzzer() {
 static byte estadoLed = 0;
 static byte estadoBuzzer = 0;


 switch (estadoLed) {
 case 0: digitalWrite(ledRojo, HIGH);       // parpadea led rojo 6 veces
 startLed = millis();
 estadoLed = 1;
 break;
 case 1: if (millis() - startLed > 20) {
 estadoLed = 2;
 digitalWrite(ledRojo, LOW);
 startLed = millis();
 }
 break;
 case 2: if (millis() - startLed > 20) {
 if (cont++ <= 6)
 estadoLed = 0;
 else 
 estadoLed = 3;
 }
 break;
 case 3: digitalWrite(ledAmarillo, HIGH);       // parpadea led rojo 6 veces
 startLed = millis();
 estadoLed = 4;
 break;
 case 4: if (millis() - startLed > 20UL ) {
 estadoLed = 5;
 digitalWrite(ledAmarillo, LOW);
 startLed = millis();
 }
 break;
 case 5: if (millis() -  startLed > 20UL) {
 if (cont++ <= 7)
 estadoLed = 3;
 else 
 estadoLed = 0; // vuelvo a comenzar
 }
 break;
 }
 switch (estadoBuzzer) {
 case 0: tone(buzzer, frecuencia1); // emite sonido a la frecuencia 1
 startBuzzer = millis();
 estadoBuzzer = 1;
 break;
 case 1: if (millis() - startBuzzer > 1000UL) {
 estadoLed = 2;
 tone(buzzer, frecuencia2);// emite sonido a la frecuencia 2
 startBuzzer = millis();
 }
 break;
 case 2: if (millis() - startBuzzer > 1000UL) {
 noTone(buzzer);          // apago el buzzer 
 estadoBuzzer = 3;
 } 
 break;
 case 3: 
 default: break; // no hago nada.
 }
       
}

EDITADO por consejo de IgnoranteAbsoluto

Hola Surbyte:
Gracias por responder.

Te comento que si se ve!!...., te has fijado en los autos de policìa y/o ambulancias en los que las luces a led de sus balizas parpadean muy ràpido? bueno esa parte del còdigo los imita bastante....jajaja... se vè, te lo aseguro, no te subo un video pues serìa ocupar espacio precioso en el forum.

Nunca he usado la funciòn millis(), voy a estudiar eso, tampoco recuerdo què es una màquina de estado aunque lo he oìdo o leìdo. Verè eso tambièn.

De todas formas, creo que en la primera parte me diste la respuesta: no serà fàcil lograr que los dos procesos se ejecuten SIMULTANEAMENTE, se acercaràn ajustando los tiempos, pero nunca serà simultàneo, lògicamente y eso lo entiendo.

El ejercicio pedìa que un buzzer sonara y los leds paradearan, para avisar y eso lo hace. Solo querìa que funcionara màs fluìdo, mas cercano a la realidad que vemos por ahì en ambulancias y bomberos. (claro que los bomberos y ambulancias tienen un sistema que controla las luces y otro que controla la sirena). Es que me he vuelto un poco caprichoso e insisto siempre en introducir variantes... me estarè poniendo viejo....?

En fin que voy a seguir tu consejo y estudiar un poco mas... (millis()).

Si al final no lo lograra, puedo, como alternativa: antes de encender los les hago sonar el buzzer con PWM y al finalizar el ciclo de los leds lo apago..... puede ser una variante... si el ladròn se va a asustar y desistir en el intento de robar en una casa, no serà por ese detalle.

Otra vez gracias por tu tiempo y comentarè si hay avances.
Buen trabajo!

Hola Surbyte:

Disculpa pero mientras escribìa la respuesta entro tu còdigo....lo voy a ver y comento los resultados.

Muchas gracias

Hola Surbyte y demàs compañeros:

Confieso que no he tenido mucho tiempo en estos dìas, sòlo el indispensable para probar el còdigo que me has sugerido, no he estudiado nada de la funciòn "millis()" todavìa pero querìa probarlos y responderles si funcionaba bien, como deber de todo buen miembro del forum... quien sabe si le pueda servir a alguien mas?

He copiado textualmente las lìneas que has incluìdo en mi còdigo pero me da el siguiente error al compilarlo:

exit status 1

  • 'avisoLedBuzzer' was not declared in this scope*

Me parece que tiene que ver con que al inicio no hemos declarado que vamos a usar la subrutina llamada "avisoLedBuzzer", digo me parece pues esta serìa a primera vez que utilizo una subrutina.

No serà que hay que declarar algo del tipo #include o algo asì???

Me disculpo por la demora en responder y por el desconocimiento, recuerden que soy principiante y autodidacta.

Muchas gracias,
Juan Carlos

Hola a todos:

Solucionado: el error de compilaciòn me lo daba el hecho de que yo automàticamente copiè el còdigo como lo habìa sugerido SURBYTE, con la subrutina "avisoLedBuzzer" desarrollada al final del còdigo.

Me di cuenta de que el error sale cuando yo llamo a ejecutar una funciòn o subrutina que Arduino no ha "visto" todavìa pues no ha llegado al final donde estaba declarada.

Pues solucionè todo quitàndola de allì y colocàndola justo esre el void setup y el void loop. De esta manera, cuando Arduino entra a ejecutar el lazo principal, void loop, ya tiene cargada la subrutina.

El còdigo funciona, solo que solo parpadea el led rojo, pero eso ya lo trabajarè, seràa qua hay que justar algo, pero se ha resuelto el problema inicial, que era que el parpadeo y el sonido se ejecutaran al mismo tiempo.

Gracias a Surbyte y al resto de los compañeros por su tiempo

Buen trabajo!

Cuando respondemos muchas veces o la gran mayoría no probamos los códigos asi que estan sujetos a pequeños olvidos o fallos que el interesado debe resolver.
Eso que hice fue una máquina de estados, que permite que cosas ocurran pero sin usar delay. Cada estado es único y solo llama a otro cuando se cumple determinada condición.
Ve a documentación y lee la teoría de las Maquinas de estado para que la comprendas y ahora en conjunto veas que esta manera de trabajar no detiene el flujo de tu programa.

Lo harè, seguro, gracias otra vez.... ya tienes tu merecido Karma...
Buen rabajo!

Recomiendo que veas el código que te sugerí originalmente en el post#2 porque @IgnoranteAbsoluto me hizo ver un problema que puede ser trivial en un instante pero si estamos haciendo un control de algo se puede producir un grave error por desbordamiento

IgnoranteAbsoluto:
Vale, ahora vamos a tratar de librarnos del "efecto desbordamiento" en dos pasos. Para ello primero buscamos y cambiamos las tres líneas de código que ponen:
t = millis() + PAUSA;
... por:
t = millis();

Una vez cambiada esas tres líneas (simplemente quitar los tres "+ PAUSA") nos queda sólo cambiar las dos comparaciones. Para ello cambiamos los dos if:
if (millis() > t) {
... por:
if (millis() - t > PAUSA) {