Contagiri funziona ma...

Ciao a tutti ho rubacchiato in rete questo scketch modificandolo in base alle mie esigenze.
Funziona molto bene, l'ho comparato con i dati letti da un contagiri ottico e sono praticamente identici.
Vorrei però che al fermarsi del motore il dispaly segni 0 giri al minuto e non l'ultimo valore che legge prima di fermarsi.
Qualcuno sà aiutarmi?
Allego lo scketch.

#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

volatile float time = 0;
volatile float time_last = 0;
volatile int rpm_array[5] = {0,0,0,0,0};

void setup()
{
  
  
      lcd.begin(16, 2);
      lcd.print("    xxxx");
      delay(3500); lcd.clear();
     lcd.begin(16, 2);
      lcd.print("xxxxxx");
      delay(2000); lcd.clear();
     lcd.begin(16, 2);
      lcd.print("  xxxxxxx");
      delay(2000); lcd.clear();
      lcd.begin(16, 2);
      lcd.print("  xx xxxxxxx'");
      delay(2000); lcd.clear();
     lcd.begin(16, 2);
      lcd.print("   xxxxxxxxxxx");
      delay(2000); lcd.clear();
      lcd.begin(16, 2);
      lcd.print("xxxxxxx.);
      delay(3000); lcd.clear();
      lcd.begin(16, 2);
      lcd.print("RPM:");
  //Digital Pin 2 Set As An Interrupt
 attachInterrupt(0, fan_interrupt, FALLING);

  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Giri al minuto:");
  
  
  
  
}

//Main Loop To Calculate RPM and Update LCD Display
void loop()
{
  int rpm = 0;
  
  while(1){    

     //Slow Down The LCD Display Updates
  delay(400);
  
  //Clear The Bottom Row
  lcd.setCursor(0, 1);
  lcd.print("                ");   
  
  //Update The Rpm Count
  lcd.setCursor(0, 1);
  lcd.print(rpm);   

  ////lcd.setCursor(4, 1);
  ////lcd.print(time);   

  //Update The RPM
  if(time > 0)
  {
    //5 Sample Moving Average To Smooth Out The Data
      rpm_array[0] = rpm_array[1];
      rpm_array[1] = rpm_array[2];
       rpm_array[2] = rpm_array[3];
      rpm_array[3] = rpm_array[4];
      rpm_array[4] = 60*(1000000/(time*13));    
    //Last 5 Average RPM Counts Eqauls....
        rpm = (rpm_array[0] + rpm_array[1] + rpm_array[2] + rpm_array[3] + rpm_array[4]) / 5;
  }
 
 }
}

//Capture The IR Break-Beam Interrupt
void fan_interrupt()
{
   time = (micros() - time_last); 
   time_last = micros();
   }

Il codice si allega usando gli appositi tag (vedi come ho modificato il tuo messaggio).
Tornando al tuo codice, in fondo c'è questo if:

if(time > 0) {
  ....
}

Che stampa il valore. Devi solo aggiungere un "else" e stampare 0. Quindi la logica dell'if diventa:

se "time" è maggiore di 0 allora scrivi il valore
altrimenti scrivi 0

grazie Leo72 ho modifica cosi ma ora segna sempre 0 anche quando gira.

 //Update The RPM
  if(time > 0)
  {
    //5 Sample Moving Average To Smooth Out The Data
      rpm_array[0] = rpm_array[1];
      rpm_array[1] = rpm_array[2];
      rpm_array[2] = rpm_array[3];
      rpm_array[3] = rpm_array[4];
      rpm_array[4] = 60*(1000000/(time*13));    
    //Last 5 Average RPM Counts Eqauls....
      rpm = (rpm_array[0] + rpm_array[1] + rpm_array[2] + rpm_array[3] + rpm_array[4]) / 5;
  }
  
  //Segna 0 quando è fermo
  else(time < 0);
  {
    
      rpm = (0);
 }
 
 }
else(time < 0);
  {
    
      rpm = (0);
 }

Questo codice non ha senso perché rpm=(0) non fa parte del blocco if..else ma è un blocco a sé stante, dato che l'else non vuole condizioni di test e quindi (time<0) il C lo interpreta come istruzione da eseguire se time non è maggiore di 0.
Scrivi così:

else {    
      rpm = (0);
 }

Cosi facendo funziona come all'inizio.
Quando si ferma segna l'ultimo valore letto.

 //Update The RPM
  if(time > 0)
  {
    //5 Sample Moving Average To Smooth Out The Data
      rpm_array[0] = rpm_array[1];
      rpm_array[1] = rpm_array[2];
      rpm_array[2] = rpm_array[3];
      rpm_array[3] = rpm_array[4];
      rpm_array[4] = 60*(1000000/(time*13));    
    //Last 5 Average RPM Counts Eqauls....
      rpm = (rpm_array[0] + rpm_array[1] + rpm_array[2] + rpm_array[3] + rpm_array[4]) / 5;
   }
  
  //Segna 0 quando è fermo
  else {
            rpm = (0);
 }
 

 }
 }

Non Ti funziona perché RPM non sará mai zero.
Se non ci sono impulsi dal sensore la variabile TIME non viene aggiornato perché non ci sono interrupt e percui resta il valore letto prima.

Altri errori:

volatile float time = 0;
volatile float time_last = 0;
volatile int rpm_array[5] = {0,0,0,0,0};

Non puoi usare variabili di tipo float per time_last. Deve essere unsigned long.
Non puoi controllare se un float sia > 0 perché se é positivo lo é sempre.

Devi definire un tempo minimo al di sotto la velocitá di rotazione viene definito zero.

Ciao Uwe

Allora fai una cosa. Metti una variabile globale ("volatile", mi raccomando) e mettila a 0 fuori dalla routine di interrupt e ad 1 dentro alla routine di interrupt.
In questo modo sai che la routine è stata chiamata controllando che la variabile sia ad 1. Se noti che resta a 0 per un certo lasso di tempo (calcolato sul più lungo intervallo di tempo che puoi misurare), allora i giri sono a zero perché il volano/ruota/ecc è fermo. A me viene a mente questo.

Sinceramente non saprei da che parte cominciare, non ho le competenze per poterlo fare quindi ho trovato questo che ho appena provato e segna 0 da fermo.

/*
 * Optical Tachometer
 *
 * Uses an IR LED and IR phototransistor to implement an optical tachometer.
 * The IR LED is connected to pin 13 and ran continually.
 * Pin 2 (interrupt 0) is connected across the IR detector.
 *
 * Code based on: www.instructables.com/id/Arduino-Based-Optical-Tachometer/
 * Coded by: arduinoprojects101.com
 */

int ledPin = 13;                // IR LED connected to digital pin 13
volatile byte rpmcount;
unsigned int rpm;
unsigned long timeold;

// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

void rpm_fun()
 {
   //Each rotation, this interrupt function is run twice, so take that into consideration for 
   //calculating RPM
   //Update count
      rpmcount++;
 }

void setup()
 {
   lcd.begin(16, 2);  // intialise the LCD

   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, rpm_fun, FALLING);

   //Turn on IR LED
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH);

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   //Update RPM every second
   delay(1000);
   //Don't process interrupts during calculations
   detachInterrupt(0);
   //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
   //happened once per revolution instead of twice. Other multiples could be used
   //for multi-bladed propellers or fans
   rpm = 30*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;

   //Print out result to lcd
   lcd.clear();
   lcd.print("RPM=");
   lcd.print(rpm);

   //Restart the interrupt processing
   attachInterrupt(0, rpm_fun, FALLING);
  }

Un aiuto io ho 13 interruzioni del segnale, come modifico questa istruzione?

  rpm = 30*1000/(millis() - timeold)*rpmcount;

Ad occhio, 60/13 = 4.6

Ed hai perfettamente ragione, avevo scritto 4,6 anzichè 4.6.
Ora funziona!!!
Grazie mille Leo72

Cambia la logica dei 2 Sketch.
Il primo misura il tempo tra 2 impulsi e il secondo misura quanti impulsi arrivano in un certo tempo.

Il primo ha il vantaggio che la misura dura tempi brevi (il tempo tra due impulsi) ed é indicato per velocitá medio alte.
Il secondo ha il vantaggio che arrivi fino a zero, ma ha lo svantaggio che il tempo di misura é sempre alto per riuscire ad avere una risoluzione accettabile a giri molto bassi.

Ciao Uwe