HArdware and timer interrupt to calculate a frequency

Not a big coder but a big learner.

Need to accurately find the generated frequency of a small generator motor to know its state and if all is running well.

I have Hall effect sensor that read the magnet of the flywheel every turn it does. This is on pin 2 of my arduino nano atmega328p 16 mhz. so it is configured to do an interrupt on rising of pin 2.
While this works ok, I am searching for way to count precisely time.
I was told that I could use timer0,1,or 2 for interrupts and that with prescaler, I know those are a bit picky.

S0 the goal is every time the timer1 running at 10khz do a cycle, it add 1 to a variable. while this go on, the input 2 create some interrupt,the isr routine copy the value of the timer1 variable and reset the timer1 to 0 ,the collected value is let say 823 in the variable.

So the hall effect sensor detect the magnet of the flywheel every 823 one 10 thousand of a second. SO to calculate the frequency we need to do that calculation. 1/(823/10000) so 823/10000= 0,0823 1 /0.0823 = 12.15 hz on a generator. DO you think that will be too much for an arduino nano?

It will also deal with a few relay to start the generator, open/close the choke, stop the generator, open and close the main breaker with a linear actuator. but those are not time critical as the rpm counter.

Do you think this will be to much demand on the arduino nano?

I dont need any display, but I do have a 16x2 lcd I could use.

What do you all think?

Pierre
VE2PF

You sound like you are recreating the setup on Timer0 that drives millis. If that's what you want, then you can just use millis or micros to figure the time between two interrupts.

If you want something more accurate, then use the input capture function on Timer1. It will require moving the input to pin 9 or 10, but it's a great way to measure frequency if nanoseconds count.

Measure the time between interrupts. Use the formula 60000UL / milliSecondTime, or 60000000UL / mictoSecondTime. This gives You RPM.

Hello OM Pierre

Use a simple ISR to count the events and a timer to read out these events per second (example).

Another approach is:
Operate Timer/Counter-1 to generate 5-sec time slot (repetitive) during which the interrupts events (say: n) will be accumulated is a variable. The RPM of the wheel would be:

RPM = (n/5)*60 rev/min

Or
If you want to avoid the interrupt strategy, then let the TC-1 be generating 5-sec time slot in the background. You keep counting the wheel turning pulses until 5-sec time has elapsed and then compute the RPM.

Watch out when using millis(). Sometimes millis() advances with 2 milliseconds at a time, so when measuring short times, deviation can be large.
You might want to use micros(), this advances with 4 microseconds each time, giving a far better accuracy. In the ISR that is triggered by your Hall-sensor, read micros(), subtract the previous reading and you can calculate the frequency (1,000,000UL / (presentMicros – previousMicros)) or RPM (60,000,000UL / (presentMicros – previousMicros))

volatile unsigned int presentRPM = 0;

void calculateSpeed() {
  static unsigned long previousMicros = micros();                 // remember variable, initialize first time
  unsigned long presentMicros = micros();                         // read microseconds
  unsigned long revolutionTime = presentMicros - previousMicros;  // works fine with wrap-around of micros()
  if (revolutionTime < 1000UL) return;                            // avoid divide by 0, also debounce, speed can't be over 60,000
  presentRPM = (60000000UL / revolutionTime);                     // calculate
  previousMicros = presentMicros;                                 // store microseconds for next time
}

void setup() {
  attachInterrupt(digitalPinToInterrupt(2), calculateSpeed, RISING);  // define interrupt
}

void loop() {
  // use presentRPM here
  // also possible: presentFreq = (float) presentRPM / 60
}

Compiled, not tested.
No need to access registers.

Exactly. Unsingned long when reading millis() or microSeconds(). For low RPM this method gives a higher resolution than counting events in a time slot.

Will not work I think. Both varibles are set when reading micros?

The static local variable previousMicros will be remembered next time, and will be initialized at the first time the function is executed.
The local variable presentMicros will be set every time the function is executed, and thrown away at the end of the function.

Thanks! I feared my remark missed something.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.