0

I am trying to build a rev counter using a Hall effect sensor and an Arduino Uno. I'm using Arduino software and I have wrote the following code:

#include <LiquidCrystal.h>

int sensorPin = 2; // hall effect
float revs;
float rpm;
volatile byte rpmcount;
long previousmicros = 0;
long interval = 500000;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);


void setup() 
{
  // setup serial - diagnostics - port
  Serial.begin(115200);
  // setup pins
  pinMode(sensorPin, INPUT);
  // setup interrupt
  attachInterrupt(0, RPM, RISING);
}

void RPM()
{
  rpmcount++;
} 

void loop() 
{
  unsigned long currentmicros = micros();
  int sensorValue = digitalRead(sensorPin);        // sensor value is read
  if (currentmicros - previousmicros > interval)  
  {
    previousmicros = currentmicros;

    detachInterrupt(0);
    revs=10.0/rpmcount;
    rpm =600.0/revs;
    Serial.print("rpmcount : ");
    Serial.print(rpmcount);
    Serial.print("  rpm : ");
    Serial.println(rpm);
    lcd.clear();
    lcd.begin(16, 2);
    lcd.print("RPM = ");
    lcd.setCursor(6,0);
    lcd.print(rpm,0);
    rpmcount=0;
    attachInterrupt(0, RPM, RISING);
  }
}

This works and measures the RPM correctly however the value is always a factor of 60. How can I change this so that it will measure the RPM more accurately, to say +-5 RPM? I tried playing about with my revs and rpm formulas but had little success.

gre_gor
  • 6,669
  • 9
  • 47
  • 52
c_user
  • 41
  • 1
  • 9
  • Sidenote: You should minimize the time interrupts are disabled. Read `rpmcount` to local variable and zero it, then re-enable interrupt before using serial port or lcd. – user694733 Mar 30 '17 at 10:45
  • Is your formula correct? Shouldn't it be `rpmcount * 60000.0 / (currentmicros - previousmicros)` ? – Klas Lindbäck Mar 30 '17 at 10:46

2 Answers2

0

Right now you have

rpm =60.0*rpmcount;

You will have to store the count over a longer time and calculate the value from that (or change how often loop is run)

Dawnkeeper
  • 2,844
  • 1
  • 25
  • 41
  • I see, so this would involve changing my `interval` value right? does this mean in order to be more accurate I will have to sacrifice for a slower update time? @Dawnkeeper – c_user Mar 30 '17 at 10:46
  • Reducing your interval will increase how accurately you read the value, but also increase the error due to bad timing of calculating the results. To reduce this again you can e.g. generate a running average of multiple loops. – Dawnkeeper Mar 30 '17 at 11:14
  • @c_user If the measurement is an integer then the resolution is `60000/interval`. If you measure 1 sec you get multiples of 60. To get multiples of 5 you need to measure 12 sec, because 60000/12000 = 5. – Klas Lindbäck Mar 30 '17 at 11:18
0

In the ISR instead of increment a count, compute the amount of time elapsed since the last ISR fire.

unsigned long someArray[2] = {0,0};
unsigned char rpmindex = 0;

void RPM_isr()
{
   rpmindex ^= 1;
   someArray[rpmindex] = micros();
} 

// And then in the main body

{
   // Disable interrupts
   // Copy someArray to a localArray
   // reEnable interrupts
   // Compute the interval between ISR fires
   unsigned long interval = abs(localArray[0] - localArray[1]);
   // Compute RPM
   unsigned int rpm = (60*1000000)/interval;
}

Pseudo code interpreted at your own risk.

Edit: For bad math on RPM computation.

Derek
  • 58
  • 3