PROBLEMA con falsos pulsos que disparan interrupciones

Hola!
Soy nuevo en el foro, y relativamente nuevo en el mundo Arduino, aunque tengo muchisima experiencia en programación C.
Estoy realizando un pequeño desarrollo para mi empresa, con el objetivo de controlar automáticamente unas cargas de agua.
El proceso es simple, al pulsar un botón, abro una electroválvula con un relé, y utilizo un caudalímetro hall para controlar el flujo de agua. Al llegar a la cantidad de litros configurada, cierro la electrovalvula, y el proceso queda a la espera de que se vuelva a tocar el botón para repetir la carga.
Todo parecía funcionar bien hasta que realice la primer prueba con agua, y me di cuenta que no sensaba bien los litros. Revise el codigo y la ecuación para el calculo mil veces pero todo esta bien.
Decidí conectar nuevamente el Arduino a la compu y hacer un debug imprimiendo las variables en cada ciclo.
Alli descubri que recibia pulsos que hacian disparar una interrupción, aun cuando no estaba circulando agua por el caudalímetro, y pude verificar que esto dejaba de suceder si desconectaba la electroválvula.
Por lo que entiendo, la electroválvula genera ruido (no estoy seguro si por retorno en el relé o por inducción electromagnética). El relé es optoacoplado así que entiendo debería estar aisalando mi circuito de baja tensión correctamente del ruido de la alta tensión.
Comprobé también que solo al conectar el cable al pin 2 de mi arduino (es el pin que dispara la interrupción 0 que estoy usando), ya comienzo a recibir pulsos.
Alguien tiene algo de experiencia con estos problemas? Alguna recomendación?

Les copio el código:

// CONSTANTES
const int pinBoton = 7;         // Pin del Boton
const int pinLedRojo = 9;       // Pin del Led Rojo
const int pinLedAzul = 10;       // Pin del Led Azul
const int pinLedVerde = 11;      // Pin del Led Verde
const int pinRele = 12;          // Pin del Rele
const int pinCaudalimetro = 2;  // Pin del Caudalimetro
const int pinBotonStart = 13;    // Pin del Boton
const double TOPE3L = 3;  // Tope de señales para 3L
const double TOPE4L = 4;  // Tope de señales para 4L
const int ROJO = 1;
const int AZUL = 2;
const int VERDE = 3;

// VARIABLES
int estadoLed = 1;  // Led en Rojo
volatile int pulsos;
double caudalTope;
double litrosLeidos;

int estadoCaudalimetro;
int ultimoEstadoCaudalimetro;

int lectura;                   // Lectura boton
int estadoBoton;               // Lectura del boton
int ultimoEstadoBoton = HIGH;  // Lectura anterior del boton

long ultimoRebote = 0;  // Ultima vez que se presiono el boton
long delayRebote = 5;   // Tiempo de rebote

int lecturaSt;                   // Lectura boton
int estadoBotonSt;               // Lectura del boton
int ultimoEstadoBotonSt = HIGH;  // Lectura anterior del boton

long ultimoReboteSt = 0;  // Ultima vez que se presiono el boton
long delayReboteSt = 5;   // Tiempo de rebote

void setup() {

 pinMode(pinBoton, INPUT);
 pinMode(pinBotonStart, INPUT);
 pinMode(pinLedRojo, OUTPUT);
 pinMode(pinLedAzul, OUTPUT);
 pinMode(pinLedVerde, OUTPUT);
 pinMode(pinRele, OUTPUT);
 pinMode(pinCaudalimetro, INPUT);

 digitalWrite(pinLedRojo, HIGH);
 digitalWrite(pinLedAzul, LOW);
 digitalWrite(pinLedVerde, LOW);
 caudalTope = TOPE3L;
 attachInterrupt(0, leoPulsos, RISING); //Vinculo la interrupcion 0 a la funcion leoPulsos
 Serial.begin(9600);
}

void leoPulsos () { // Esta funcion agrega un pulso cuando se detecta una interrupcion
 pulsos++;
}

boolean debounce(boolean last, int pin) { // Función antirebote
 boolean current = digitalRead(pin);

 if (last != current) {
   delay(5);
   current = digitalRead(pin);
 }
 return current;
}

void loop() {

 int lectura = digitalRead(pinBoton);

 if (lectura != ultimoEstadoBoton) {
   ultimoRebote = millis();
 }

 if ((millis() - ultimoRebote) > delayRebote) {
   if (lectura != estadoBoton) {
     estadoBoton = lectura;

     if (estadoBoton == LOW) {
       switch (estadoLed) {
         case ROJO:
           digitalWrite(pinLedRojo, LOW);
           digitalWrite(pinLedAzul, HIGH);
           caudalTope = TOPE4L;
           estadoLed = AZUL;
           break;
         case AZUL:
           digitalWrite(pinLedAzul, LOW);
           digitalWrite(pinLedRojo, HIGH);
           caudalTope = TOPE3L;
           estadoLed = ROJO;
           break;
       }
     }
   }
 }

 int lecturaSt = digitalRead(pinBotonStart);

 if (lecturaSt != ultimoEstadoBotonSt) {
   ultimoReboteSt = millis();
 }

 if ((millis() - ultimoReboteSt) > delayReboteSt) {
   if (lecturaSt != estadoBotonSt) {
     estadoBotonSt = lecturaSt;

     if (estadoBotonSt == LOW) {
       // ABRO ELECTROVALVULA
       digitalWrite(pinRele, HIGH);
       // SETEO EL LED EN VERDE - CARGA EN PROCESO
       digitalWrite(pinLedAzul, LOW);
       digitalWrite(pinLedRojo, LOW);
       digitalWrite(pinLedVerde, HIGH);
       pulsos = 0;
       litrosLeidos = 0;
       // CONTROLO LA CARGA        
       while (litrosLeidos < caudalTope) {
         sei();
         delay(1000); // Espero un segundo
         cli();
         litrosLeidos = litrosLeidos + ((pulsos / 5.5) / 60); // (Pulsos en un segundo) / 5.5Q, = tasa de flujo en LxM luego divido por 60 para saber cuantos litros pasaron en un segundo
         Serial.print (litrosLeidos, DEC); 
         Serial.print (" L/seg\r\n"); 
       }

       // CIERRO LA ELECTROVALVULA
       digitalWrite(pinRele, LOW);

       // APAGO EL LED VERDE
       digitalWrite(pinLedVerde, LOW);
       // SETEO EL LED EN EL ESTADO ANTERIOR
       if (estadoLed == ROJO) {
         digitalWrite(pinLedRojo, HIGH);
       } else {
         digitalWrite(pinLedAzul, HIGH);
       }
     }
   }
 }

 ultimoEstadoBoton = lectura;
 ultimoEstadoBotonSt = lecturaSt;
}

Del tema eléctrico te dirán, que yo estoy muy pez, pero... ¿te es necesario gestionarlo con una interrupción? ¿no podrías gestionarlo dentro del ciclo del loop, y así podrías tener más control sobre cuando lanzas la función?

Tiene problema con tu switch. revisa tu boton

y tu funcion antirebote.

Gracias por las respuestas. Es necesario utilizar interrupciones para controlar el sensor caudalimetro ya que la ecuación que me permite calcular la cantidad de agua, utiliza la variable tiempo. En un ciclo (while o for), no podría calcular cuántas revoluciones por segundo realizó el caudalímetro).
El problema se genera cuando activo la electroválvula. Allí por más que el caudalímetro está desconectado, comienzo a recibir pulsos que disparan interrupciones. Si alejo lo suficiente la electroválvula esto deja de suceder, pero lamentablemente por el diseño de mi desarrollo es necesario que la electroválvula este a pocos centímetros del caudalímetro.
Necesito saber si aplicando algún capacitor a mi circuito o algún otro componente puedo filtrar estos falsos pulsos.

Los antirebotes de los botones pueden llegar hasta 20 mseg.
Como es la conexión del caudalímetro a la interrupción? hay alguna resistencia a masa?
Coloca una resistencia de 10k a GND y al pin 2 con el que unes a la salida digital del caudalímetro y luego nos dices si algo cambió o no.

Hola buenas.

A mi me paso exactamente lo mismo. Efectivamente, cualquier aparato electronico que tenga una bobina genera ruido, que por induccion dispara una interrupcion.
Al alejar el campo magnetico lo suficiente, esto deja de ocurrir.

Solucion:

Lo primero, arreglatelas para eliminar todos los delays de tu codigo.

La solucion al ruido es poner un diodo de flyback en cada rele. Esto que parece una tontería, no lo es en absoluto, es totalmente necesario para evitar falsas interrupciones.
Tienes que colocar un diodo entre los dos polos de la bobina de todos los reles que tengas cerca de la placa.
Yo usé diodos 1N4007. Ojo con la polaridad. Busca el diagrama por internet, es muy simple.

Si te fijas, la falsa interuupcion se produce cuando el rele pasa de activado a desactivado, esto es porque la descarga de golpe de la bobina genera un campo electromagnetico que induce una corriente en el cable suficiente para disparar la interrupcion.

Releyendo este post no me perdono haber obviado al responsable del problema que muy bien identificó hfxalvarez.
Debes usar un diodo en antiparalelo.
Borne positivo al catodo del diodo y bonre restantante al ánodo. Suponiendo que las electroválvulas trabajan con DC.
Espero que sea el caso sino tendras que usar snubbers para limitar los transitorios o bien un conmutador x cruce por cero.
Ya leí que usas un relé pero de nuevo, no dices si la válvula se alimenta con DC o AC.
con DC esta solución propuesta por hfxalvarez

con AC la cosa es mas compleja. Yo recomiendo usar un rele de estado solido con cruce por cero. Si es el caso te recomendaremos cuales son las opciones.

1 Like