emisor de impulsos reed

Pretendo conectar un emisor de impulsos Reed a mi Arduino para contabilizar los pulsos y cuando tengo 100 pulsos activar dos salidas de arduino durante 500 ms para contabilidad que han pasado 100 pulsos.
El emisor es un Elster emeris PR7 1:100 2925M1263:

Los cables empleados del emisor para contabilizar son el amarillo CH1P y negro GND.
El datasheet me indica que todas las salidas del emisor es de colector abierto. Las salidas de pulsos activas son de nivel bajo. Las salidas pueden conectarse vía resistencia pull-up hasta 30V. Por lo tanto yo configuro la entrada D2 de Arduino como pull-up, utilizando la resistencia interna que lleva Arduino que es de mas o menos 20-50 Kohm.

Este sensor está a una distancia de +-30mts del arduino. El cable no lleva malla :(, pero por el conducto por el que pasa solo va este cable que es de 2x 1,5mm. ¿puede ser esto un problema?. Tengo que detectar 0v= 0 o 1=5v.

(NO FUNCIONA) Primero probé este código. Que en la mesa de practica me funcionaba perfectamente. Pero a la hora de conectarlo a este emisor me proporcionaba mas impulsos de los que llegaba, y en el periodo de 100 pulsos, no los realizaba en el mismo tiempo. Debiendo ser en el mismo tiempo ya que el caudal no variaba:

/*Entrada digital 2 cuenta impulsos entra del emisor impulsos
  Se utiliza resistencia PullUp de Arduino.  
  Al Contar 100 sera equivalente a 1m3. Activa una salida durante
   1 seg en estado alto y luego vuelve a estado bajo. Volviendo 
   el contador a 0.
*/
int Pulsos=100;    //Numero de pulsos para la activación del Relé
int conta = 0;  //Variable para guardar el conteo de los pulsos
//--------------------------------------------------
// Constantes y variales de tiempo
//-------------------------------------------
unsigned long InicioMillis=0; //inicia tiempo 
unsigned long FinMillis=0;  //Finaliza tiempo
const long intervalo=1000; //Tiempo de cerrado del contacto del relé
int EnTiempo=0;  //1= en tiempo de intervalo, 0= no intervalo.
//------------------------------------
void setup() 
{
  Serial.begin(9600);   //Inicia comunicación serial
  pinMode(2,INPUT_PULLUP); //Configura el pin 2 como una entrada, pulsador Con resistencia Pullup
  pinMode(13,OUTPUT);   //Configura el pin 13 como una salida, Relé
}
 
void loop() 
{           
  //Si pulsador pulsado.
  if ( digitalRead(2) == HIGH ) 
  {
    delay(20); //tiempo anti-rebore.
      // Si el pulsador no esta oprimido, flanco de bajada.Para 
      //saber que a terminado el pulso.
      if ( digitalRead(2) == LOW )
      {
         conta++;               //Incrementa el contador
         Serial.println(conta); //Imprime el valor por consola
         delay (20);           // Tiempo anti-rebote
      }
  }
 
  // Si el valor del contador es 100 tenemos 1 m3 y mandamos 
  //Un estado en alto en la salida 13 de 1 seg. Volviendo luego a
  //Estado bajo.
  if (conta==Pulsos)
  {
    digitalWrite(13,HIGH); 
    Serial.println("PRENDE");
    InicioMillis=millis();//inicia el tiempo de 1 seg de retardo.
    EnTiempo=1; //1= en tiempo de intervalo.
    conta=0; //Volvemos contador a 0 para que vuelva a contar.
  }
  if(millis()-InicioMillis>=intervalo&&EnTiempo==1){//si transcurre 1 seg hace esto o en tiempo de intervalo hace esto
    digitalWrite(13,LOW);
    Serial.println("OFF");
    EnTiempo=0; //0= desactivamos intervalo.
    }   
}

Navegando y buscando por el foro encontré este post:

Donde vi que tenia el mismo problema, tenia que comprobar el estado anteriores.

Ahora he modificado el código que es el:

/*Entrada digital 2 cuenta impulsos entra del emisor impulsos
  Se utiliza resistencia PullUp de Arduino.  
  Al Contar 100 sera equivalente a 1m3. Activa una salida durante
   1 seg en estado alto y luego vuelve a estado bajo. Volviendo 
   el contador a 0.
*/
int Pulsos=100; //Numero de pulsos para la activación del Relé.
const int boton = 2; //Entrada emisor impulsos
const int Rele = 13; //Salida rele
int contador = 0;  //Variable para guardar la cuenta de pulsaciones
int estadoAnteriorBoton = 0; //Declaramos e inicializamos la variable
int valorBoton = 0; //Declaramos e inicializamos la variable
// Constantes y variales de tiempo
//-------------------------------------------
unsigned long InicioMillis=0; //inicia tiempo 
unsigned long FinMillis=0;  //Finaliza tiempo
const long intervalo=100; //Tiempo de cerrado del contacto del relé
int EnTiempo=0;  //1= en tiempo de intervalo, 0= no intervalo.

//------------------------------------
//Funcion principal
//------------------------------------
void setup()
{
  Serial.begin(9600);   //Inicia comunicación serie
  pinMode(boton,INPUT_PULLUP);     //Configura el pin 2 como una entrada, con resistencia pullup
  pinMode(Rele,OUTPUT);   //Configura el pin 13 como una salida, LED
}

//------------------------------------
//Funcion ciclica
//------------------------------------
void loop() 
{           

valorBoton=digitalRead(boton); //Leemos el estado del interruptor emisor

if(valorBoton!=estadoAnteriorBoton){ //Si hay un cambio de estado, entramos en el if

  if(valorBoton==0){
    contador++; //Aumentamos en una unidad la cuenta
    Serial.println(contador); //Imprime el valor por consola
  }
}
if(contador==Pulsos)
  {
    digitalWrite(Rele,HIGH); 
    Serial.println("PRENDE");
    InicioMillis=millis();//inicia el tiempo de 1 seg de retardo.
    EnTiempo=1; //1= en tiempo de intervalo.
    contador=0; //Volvemos contador a 0 para que vuelva a contar.
  }
  if(millis()-InicioMillis>=intervalo&&EnTiempo==1){//si transcurre 1 seg hace esto o en tiempo de intervalo hace esto
    digitalWrite(Rele,LOW);
    Serial.println("OFF");
    EnTiempo=0; //0= desactivamos intervalo.
}
estadoAnteriorBoton=valorBoton; //guardamos el estado actual del pulsador para la siguiente iteración
}

Tengo que comprobar este código, espero que sea esta la solución.
¿habría alguna otra forma de contabilizarlo?.

Gracias.

Olvide dos cosas muy importantes. Primer saludar que no lo hice. Lo segundo, olvide introducir en el ultimo código el el problema del desbordamiento de millis a los 50 días. Que lo soluciono añadiendo una función Overflow:
[code/*Entrada digital 2 cuenta impulsos entra del emisor impulsos
  Se utiliza resistencia PullUp de Arduino.  
  Al Contar 100 sera equivalente a 1m3. Activa una salida durante
   1 seg en estado alto y luego vuelve a estado bajo. Volviendo 
   el contador a 0.
*/
int Pulsos=100; //Numero de pulsos para la activación del Relé.
const int boton = 2; //Entrada emisor impulsos
const int Rele = 13; //Salida rele
int contador = 0;  //Variable para guardar la cuenta de pulsaciones
int estadoAnteriorBoton = 0; //Declaramos e inicializamos la variable
int valorBoton = 0; //Declaramos e inicializamos la variable
// Constantes y variales de tiempo
//-------------------------------------------
unsigned long InicioMillis=0; //inicia tiempo 
unsigned long FinMillis=0;  //Finaliza tiempo
const long intervalo=100; //Tiempo de cerrado del contacto del relé
int EnTiempo=0;  //1= en tiempo de intervalo, 0= no intervalo.

//SOLUCION PARA EVITAR OVERFLOW DE LA FUNCION MILLIS()((2^32)-1) + o - a los 50 dias millis() volvera a 0//
unsigned long Overflow(unsigned long FinMillis, unsigned long InicioMillis, unsigned long intervalo)
{
  unsigned long Overflow;
  unsigned long MaxMedida=4294967295;

  if(FinMillis<InicioMillis)
  {
    Overflow=MaxMedida-InicioMillis;
    //Serial.print("Overflow de la primera parte: ");
    //Serial.println(Overflow);
    intervalo=Overflow+FinMillis;
    //Serial.print("tiempo rectificado en milisegundos= ");
    //Serial.print(Tiempoms);
  }
  else
  {
    //Serial.print("no hace falta overflow");
  }
}

//------------------------------------
//Funcion principal
//------------------------------------
void setup()
{
  Serial.begin(9600);   //Inicia comunicación serie
  pinMode(boton,INPUT_PULLUP);     //Configura el pin 2 como una entrada, con resistencia pullup
  pinMode(Rele,OUTPUT);   //Configura el pin 13 como una salida, LED
}

//------------------------------------
//Funcion ciclica
//------------------------------------
void loop() 
{           
Overflow(FinMillis, InicioMillis, intervalo);
valorBoton=digitalRead(boton); //Leemos el estado del interruptor emisor

if(valorBoton!=estadoAnteriorBoton){ //Si hay un cambio de estado, entramos en el if

  if(valorBoton==0){
    contador++; //Aumentamos en una unidad la cuenta
    Serial.println(contador); //Imprime el valor por consola
  }
}
if(contador==Pulsos)
  {
    digitalWrite(Rele,HIGH); 
    Serial.println("PRENDE");
    InicioMillis=millis();//inicia el tiempo de 1 seg de retardo.
    EnTiempo=1; //1= en tiempo de intervalo.
    contador=0; //Volvemos contador a 0 para que vuelva a contar.
  }
  if(millis()-InicioMillis>=intervalo&&EnTiempo==1){//si transcurre 1 seg hace esto o en tiempo de intervalo hace esto
    digitalWrite(Rele,LOW);
    Serial.println("OFF");
    EnTiempo=0; //0= desactivamos intervalo.
}
estadoAnteriorBoton=valorBoton; //guardamos el estado actual del pulsador para la siguiente iteración
}
]

También quiero decir que los intervalos de cierre del emisor de impulsos varia según el caudal de agua. A más caudal más impulsos. Y los pulsos por segundo pueden llegar a ser de 11 como máximo. Cada 0,0909 segundos un pulso. Por eso no utilizo la función delay. Según tengo entendido en este periodo de tiempo del delay el código se para y no detectaría ningún pulso.

Gracias.

Gracias.

Hola chufi.

Primero de todo, debes decirnos como son las conexiones del sensor al arduino porque no me queda claro que lo estes haciendo bien.

Definir INPUT_PULLUP implica que tu sensor es un contacto seco como si fuera un interruptor o un contacto de rele.
Definelo como INPUT solamente.

Ahora supongo que usas esto

Configura el pin 2 como una entrada, pulsador Con resistencia Pullup

y entonces de ese modo va a contar bien.

Hola Surbyte. El emisor de impulsos según las especificaciones es de salida colector abierto. Creo que es lo mismo que contacto seco. realmente lo que hace este sensor es usar un interruptor reed que cuando pasa por un imán cierra el contacto. Mi conexión al sensor es la siguiente:

El cable amarillo del sensor que lleva el cuenteo y es de salida de colector abierto, lo llevo a la entrada 2 digital. Por eso configuro la entrada 2 con la resistencia pull-up interna. Pero ahora que lo dices lo probare también como dices.
El otro cable que me llega del sensor es negro y es el tierra. que lo llevo a tierra del Arduino.

Gracias.

Como alimentas el sensor?

Según especificaciones, la alimentación se realiza por medio de una batería de Litio DC 3.6V que va incluida en el sensor y tiene una duración de 10 años. La Batería esta ok por que conectando un Totalizador digital a estos dos cables amarillo=cuenteo y negro=GND. La cuenta de impulsos es la correcta.

El esquema de las salida de colector abierto que van incluidas en el sensor es el siguiente y es la salida de cuenteo cable amarillo:

bueno pero eso es un colector abierto, asi que falta una R y conectarlo a 5V si es el caso de tu arduino.
Supongamos 1k y 5V.
De la salida tendras los pulsos deseados.

Gracias surbyte. Cuando pueda colocaré la resistencia de 1K lo más cerca de Arduino en serie con pin 2 a ver qué tal.

Mis progresos son los siguientes:

El conexionado a Arduino es el siguiente (el Reed Switch es el esquema de colector abierto).

Añado un condensador de 100nF lo más cercano Arduino entre los pines de tierra y pin 2. Al crearme efecto antena. Aun que estos dos pines no estuvieran cortocircuitos me creaba impulsos. Con este condensador ya no los crea.
Utilizo resistencia interna de Arduino PullUp. (Compruebo a utilizar resistencia PullUp y PullDown externas. Pero al quitar cable de alimentación 5V y D2 me creaba multitud de impulsos. Por lo tanto opto por utilizar resistencia interna).
El emisor de impulsos es un Reed Switch Pr7 Elster. En la foto se resume sus pin de conexiones, yo utilizo Cable amarillo para el recuento y negro Tierra:

He realizado dos Sketch lo más básicos posibles.
Cuando detecte la entrada pin 2 de Arduino 100 impulsos me activa la salida D13 y D12. Aprovecho el impulsos 100 para activar salidas y el impulsos 4 para desactivar salidas. Así evito de utilizar temporizaciones delay y millis para provocar un impulso a la salida.

1º Sketch:

/*BORRADOR:2 relés activan a los 100 y desactivan a los 4 pulsos.
 *         No se usa millis ni delays.
 * Entrada digital 2 cuenta impulsos entra del emisor impulsos
  Se utiliza resistencia PullUp de Arduino.  
*/
int Pulsos=100; //Numero de pulsos para la activación del Relé.
const int boton = 2; //Entrada emisor impulsos
const int Rele = 13; //Salida rele
const int Rele2=12;//Salida rele 2
int contador = 0;  //Variable para guardar la cuenta de pulsaciones
int estadoAnteriorBoton = 0; //Declaramos e inicializamos la variable
int valorBoton = 0; //Declaramos e inicializamos la variable
// Constantes y variales de tiempo

void setup()
{
  Serial.begin(9600);   //Inicia comunicación serie
  pinMode(boton,INPUT_PULLUP);     //Configura el pin 2 como una entrada, con resistencia pullup
  pinMode(Rele,OUTPUT);   //Configura el pin 13 como una salida
  pinMode(Rele2,OUTPUT);
}


void loop() 
{           

valorBoton=digitalRead(boton); //Leemos el estado del interruptor emisor

if(valorBoton!=estadoAnteriorBoton){ //Si hay un cambio de estado, entramos en el if

  if(valorBoton==0){
    contador++; //Aumentamos en una unidad la cuenta
    Serial.println(contador); //Imprime el valor por consola
  }
}

estadoAnteriorBoton=valorBoton; //guardamos el estado actual del pulsador para la siguiente iteración

if(contador==Pulsos)
  {
    digitalWrite(Rele,HIGH); 
    digitalWrite(Rele2,HIGH); 
    Serial.println("PRENDE");

    contador=0; //Volvemos contador a 0 para que vuelva a contar.
  }
if(contador==4)
{
  digitalWrite(Rele,LOW);
  digitalWrite(Rele2,LOW);
  Serial.println("OFF");
}

}

2º Sketch he utilizado interrupciones:

int contador = 0;
int pulsos=100 ;
int Activo=0;
const int Rele=13;
const int Rele2=12;
const int boton=2;


void setup()
   {   Serial.begin(9600);
       pinMode(Rele,OUTPUT);
       pinMode(Rele2,OUTPUT);
       pinMode(boton,INPUT_PULLUP);
       attachInterrupt( INT0, EmisorPulsos, FALLING);
       interrupts();                              
   }
void loop()
   {
       if (contador>=pulsos)
       {  
        Serial.println("prende");
        digitalWrite(Rele,HIGH);
        digitalWrite(Rele2,HIGH);
        contador=0 ;
        Activo=1;
       }
      if(contador>=4&&Activo==1)
      {  
       Serial.println("OFF"); 
       digitalWrite(Rele,LOW);
       digitalWrite(Rele2,LOW);
       Activo=0;
      }
   }

void EmisorPulsos() 
   {    contador++ ;
   Serial.println(contador);
   }

Estos Sketch cuando los pruebo en protoboard me funcionan de maravilla. Pero cuál es mi sorpresa que cuando los intento aplicar a la práctica, conectado al Reed Switch el cuenteo no es el debido.

El 1º Sketch de ellos, me realiza el cuenteo de 100 impulsos variando entre 10,42 a 11,59 segundos. Debiendo de ser la correcta de 14 segundos. Es decir, me cuenta más impulsos de los que llega. Y a demás hay variación de 1 segundo entre algunas lecturas. Que eso debe de ser imposible ya que el caudal del agua es el mismo durante dichas medidas.
2º Sketch que esta con interrupciones funciona peor. Me realiza el cuenteo de 100 impulsos en tan solo 2,25 segundos. Me cuenta impulsos de más exageradamente. Debiendo ser de 14 segundos.
He llegado a la conclusión que esto puede ser debido al ruido.
La manguera que va del detector Reed Switch a caseta donde está Arduino está apantallada, tiene una longitud de 40 metros, y por el conducto pasa únicamente esta manguera, donde solo está conectada los dos cables del Reed Switch.

Eso sí, en la caseta existe componentes de corte eléctrico magnetotérmico, variador de frecuencia, y cables por el que circulan 500v y consumo de 300A. Arduino se encuentra a más o menos 1 metro de ellos. Esto me hace pensar, que pueda haber ruido radiante que pueda hacer funcionar mal Arduino.
Seguiré investigando y si alguien pudiera aportarme alguna ayuda estaría agradecida.
Un proyecto que parecía sencillo se complica.
Gracias.

Y probaste en la prueba de campo, sin el capacitor?

La prueba en casa, sustituí el emisor por un pulsador, todo me va perfecto sin el capacitor y con capacitor.

Llevo esa misma instalación al recinto de trabajo. Sin capacitor, me llegan impulsos aun que no pulse el pulsador. Coloco el capacitor y funciona bien. Cuando pulso y suelto pulsador cuenta un impulso.
Ahora sustituyó el pulsador por el emisor impulsos y me sucede para cada Sketch lo que comento en el anterior post.

Hola Chufi, tu guerra es mi guerra!!!!

Primero me presento, soy apasionado en arduino y soy nuevo en la comunidad.
Espero aportar mucho, asi como aprender.

Tengo 3 contadores Elster con sensor PR6, conectados en cable CH2. Cable Rojo.

Puedo constatar que hace 5 dias q obtengo pulsos correctos de sensores Elster.

Probe muchos ejemplos hardware y software, e indague en muchos sitios, y al final creo he dado con la solucion.

Como yo, llegue hasta aqui por tu articulo, me gustaria dar solucion al problema que nos ha dado muchos dolores de cabeza.

Bueno, para todo el que este trabajando con pulsadores o pulsos via transistor. Como bien dice chufi la resistencia pullup que incorpora arduino es elevada.
Con lo ejemplos 10 k, la entrada tiene 5 Vcc pero pasa poca chicha.

Para no tener falsos pulsos se tiene que configurar la entrada como simple INPUT y colocar una residtencia de valor 2,2 k ohms en PULL UP.

Ya esta. Si el pulso viene de un contacto mecanico (pulsador, interruptor, reed,...) colocar un condensador en paralelo de 1 microfaradio. Aunque con un simple debounce tambien sirve. Y si los tiempos te lo permiten y no quieres mas que hacerlo rapido tras detectar el cambio de estado a LOW colocas un delay de 10 ms o mas y tambien vale.

Espero sirva de ayuda. Saludos.

Hola RLC muchas gracias por la ayuda. Me trajo mucho quebraderos de cabeza este problema que no solucione. En cuando pueda probaré lo que me expones.

Gracias.