Scenario: Arduino(Mega)
Misura di velocità con rilevamento IR su albero con rifrangente, Velocità 60÷300rpm
Ho fatto 2 differenti approcci alla misura:
1) Misura impulsi in isr su finestra temporale fissa
2) Misura dT(microsecondi) sempre in isr tra 2 impulsi, e calcolo in Loop.
Il primo appoccio stando la bassa velocità non è in grado di dare rilevamenti significativi se non aumentando il Tempo finestra di campionamento ma la risoluzione rimane di 60rpm, ho ovviato con ruota fonica a 20 tacche migliorando sensibilmente il risultato, in questo caso la risoluzione non può scendere sotto i 3rpm, se non ho sbagliato i conti.
Questo metodo introduce peraltro un DELAY del tempo finestra, in cui se non erro, il processore non processa nulla, salvo le azioni in isr, ma siccome oltre alla velocità dovrà fare altre cose... non mi piace molto... oppure sbaglio...?
Il secondo sembra non soffrire di grossi problemi, ed offre un grado di precisione teorica migliore con queste bassissime velocità, ed il ritardo introdotto è inversamente proporzionale alla velocità, per come ho scritto il codice che mostro dopo.
Ora diciamo che entrambi danno "un risultato", che sia un risultato da ritenere buono è un discorso differente.
Le misure hanno grosse variazioni, soprattutto nel 2° Approccio, ed avrei pensato di introdurre un filtro.
Mostro banalmente i 2 codici di test, uso questo linguaggio da 2 settimane, quindi sono molto acerbo, pensavo, semplificando molto le cose, di usare un'array, escludendo i valori toppo alti o troppo bassi, e calcolare la mediana.
Quì mi fermo e Vi chiedo una spinta.
Mostro il codice di test:
PRIMO APPROCCIO
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);
const byte interruptPin = 2;
float rev=0;
int rpm;
unsigned long oldtime=0;
unsigned long time;
void isr() {rev++;}
void setup()
{
Serial.begin(9600);
lcd.init();
lcd.backlight();
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin),isr,RISING); //attaching the interrupt
}
void loop()
{
delay(1000); // 1 second delay
detachInterrupt(digitalPinToInterrupt(interruptPin)); //detaches the interrupt while calculating
time=millis()-oldtime; //finds the time
rpm=(rev/time)*60000; //calculates rpm
oldtime=millis(); //saves the current time
rev=0;
lcd.setCursor(0,0);
lcd.print("RPM:" + String(rpm));
attachInterrupt(digitalPinToInterrupt(interruptPin),isr,RISING); //attaching the interrupt
}
SECONDO APPROCCIO:
#include <LiquidCrystal_I2C.h>
uint32_t volatile t; // per misura periodo in microsecondi
uint8_t volatile s; // stato processo misura
uint32_t rpm=0;
const byte interruptPin = 2;
LiquidCrystal_I2C lcd(0x27,20,4);
void setup()
{
Serial.begin(9600);
lcd.init();
// Print a message to the LCD.
lcd.backlight();
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), isr, RISING);
}
void loop()
{
// avvia e attende misura 't' da ISR
for (s = 0; s != 2; ) {}
if (t > 60000L) // se < 1000 rpm calcola RPM da 't' (errore 0.05 rpm, +/-1 rpm)
{rpm = 60000000L / t;}
lcd.setCursor(0,0);
lcd.print(rpm);
lcd.setCursor(0,2);
lcd.print(t);
}
void isr(void)
{
if (s == 0) { t = micros(); s = 1; }
else if (s == 1) { t = micros() - t; s = 2; }
else { }
}