Sistema de alarma con bajo voltaje con sensor de tensión

Hola a todos!
Estoy con una confusión por ser nuevo en programación de Arduino. Quiero armar un sistema de alarma son un sensor de tensión "zmpt101b", que cuando baje de cierto nivel de tensión suene una sirena o encienda un indicador, seria una salida a un modulo de relé.
Logre hacer funcionar correctamente el sensor y puedo ver los parámetros de tensión en el monitor serie, pero después al querer hacer la lógica con la función "if y else" y hacer encender el relé cuando el nivel de tensión sea menor al establecido, el relé queda siempre activado.
Dejo el código de programación a ver si alguno con mas experiencia puede ver en que me estoy equivocando.
Muchas gracias!

#include <Filters.h>
float testFrequency = 50;                     // Frecuencia (Hz)
float windowLength = 40.0/testFrequency;     // promedio de la señal
int Sensor = 0; //A0
float intercept = -0.04; // para ser ajustado en base a las pruebas de calibración
float slope = 0.0405; // para ser ajustado en base a las pruebas de calibración
float volts; // Voltaje
unsigned long periodo = 1000; // tiempo de lectura
unsigned long tiempoAnterior = 0;
float Nivel = volts;       // nivel de volts

int AlarmaLowLevel = 100;  // Si baja de este nivel activa alarma pin 7

int Alarma = 7; //salida rele 1, por bajo nivel 


void setup() {
  pinMode (Alarma, OUTPUT); //definir rele 1 como salida, activa alarma o desactiva
  Serial.begin(9600);
  delay(5000);
  }

void loop() {
    
    RunningStatistics inputStats;  //inicio sensor de voltaje 
    inputStats.setWindowSecs(windowLength);   //inicio sensor de voltaje 
    while(true) {   
    Sensor = analogRead(A1);  //leer pin analógico
    inputStats.input(Sensor);  
    if((unsigned long)(millis() - tiempoAnterior) >= periodo) {          
      volts = intercept + slope * inputStats.sigma(); //offset y amplitud
      volts = volts*(40.3231);                        //calibración  
      Serial.print("\tVoltaje: ");  // solo para ver voltaje en monitor serie
      Serial.println(volts);  // solo para ver voltaje en monitor serie
      tiempoAnterior = millis();
    }
  }
  
    if(AlarmaLowLevel > Nivel) //inicio logica de alarma
 {
    digitalWrite(Alarma,LOW);
      }
    else
    {
    digitalWrite(Alarma,HIGH);
      }
}

Así a vistazo rápido,

while (true)
{
}

de ahi no sale nunca, se quedará para siempre en ese bucle y no hará la parte de abajo de la alarma.

1 Like

por otro lado, en el IF inferior comparas dos constantes. no veo que la variable "Nivel" estés asignándola.

#include <Filters.h>
float testFrequency = 50;                     // Frecuencia (Hz)
float windowLength = 40.0/testFrequency;     // promedio de la señal
int Sensor = 0; //A0
float intercept = -0.04; // para ser ajustado en base a las pruebas de calibración
float slope = 0.0405; // para ser ajustado en base a las pruebas de calibración
float volts; // Voltaje
unsigned long periodo = 1000; // tiempo de lectura
unsigned long tiempoAnterior = 0;
float Nivel = volts;       // nivel de volts

int AlarmaLowLevel = 100;  // Si baja de este nivel activa alarma pin 7

int Alarma = 7; //salida rele 1, por bajo nivel 


void setup() {
  pinMode (Alarma, OUTPUT); //definir rele 1 como salida, activa alarma o desactiva
  Serial.begin(9600);
  delay(5000);
  }

void loop() {
    
    RunningStatistics inputStats;  //inicio sensor de voltaje 
    inputStats.setWindowSecs(windowLength);   //inicio sensor de voltaje 
   
    Sensor = analogRead(A1);  //leer pin analógico
    inputStats.input(Sensor);  
    if((millis() - tiempoAnterior) >= periodo) {          
      volts = intercept + slope * inputStats.sigma(); //offset y amplitud
      volts = volts*(40.3231);                      //calibración  
      Nivel = volts;
      Serial.print("\tVoltaje: ");  // solo para ver voltaje en monitor serie
      Serial.println(volts);  // solo para ver voltaje en monitor serie
      tiempoAnterior = millis();
  }
  
    if(AlarmaLowLevel > Nivel) //inicio logica de alarma
 {
    digitalWrite(Alarma,LOW);
      }
    else
    {
    digitalWrite(Alarma,HIGH);
      }
}

Probalo ahora.
Como dijo @DanX3 tenía un while() innecesario que lo trababa todo y olvidaste reasignar Nivel.

Por otro lado todos los parametros del primer if() ya son unsigned long por lo que no es necesario forzar el tipo.

Saludos

1 Like

Hola muchas gracias, ahora mismo lo pruebo sin el while. El parámetro Nivel lo tengo asignado al comienzo como los "volts" del sensor. No se si estará bien asignado, porque copie el código del sensor donde esta la calibración del mismo y utilizo esa variable ya calculada.

Hola muchas gracias por la respuesta, la variable nivel la tengo asignada arriba como la salida de "volts", ahora nos si estará bien asignada. Porque copie el código del sensor de un ejemplo, y al tener una calibración utilice directamente la salida ya calculada como mi nivel.

Ahí lo probé, y sin el while() no me lee el sensor los volts directamente.

Veo que la librería Filters.h es especial en como toma los datos asi que ese while(1) que a todos nos molesta, en realidad tiene un break cuando la ventana de tiempo se termina.

A ver si esto funciona, simplemente poniendo las comparación luego de cuando muestras los datos.


void loop() {

  RunningStatistics inputStats;           // inicio sensor de voltaje
  inputStats.setWindowSecs(windowLength); // inicio sensor de voltaje
  while (true) {
    Sensor = analogRead(A1); // leer pin analógico
    inputStats.input(Sensor);
    if ((unsigned long)(millis() - tiempoAnterior) >= periodo) {
      volts = intercept + slope * inputStats.sigma(); // offset y amplitud
      volts = volts * (40.3231);                      // calibración
       Nivel = volts;    // <=== esto tmb es importante
      Serial.print("\tVoltaje: "); // solo para ver voltaje en monitor serie
      Serial.println(volts);       // solo para ver voltaje en monitor serie
      if (AlarmaLowLevel > Nivel) { // inicio logica de alarma
          digitalWrite(Alarma, LOW);
      } else {
          digitalWrite(Alarma, HIGH);
      }
      tiempoAnterior = millis();
    }
  }
}
1 Like

Funciono! muchísimas gracias! Aprovecho a hacerte una consultas de unas dudas que me surgen.
Veo que pones "Nivel = volts" dentro del loop, era eso en si el problema? o es que debía incluir la función If dentro de toda la función "while"
Y si no es mucha molestia, cuando arranca el sensor por unos 3 segundos toma al principio mediciones erradas, que no son las verdaderas y esto hace que la alarma actué, como seria la forma de darle un delay a toda la programación así al enchufar el circuito no empieza sonando la alarma hasta que se estabilice la medición del sensor.
Una vez mas, muchísimas gracias!

Si ese era el mayor de los problemas. Luego poner los condicionales dentro es anecdótico.
Me gusta mas poner que se haga un cambio si realmente lo hubo, que no este como loco cambiando.
Deberias poner una histéresis o sea.. que cambie o se active para un lado como esta pero que se apague no cuando no se de la condición

 if (AlarmaLowLevel > Nivel) 

sino cuando se de esta

 if (AlarmaLowLevel < (Nivel-1.0)) 
1 Like

No sería mejor

#include <Filters.h>
float testFrequency = 50;                     // Frecuencia (Hz)
float windowLength = 40.0/testFrequency;     // promedio de la señal
int Sensor = 0; //A0
float intercept = -0.04; // para ser ajustado en base a las pruebas de calibración
float slope = 0.0405; // para ser ajustado en base a las pruebas de calibración
float volts; // Voltaje
unsigned long periodo = 1000; // tiempo de lectura
unsigned long tiempoAnterior = 0;
float Nivel = volts;       // nivel de volts

int AlarmaLowLevel = 100;  // Si baja de este nivel activa alarma pin 7

int Alarma = 7; //salida rele 1, por bajo nivel 


void setup() {
  pinMode (Alarma, OUTPUT); //definir rele 1 como salida, activa alarma o desactiva
  Serial.begin(9600);
  delay(5000);

    RunningStatistics inputStats;  //inicio sensor de voltaje 
    inputStats.setWindowSecs(windowLength);   //inicio sensor de voltaje 
}

void loop() {

    Sensor = analogRead(A1); // leer pin analógico
    inputStats.input(Sensor);
    if ((millis() - tiempoAnterior) >= periodo) {
      volts = intercept + slope * inputStats.sigma(); // offset y amplitud
      volts = volts * (40.3231);                      // calibración
       Nivel = volts;    // <=== esto tmb es importante
      Serial.print("\tVoltaje: "); // solo para ver voltaje en monitor serie
      Serial.println(volts);       // solo para ver voltaje en monitor serie
      if (AlarmaLowLevel > Nivel) { // inicio logica de alarma
          digitalWrite(Alarma, LOW);
      } else {
          digitalWrite(Alarma, HIGH);
      }
      tiempoAnterior = millis();
    }
}
    

?

Porque

while(true)

dentro del loop()...

Saludos

1 Like

Sin el while no funciona el sensor, no toma lectura. Creo que como dijo el compañero @Surbyte, la librería Filters lo utiliza.

La librería Filters.h lo exige de ese modo, por eso no funciona sin el while. Deben llenarse las muestras y luego libera.

Y cuál sería la diferencia @Surbyte ? No entiendo...

Es el mismo código solo que moví las 2 lineas que se ejecutan solo una vez al setup() y obviamente saqué el while() que ya no sería necesario.

De hecho el ejemplo que viene con la librería no usa while() para nada.

Saludos

Mira la librería y vas a ver que entre en ese while(true) que parece infinito pero como tiene una ventana de lectura, termina el saliendo con algun break. No lo busqué porque no es importante para mi en este momento. Pero asi funciona!!
Yo habia hecho lo mismo que vos, vi que te dijo que no funcionaba y entonces miré la librería y ahi me di cuenta como trabaja.

Como sueles decir "Aclaren de dónde descargaron la librería para evitar pérdidas de tiempo" o algo así.

A falta de aclaración miraba la librería Filters que se encuentra en el gestor de la IDE, o sea la de hideakitai, y resultó que ésta es Filters-master de ThamKhao.

Mejor me dedico a tejer al crochet...

Saludos

Me pasó lo mismo.
Ya te das cuentas que agregar el link de donde se obtuvo la librería es muy importante y nos ahorra tiempo a los que respondemos.

La verdad es que es una cosa muy chula, como una mini estación. Los conocimientos sobre este tema te serán muy útiles en la vida. Me encontré con esto cuando estaba instalando un sistema de seguridad ajax, sólo con sensores. Quiero que mi hijo se dedique a la ingeniería eléctrica o a la programación. Es una de las áreas más demandadas de la vida en este momento. Creo que es muy digno que un hombre sea capaz de entenderlo, al menos para sí mismo.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.