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();
}
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ì:
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.
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?
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.