Programacion tipo Contador RPM [SOLUCIONADO]

Muy buenas tardes a todos, he visto que seria mejor poner este tipo de consulta en "Software" ya que no es una explicación del proyecto completamente entero.

Espero que con un poco de ayuda de cada uno de ustedes pueden resolver este código.

Lo dividiré en partes para que sepáis por donde va el tema y su función.

FUNCIONAMIENTO / OBJETIVO:

1.- Un plato / disco con un imán gira a "X" revoluciones activando un Sensor Hall con su respectivo circuito conectado a Arduino.

2.- Un LED llamado "Led1" se debe de encender cada vez que el Sensor Hall detecta 1 pulso / RPM.

3.- Otro LED llamado "Led2" se debe de encender a "Y" ms. de haber encendido el "Led1" y apagarse automáticamente el "Led1" y "Led2" cuando pase "Z" ms. , los cuales siempre serán valores muy bajos ya que le tiene que dar tiempo a contar otra RPM.

4.- A medida que las "RPM" aumenten, debe reducir el tiempo que tarda el "Led2" en encenderse después del "Led1", así como la duración de los dos al mismo tiempo.

5.- Y bueno, como extra, ver las RPM/Hz en Monitor Serial

EJEMPLO:

El plato esta girando a X = 1000RPM, cada vez que cuenta 1 RPM el "Led1" se enciende y el "Led2" se enciende a Y = 50ms despues, y los dos se apagan a los Z = 100ms. Habiéndose encendido el "Led1" 100ms y el "Led2" 50ms.

Y a medida que aumenten las RPM "X" se van reduciendo los tiempos "Y" y "Z".

Espero que lo halláis entendido, parece un poco complicado o al menos para mi. Si tiene alguna duda o necesita más datos decírmelo.

Aquí os dejo como llevo el código yo, para que tengas más o menos una base.

volatile int RPMContados = 0;
int RPM = 0;

const byte LED1Pin              = 4;
const byte LED2Pin              = 5;     
const byte sensorHallpin        = 2;   

bool EstadoActualLed                   = HIGH;       
bool lastButtonState            = LOW;
bool buttonState;   
bool LecturaSensor;

unsigned long tiempoAnterior    = 0;

unsigned long debounceDelay     = 0;
unsigned long lastDebounceTime;
unsigned long startDelay;
unsigned long retardoApagado    = 50;

void setup() {
  pinMode(sensorHallpin, INPUT);
  pinMode(LED1Pin, OUTPUT);
  pinMode(LED2Pin, OUTPUT);
  Serial.begin(9600);
  attachInterrupt(0, RPM_Motor, FALLING);
}
void loop() {

 if (millis() - tiempoAnterior == 1000){

 detachInterrupt(0);

 RPM = RPMContados * 60;

 Serial.print("RPM =\t");
 Serial.print(RPM);
 Serial.print("\t Hz =\t");
 Serial.println(RPMContados);

 RPMcontados = 0;
 tiempoAnterior = millis();
 attachInterrupt(0, RPM_Motor, FALLING);
  }

  LecturaSensor = digitalRead(sensorHallpin);                                         

  if (LecturaSensor != lastButtonState) {
      lastDebounceTime = millis() + debounceDelay;

  }

  if (millis() > lastDebounceTime) {
      if (LecturaSensor != buttonState) {
          buttonState = LecturaSensor;
          if (buttonState == HIGH) {
              EstadoActualLed = !EstadoActualLed;
              if (EstadoActualLed)
                  startDelay = millis() + retardoApagado;
          }
      }
  }

  lastButtonState = LecturaSensor;

  if (EstadoActualLed) {
     digitalWrite(LED2Pin,  HIGH);
     if (millis()>startDelay)
         digitalWrite(LED1Pin, HIGH);
  }
  else {
     digitalWrite(LED2Pin, LOW);
     digitalWrite(LED1Pin, LOW);
  }
}

void RPM_Motor(){
  RPMContados++;
}

Olvidaste poner la consulta.

Disculpa, mi CONSULTA es como hacer que funcione y se cumplan todos esos objetivos...
Lo único que consigo ahora mismo es contar los RPM bien y encender los dos LED como dije, pero no se apagan cuando quiero, solo cuando cuenta otra vuelta.

Quizas si dejas de jugar con las interrupcioones...

const byte sensorHallpin        = 2;  
const byte LED1Pin              = 4;
const byte LED2Pin              = 5;    

int RPMContados;
bool actual,anterior;
unsigned long t0,t1;

void setup() {
   Serial.begin(9600);
   pinMode(sensorHallpin, INPUT);
   pinMode(LED1Pin, OUTPUT);
   pinMode(LED2Pin, OUTPUT);
}

void loop() {
   actual = digitalRead(sensorHallpin);
   id (actual && !anterior){
      RPMContados++;
      digitalWrite(LED1Pin, HIGH);
      t1 = millis();
   }
   anterior = actual;
   //Prende LED 2
   if (millis() - t1 >= 50){
      digitalWrite(LED2Pin, HIGH);      
   }
   //Apaga ambos LEDs
   if (millis() - t1 >= 100){
      digitalWrite(LED1Pin, LOW);
      digitalWrite(LED2Pin, LOW);      
   }
   //Calcula RPM  
   if (millis() - t0 >= 1000){
      t0 = millis();
      RPM = RPMContados * 60;
      Serial.print("RPM =\t");
      Serial.println(RPMContados);
      RPMcontados = 0;
   }
}

El codigo puede estar bien y sin embargo hay un gran error de criterio o tu ejemplo no ha sido acertado.
Me explico:

El plato esta girando a X = 1000RPM, cada vez que cuenta 1 RPM el “Led1” se enciende y el “Led2” se enciende a Y = 50ms despues, y los dos se apagan a los Z = 100ms. Habiéndose encendido el “Led1” 100ms y el “Led2” 50ms.

Un plato girando a 1000 RPM implica 1000/60 = 16.66 rev x segundo o sea 60 mseg aprox

O sea… quieres que un LED que ambos sabemos que no puedes ver pero tal vez tenga otra función reaccione cada 50 mseg a algo que ocurre cada 60 mseg, bueno eso no es problema.
Ahora resulta que quieres que otra salida demore mas tiempo que el que le lleva a dos revoluciones por segunto tomar. 120 mseg, o sea que tu señal Y fallará.

surbyte:
El codigo puede estar bien y sin embargo hay un gran error de criterio o tu ejemplo no ha sido acertado.
Me explico:
Un plato girando a 1000 RPM implica 1000/60 = 16.66 rev x segundo o sea 60 mseg aprox

O sea.. quieres que un LED que ambos sabemos que no puedes ver pero tal vez tenga otra función reaccione cada 50 mseg a algo que ocurre cada 60 mseg, bueno eso no es problema.
Ahora resulta que quieres que otra salida demore mas tiempo que el que le lleva a dos revoluciones por segunto tomar. 120 mseg, o sea que tu señal Y fallará.

Perdona, fue un ejemplo rápido sin haberlo pensado bien.... Digamos que serian otros tiempos diferentes de activación y desactivacion, y si, es para otro uso, no con LED... Pero la salida seria la misma, solo quería simplificar diciendo que son LED. Voy a probar el código de "Kike_GL" haber que tal.

Tiene que ser un código super preciso y con mínimos errores de calculo. Ya que debe activar cada una de las salidas LED en el tiempo exacto que necesito. Quiero saber como funcionaria y de que base mas avanzada partir a configurar yo después.

Gracias por vuestra ayuda, en un rato avisare como fue el segundo código...

El código de Kike es todo lo preciso que permite el codigo usando millis(), quieres mas precision usa micros() quieres mas, usa timers.

Disculpar por tardar en contestar. He tenido problema con el Foro, no cargaba bien la pagina…

Bueno, probe el codigo de Kike:

EL código muestra 3 errores, falta declarar los “RPM”, poner algunas mayúsculas y un “if” mal puesto. Habiendolo reparado, no cuenta RPM, sino RPS… Ademas los LED los enciende 1 vez nada mas o no los vuelve a apagar nunca…

Bueno trabaja mas y corrigelo entonces!!

Ya te lo dirá Kike pero la mayoría de las respustas uno las hace sin probar el código.

Moderador:
No repitas lo que se lee arriba, simplemente coloca @fulano y tu comentario.
Si vas a responder a un párrafo usa la cita pero si tomas toda la respuesta recibirás una advertencia mía y posible sanción cuando repitas el error varias 3 veces.
En las normas del foro esta indicado.

Hola @surbyte , te agradezco tus ganas de ayudar, pero podrías dejar a un lado por un momento tu ROL de Moderador, y no corregir ejemplos con errores tontos y obvios, ademas de parecer que estas en contra de ayudarme...

Esto es lo que me parece a mi, lo siento si piensas lo contrario, y sobre las Normas del Foro las tengo bien leídas y tengo practica en otros foros/comunidades.

Perdóname si he citado varias veces las respuestas de Kike, no era mi intención que tengáis que escrollear mas el ratón, pero era por si acaso se metía mas gente a ayudar que supiesen por donde van los tiros, ya que muchos solo leen el principio y el final...

Bueno me gustaría pedirte que me ayudaras con este tedioso código, y no me corrigieses solamente la manera de explicarlo o contestar en este hilo, tu tienes bastante experiencia en esto y no debería costarte darme un par de consejos sobre el código.

Y @Kike_GL gracias por tu primer intento de colaborar en el código, me lo has simplificado bastante, cosa que me gusta, ya que es mejor tener un código simple y que cumpla que uno muy elaborado y que luego falle algo y YO no tenga de idea de que es.

PD: Aunque no se pueda probar los códigos físicamente, por lo menos se compilan para que no tengan errores!

Bueno, vamos a trabajar primero con el código de encender el led con retraso.

Necesito que cada vez que se detecta un pulso encienda un LED 4ms después y se apague solo 7ms después de haber sido encendido

Por ahora lo único que he conseguido es que con un pulso se encienda 4ms despues y con otro pulso se apague.

Asi que digamos que cada pulso inicia un ciclo, en el cual un led tarda 4ms en encenderse y 7ms en apagarse, pero a mi solo se enciende en un pulso y en el siguiente pulso se apaga, cuando ya deberia de haberse apagado y volver a encenderse...

const int Sensor            = 2;
const int Led              = 4;

bool EstadoLed                   = LOW;
bool EstadoSensor;
bool Lectura;

unsigned long EmpezarRetraso;
unsigned long RetrasoEncendido    = 4;

void setup() {
  pinMode(Sensor, INPUT);
  pinMode(Led, OUTPUT);
}
void loop() {
  
  Lectura = digitalRead(Sensor); //Declaro que la Lectura es leida digitalmente en el pin del Sensor

      if (Lectura != EstadoSensor) { //Si la Lectura no es igual al Estado del Sensor...
          EstadoSensor = Lectura; //...actualiza el Estado del Sensor a la Lectura
          if (EstadoSensor == HIGH) { //Si el Estado del Sensor esta en HIGH...
              EstadoLed = !EstadoLed; //...invierte el Estado del LED
              if (EstadoLed == HIGH) { //Si el Estado del LED esta en HIGH...
                  EmpezarRetraso = millis() + RetrasoEncendido; //...actualiza el "EmpezarRetraso" con el "tiempo" + el Retardo de Encendido
              }
          }
      }

  if (EstadoLed == HIGH && millis() > EmpezarRetraso) {                      
     digitalWrite(Led, HIGH);
  }
  else {
     digitalWrite(Led, LOW);
  }
}

Si es cada vez que se detecta el pulso entonces esto

if (Lectura != EstadoSensor) {

esta mal.
Eso responde a cada cambio
Y tu quieres ver un flanco.

Supongamos que fuera flanco descendente.

if (Lectura && !EstadoSensor) {

Eso corregirá las cosas

Esto es lo que me parece a mi, lo siento si piensas lo contrario, y sobre las Normas del Foro las tengo bien leídas y tengo practica en otros foros/comunidades.

Yo también tengo prácticas y sin embargo, choco con los mismos problemas que acabo de explicarte. Cada foro tiene peculiaridades. Solo hay que prestarle atención y sigue la corriente.

EDITO:
Estaba por borrar el código y me encuentro esto

  Lectura = digitalRead(Sensor);      // Declaro que la Lectura es leida digitalmente en el pin del Sensor

      if (Lectura && !EstadoSensor) {  // Si la Lectura no es igual al Estado del Sensor...
          EstadoSensor = Lectura;     // ...actualiza el Estado del Sensor a la Lectura
          if (EstadoSensor == HIGH) { // Si el Estado del Sensor esta en HIGH...
              EstadoLed = !EstadoLed; // ...invierte el Estado del LED
              if (EstadoLed == HIGH) { // Si el Estado del LED esta en HIGH...
                  EmpezarRetraso = millis() + RetrasoEncendido; //...actualiza el "EmpezarRetraso" con el "tiempo" + el Retardo de Encendido
              }
          }
      }

para mi gusto (que no he probado) debiera ser asi

  Lectura = digitalRead(Sensor);      // Declaro que la Lectura es leida digitalmente en el pin del Sensor

  if (Lectura && !EstadoSensor) {  // Si hay flanco de 0 a 1, si debe ser al revés invierte! 
      EstadoLed = !EstadoLed;      // ...invierte el Estado del LED
      if (EstadoLed) {             // Si el Estado del LED esta en HIGH...
          EmpezarRetraso = millis() + RetrasoEncendido; //...actualiza el "EmpezarRetraso" con el "tiempo" + el Retardo de Encendido
      }
  }
  EstadoSensor = Lectura;     // ...actualiza el Estado del Sensor a la Lectura

Muchas gracias por tu ayuda, me has encaminado mucho mejor hacia la solución.

Ya tengo la primera parte del código resuelta.

Puedo retrasar tanto el encendido como el apagado del led una vez recibe un único pulso.

Aquí dejare el código terminado de la primera parte, ahora tocara implementarlo con los RPM y hacer lo mas difícil.

Dejo pruebas bajo osciloscopio y el código usado

Retraso de Encendido de 2ms:

Retraso de Apagado de 8ms:

const int Sensor            = 2;
const int Led               = 4;

bool EstadoLed              = LOW;
bool EstadoSensor;
bool Lectura;

unsigned long EmpezarRetraso;
unsigned long RetrasoEncendido    = 8;
unsigned long EmpezarApagado;
unsigned long RetrasoApagado      = 2; 

void setup() {
  pinMode(Sensor, INPUT);
  pinMode(Led, OUTPUT);
}
void loop() {
  
    Lectura = digitalRead(Sensor);      // Declaro que la Lectura es leida digitalmente en el pin del Sensor

  if (Lectura && !EstadoSensor) {  // Si hay flanco de 0 a 1, si debe ser al revés invierte!
      EstadoLed = !EstadoLed;      // ...invierte el Estado del LED
      if (EstadoLed) {             // Si el Estado del LED esta en HIGH...
          EmpezarRetraso = millis() + RetrasoEncendido; //...actualiza el "EmpezarRetraso" con el "tiempo" + el Retardo de Encendido
      }
  }
  EstadoSensor = Lectura;     // ...actualiza el Estado del Sensor a la Lectura

  if (EstadoLed == HIGH && millis() > EmpezarRetraso) {
     EmpezarApagado = millis();
     digitalWrite(Led, HIGH);
    }
  
  if (millis() - EmpezarApagado > RetrasoApagado) {
   digitalWrite(Led, LOW);
    }
}

Bueno y al final de todo, queda por concluido el codigo, acabo de terminarlo, ya cumple al 100% lo que necesitaba.

Funcionamiento final:

1-. Al recibir un pulso enciende el LED 2ms después y lo apaga 8ms después de haberse encendido. Ademas cuenta 1 RPM

2-. Transmite los RPM y Hz por puerto serial.

3-. A mas RPM, mas corto es el retraso de encendido del led y su apagado.

Aquí os dejo el código final.

#include <Arduino.h>

volatile int RPMcontados = 0; //Configuro volatil los RPM contados para que no se pierdan de una interrupcion a otra
const int Sensor = 2; //Declaro variable del pin del Sensor
const int Salida = 5; //Declaro variable del pin del Salida
int RPM = 0; //Declaro que la variable RPM esta a 0 en cada bucle

bool EstadoSalida = LOW;
bool EstadoSensor;
bool Lectura;

unsigned long tiempo = 0; //Declaro que la variable tiempo esta a 0 en cada bucle
unsigned long EmpezarRetraso;
unsigned long RetrasoEncendido;
unsigned long EmpezarApagado;
unsigned long RetrasoApagado; 

void setup() {

    Serial.begin(9600); //Abro comunicacion con la consola
    pinMode(Sensor, INPUT); //Declaro el Sensor como una entrada
    pinMode(Salida, OUTPUT); //Declaro el Salida como una salida
    attachInterrupt(digitalPinToInterrupt(Sensor), RPM_motor, FALLING); //Activo la interrupcion

}

void loop() {

    Lectura = digitalRead(Sensor); //Declaro que la Lectura es leida digitalmente en el pin del Sensor
    
    if (RPM >= 1000) {
    RetrasoEncendido    = 6;
    RetrasoApagado      = 4;
    }
    
    if (RPM >= 2000) {
    RetrasoEncendido    = 3;
    RetrasoApagado      = 2;
    }

    if (RPM >= 4000) {
    RetrasoEncendido    = 1;
    RetrasoApagado      = 1;
    }

    if (millis() - tiempo == 1000) { //Cada vez que pasan 1000 millis hace lo de abajo, si se altera esto cambias la duracion real de 1 segundo

    detachInterrupt(digitalPinToInterrupt(Sensor)); //Desactivo la interrupcion mientras calcula

    RPM = RPMcontados * 60; //Para una interrupcion por vuelta lo multiplico por 60 para saber las RPM

    Serial.print("RPM =\t"); //Escribe las RPM en cosola
    Serial.print(RPM); //Escribe las RPM en consola
    Serial.print("\t Hz=\t"); //Escribe los Hz en consola
    Serial.println(RPMcontados); //Escribe los Hz en consola

    RPMcontados = 0; // Reseteo el contador de revoluciones
    tiempo = millis(); // Actualizo el tiempo
    attachInterrupt(digitalPinToInterrupt(Sensor), RPM_motor, FALLING); //Activo la interrupcion
    }
    if (Lectura && !EstadoSensor) { //Si la Lectura no es igual al Estado del Sensor...
        EstadoSalida = !EstadoSalida; //...actualiza el Estado del Sensor a la Lectura
            if (EstadoSalida == HIGH) { //Si el Estado del Salida esta en HIGH...
                EmpezarRetraso = millis() + RetrasoEncendido; //...actualiza el "EmpezarRetraso" con el "tiempo" + el Retardo de Encendido
            }
        }
    EstadoSensor = Lectura;     // ...actualiza el Estado del Sensor a la Lectura

    if (EstadoSalida == HIGH && millis() > EmpezarRetraso) {
        EmpezarApagado = millis();
        EstadoSalida = !EstadoSalida;
        digitalWrite(Salida, HIGH);
    }
  
    if (millis() - EmpezarApagado > RetrasoApagado) {
        digitalWrite(Salida, LOW);
    }
}

void RPM_motor() {

    RPMcontados++; //Se suma 1 RPM cada vez que pasa por aqui

}