Sensor inductivo activa relay por un tiempo y resetea nuevo flanco del sensor

Hola a todos, me metí en un proyecto para mi trabajo que no puedo resolver, soy nuevo en esto, quisiera si alguien me puede orientar un poco.

basicamente tengo un motor que gira a 25 RPM, en el eje tiene un disco plástico con 1tornillo metálico que al girar activa un sensor inductivo, esta señal entra en mi arduino y este enciende una salida (relay) por un tiempo determinado y luego se apague, salvo que el sensor siga sensando lo que hará que la salida (relay) quede encendida.

es básico, pero me estoy embrollando con los flancos, busque por la sentencia millis, puse un contador, pero hice un lio barbaro, a ver si alguien me puede orientar, luego yo hago el codigo

gracias de antemano

Saludos Damián

Subí el código que tenés y lo vemos.

Saludos

Hola Gatul gracias por responder, tengo un montón de borradores pero nada definido, estoy aprendiendo a programar , así que estoy lento.

Tengo que controlar el motor de una máquina, que si se traba o gira más lento de lo normal, se apague para no romper nada, como les dije gira a 25 vueltas por min (1 vuelta = 2.4 seg =
2400 mseg), y tiene en el eje un disco con un tornillo , quien me activa la salida cada vez que este pasa por el sensor, por lo tanto si tarda más que 2500 mseg (le di un poco más para resguardo), se apaga el motor

ya se que este código no sirve, no me deja compilarlo por la instrucción delay, pero por esta es la idea que tengo, no se que usar..... me estoy complicando

luego vemos el tema de los flancos, poner un filtro etc, etc, por ahora quiero resolver esto, solo

agradecido si me tiras alguna pista para seguir, abrazo Damián

const int sensor = 2; //(entrada)
const int relay =  3; //(salida)
int estado_sensor;

void setup()
{
  pinMode(relay, OUTPUT);//motor encendido
  pinMode(sensor, INPUT);// entrada de sensor
}

void loop()
{
  estado_sensor = digitalRead(sensor);
  
  if(estado_sensor == HIGH){
  
    digitalWrite(relay,HIGH);
    estado_sensor = 0;                 // reseteo la lectura del sensor, para proxima lectura
    
    delay(2500)                             //le doy un tiempo entre sensadas y un poco más para que siga        
    
      if(delay > 2500) {                  //si el tiempo entre sensadas es mayor a delay, apaga el relay
      digitalWrite(relay, LOW);
                                                     // y empieza el ciclo de nuevo
    }
  }
}

Moderador:
Bienvenido al Foro Arduino en Español.
Por favor, lee las Normas del foro y edita tu código usando etiquetas de código.
Ve a edición, luego selecciona todo el error que has publicado, lo cortas y click en </>


Sinceramente me sorprende que te digan, sube el código y lo hagas mal. Entiendo que eres nuevo pero todo novato debe leer las normas y no dar por sobreentendido nada.
Me pregunto, no viste otros hilos? Supongo que si, y ves que alguno este con el código como tu lo posteaste? No.
Mas cuidado la próxima por favor!!

Ahora te comento, es codigo no puede funcionar por cosas como esta

if(delay > 2500) { 

NOTA: observa que una línea y va con etiquetas. Asi que a tener en cuenta

delay no es una variable asi que no puedes compararla.
es un procedimiento, que no hace nada, detiene el microcontrolador por ese tiempo entre ()

Hola Surbyte, gracias por las aclaraciones, pido disculpa, ya corregí lo que me indicaste.

volviendo al caso, que función puedo usar para remplazar el (delay)?..... , necesito un contador que se active cuando el sensor envía 5v y me de un tiempo de 2500 mseg y luego de este tiempo se resetee con las próximas pasadas del motor, para que no me apague la salida de relay, si cuenta mas de 2500mseg, se tendría que apagar la salida relay.

mi placa es UNO R3

gracias, saludos

Ve a la Sección Documentación y lee sobre millis(). Te permitirá medir tiempos sin detener el funcionamiento del microcontrolador.
Hay varios tutoriales en Documentación =>Indice de temas tutoriales => millis()
Puedes ver el ejemplo en tu IDE BlinkWithoutDelay.ino que es lo mismo que necesitas para tu código.

Te sugiero que leas de la sección Documentación los temas Como NO leer un botón y como SI debemos hacerlo (la teoría aplica también a algunos sensores) y Entender millis y no morir en el intento, ambos son prácticamente indispensables.

Más allá de las recomendaciones, en tu caso, lo ideal sería utilizar interrupciones pero aplicar lo expuesto en esos temas es un muy buen comienzo para luego poder profundizar y mejorar.

Saludos

Hola, si ayer estuve viendo varios temas relacionados, voy a profundizar, cualquier cosa consulto de nuevo

gracias

Hola perfecto, si ayer vi el tuto Entender millis y no morir en el intento, que recomienda Gatul lo voy a ver nuevamente así avanzo con eso.

gracias

Vamos que con el ejemplo del IDE BlinkWithoutDelay.ino aprendes lo mismo.
Este es el ejemplo citado

const int ledPin =  LED_BUILTIN; // el pin LED correspondiente al Arduino en uso

int ledState = LOW;             // ledState usado para setear el LED

// Debes usar "unsigned long" para variables que almacenen tiempos con millis
// El valor rapidamente se convierte en demasiado grande para un int (entero) 
unsigned long previousMillis = 0;        // almacenará la ultima actualización de LED
// constantes no cambian
const unsigned long interval = 1000;           // intervalo al cual parpadea (milliseconds)

void setup() {
  pinMode(ledPin, OUTPUT);     // Establezco el pin digital como salida:
}

void loop() {

  // Verifico si es tiempo de parpadear el LED, si la diferencia entre el tiempo  
  // actual y el tiempo anterior en que cambiaste el estado del LED es mayor 
  // que el intervalo
  unsigned long currentMillis = millis();  // cargo currentMillis con el valor de millis()

  if (currentMillis - previousMillis >= interval) {
     // guardo el ultimo instante en que el LED parpadeó    
     previousMillis = currentMillis;

    // Si el led esta ON lo apago y si esta OFF lo enciendo
    if (ledState == LOW) {
        ledState = HIGH;
    } else {
       ledState = LOW;
    }

    // fijo la salida al estado de ledState que corresponda
    digitalWrite(ledPin, ledState);
  }
}

Dinos que parte no entiendes?

Hasta ahí .. "creo" que entendí todo, currentMillis y previusMillis se van incrementando y se comparan con el intervalo generando un loop, salvo que la diferencia de menos que el intervalo, ahí sale del if, lo que no logro comprender es donde puedo poner el dato del sensor inductivo para mi caso...

if (estado_sensor == HIGH){
    digitalWrite(relay,HIGH);
    estado_sensor = 0;          // reseteo la lectura del sensor, para proxima lectura
    delay(2500)                      //le doy un tiempo entre sensadas y un poco más     
    digitalWrite(relay, LOW);
  }

Este es en realidad tu código, la consulta de si ya pasaron los 2500mseg esta de mas porque delay(2500) hace eso justamente. Detiene 2500 mseg sin HACER NADA.
Ahora el reemplazo por millis() cambia porque si hace cosas o no, depende de ti.

#include <Arduino.h>

const int sensor = 2; //(entrada)
const int relay =  3; //(salida)
int estado_sensor, estado_sensorAnt = LOW;
unsigned long previousMillis = 0;        // almacenará la ultima actualización de LED
const unsigned long interval = 2500; 
bool flag = false;                      // flag que controla cuando usar el delay con millis()

void setup() {
  pinMode(relay, OUTPUT);//motor encendido
  pinMode(sensor, INPUT);// entrada de sensor
}

void loop() {
  unsigned long currentMillis = millis();  // cargo currentMillis con el valor de millis()

  estado_sensor = digitalRead(sensor);
  
  if (estado_sensor && !estado_sensorAnt) { // si cambia de 0 a 1 entonces se activó el sensor 
                                            // esto ocurre solo 1 vez cuando cambió el sensor
      digitalWrite(relay,HIGH);
      previousMillis = millis();
      flag = true;
  }
    
  estado_sensorAnt = estado_sensor;
  if (flag) {                      // solo ejecuto el tiempo si el flag esta activo
      if (currentMillis - previousMillis >= interval) { // si pasaron 2500 mseg apago
          digitalWrite(relay, LOW);
          flag = false;           // reseteo flag hasta la proxima activación
      }
  }
}

Aca tienes una versión que podría funcionar. Revisa a ver si lo hace bien.

Hola Surbyte, agradecido de antemano!! ahí lo simule y hace lo que yo necesito, todavía no logro entender bien la lógica, por ejemplo en el primer if cuál es la condición? veo que hay un (and negado) pero no se que compara ó hace.....
dame un tiempito que lo trato de entender y cualquier cosa te consulto nuevamente, soy muy novato en esto.

por otro lado me da la impresión que los 2500 ms no son reales, veo que el tiempo dura como 4 seg. aprox. esto a que se debe?

saudos y gracias

Mira la explicación que te pongo.
si una señal pasa de 0 a 1 entonces eso conforma un flanco ascendente
Cuando tu lees el pin digital lees el estado actual o sea estado_sensor por eso luego de todo almaceno el estado anterior en estado_sensorAnt
El if compara el estado actual con el anterior y si ambos son 1 && 0 o sea 1 AND !0 = 1 AND 1 = 1 o sea verdadero entonces hago lo que sigue
veamos un poco mas.
poner estado_sensor es lo mismo que poner estado_sensor == HIGH
poner !estado_sensorAnt es lo mismo que poner estado_sensorAnt == LOW
! es el operador que niega lo que sigue
entonces si el estado anterior de estadoSensor es 0 y lo invierto tengo un 1.
Por algebra de Boole, 1 AND 1 = 1 o sea VERDADERO
la condición ve el flanco que ocurre solo 1 vez.
Luego pones en HIGH el rele
cargas previousMillis con su valor y activas el flag a true
Ahora viene lo bueno...
almacenas el valor anterior con el actual.
y si flag es true entonces hago lo que sigue
aca viene lo mismo que BlinkWithoutDelay.ino
el millis actual menos el anterior si han superado 2500 mseg haran lo que sigue y sino pasan. Solo cuando superen 2500 mseg pongo en low el relay y en false el flag
y listo.. eso no se ejecuta mas porque flag estará en false
Todo eso se repite en cada ciclo y no me quedo mirando la LUNA durante 2500 mseg sin hacer nada como cuando uso delay.

Hola gracias por tu explicación y tiempo, me tuve que hacer el diagrama de flujo y con lo que me escribiste pude entenderlo, voy a ver unos videos en youtube de arduino para ponerme más al día.

volviendo al tema, lo del algebra de boole lo entiendo bien.... pero entonces en un IF si pongo (1 && 1), con esto solo sale por verdadero? no hay que hacer ninguna comparación?.... lo mismo si pongo IF (1 && !0) que sería lo mismo.

y por otro lado, noto que el intervalo de 2500 mseg, dura mucho más, igual me sirve porque lo ajusto con un valor menor y listo, pero que podría estar pasando?

saludos

Para que en un if vas a poner algo verdadero? No tiene sentido, se comparan cosas cuyos valores no conoces contra algo que si conoces y si se cumple haces lo que esta a continuación delimitado por las llaves {} o de lo contrario el else {}

Bueno me he desdicho como 2 veces. A ver si me ordeno.

void loop() {
  unsigned long currentMillis = millis();  // cargo currentMillis con el valor de millis()

  estado_sensor = digitalRead(sensor);
  
  if (estado_sensor && !estado_sensorAnt) { // si cambia de 0 a 1 entonces se activó el sensor 
                                            // esto ocurre solo 1 vez cuando cambió el sensor
      digitalWrite(relay,HIGH);
      previousMillis = currentMillis;
      flag = true;
  }
    
  estado_sensorAnt = estado_sensor;
  if (flag) {                      // solo ejecuto el tiempo si el flag esta activo
      if (currentMillis - previousMillis >= interval) { // si pasaron 2500 mseg apago
          digitalWrite(relay, LOW);
          flag = false;           // reseteo flag hasta la proxima activación
      }
  }
}

Este es el código propuesto con la variante de tomar currentMilllis y no millis() pero no cambia nada.
Cuando se da el flanco ascendente el flag se pone en true y cargo previousMillis con el valor actual.
Luego nos enfocamos en la comparación

if (currentMillis - previousMillis >= interval) { 

currentMillis sigue creciendo por millis() lo hace aumentan los milisegundos.
previousMillis no.
cuando la diferencia supera los 2500 entonces se cumple y apaga el relay.
No hay modo que eso ocurra mucho mas allá de 2500 a 2501 mseg.

Hola Surbyte, ahora lo enteniendo...es muy ingenioso, le voy a poner un serial.print para que me muestre el if que calcula el intervalo y ver como se comporta en ese momento, lo estoy simulando con el tinkercad pero este no tiene un modo paso a paso.

así que muy agradecido por tu explicación y saludos!

Los simuladores tardan en representar el tiempo normal asi que no te dejes llevar por la sensación porque NO ES REAL, es simulada.
Si pones Serial.print comprobarás que funciona bien.

1 Like