Rather than show the whole sketch heres the function that does it… or should, anything glaringly wrong?
void findRPM()
{
static unsigned long oldTime;
unsigned long currentTime;
unsigned long timeDiff;
unsigned int blah;
while (digitalRead(12) == LOW) {blah =0;} // pause code waiting for a pulse, theyre regular enough so dont need to wait long
currentTime = micros();
for (int i = 0; i < 4; i++)
{
while (digitalRead(12) == LOW) {blah =0;} // taking the time difference between 4 rev samples...
}
timeDiff = micros() - currentTime;
Serial.println(timeDiff);
RPM = 1000000 / (timeDiff / 4) * 60; //uses 4 rev samples to get a fair average between them also creating higher accuracy
////// code to calculate RPM here
//random generator with more realistic increases decreases....
// RPM = random((RPM - 1500),(RPM + 1500));
// RPM = (RPM <0) ? 0:RPM;
// RPM = (RPM > rpmRange) ? rpmRange:RPM;
}
To keep your interrupt service routine short (always a very good idea) you can also simply log the timer value at each interrupt to a variable, and do the actual time calculations in your main loop.
Oh and in my code above im doing it via 4 pulse averages…
But hall effect? This is the RPM portion, not the mph side…
Though on my MPH side im going to read it off the MPH cable thats attached to a optical interrupt… IE mouse wheel sensor…
Then then in your display code, read that value and convert to RPM ( as your display code runs at a fixed interval)
then zero the global value
In your ISR just increment that gobal

http://docs.leaflabs.com/static.leaflab … rrupt.html
I think the only thing to be aware of, is how often your display RPM function is called versus how often the RPM interrupt is triggered.
e.g. at 1500 rpm, you will only get 25 pulses per second. and if your display function is called every 100ms you will only have 2 or 3 pulses between display updates.
This causes a lot of inaccuracy. (but you can average out the 2 or 3 pulse problem)
Or even better use a longer sample window, i.e actually get the pulse count every 250ms or 500ms and animate your RPM display to the new value over 250 or 500mS
There is also a very technical way to get the STM32 to measure the pulse width (or distance between pulses) called Timer Input Capture mode.
Someone did a blog post of how to do it with bare metal coding of the STM32
http://embedded-lab.com/blog/stm32-timers/
This allows very accurate measurement of incoming pulses, as I think it runs a counter (from a divider off the main CPU clock). But I”m not sure if it has a mode where the counter is started by one pulse and stopped by another – it seems like a feature it should have, but you’d need to read the master programming doc (which is somewhat hard going)
Personally, I’d get it working with the ISR method and perhaps upgrade to the Timer Input Capture at a later date.
Going to convert that to rpm counting and measuring like you said averaging out over so many samples. once i got all that tied down ill add it to the main project code.
I think the guy i used to know meant that timer based way of doing things very accurately… But yeah I think that might be a tinsy bit out my league
Trouble is its not really accurate. Unless the pulse generator isn’t working quite right and is werbling a little even though its set to 1000…
Ive tried fiddling with the code to produce slightly sharper timing and its not made any difference… 1000rpm is coming up as around 1900-2500 rpm
5000 rpm is coming up at around 4800-5200 ish.
Now what is odd is I got the numbers on serial print and theres a pattern to the inaccuracies… Its not randomly inaccurate.
Even when I got the RPM calculator running once a second the numbers are still inaccurate by quite a noticeable amount. Its close but not there yet…
Heres the sketch im using as a test
#include <Thread.h>
#include <ThreadController.h>// new scheduler
ThreadController controll = ThreadController();
Thread ReadRPM = Thread();
long rpmSample = 0;
unsigned long oldTime = 0;
unsigned long timeDiff = 0;
long RPM;
void setup() {
Serial.begin(9600);
pinMode(33, OUTPUT);
pinMode(12, INPUT);
ReadRPM.onRun(findRPM);
ReadRPM.setInterval(100);
controll.add(&ReadRPM);
attachInterrupt(12, sampleRPM, RISING);
oldTime = micros();
}
void findRPM() {
RPM = 1000000 / ((micros() - oldTime) / rpmSample) * 60;
rpmSample = 0;
//oldTime = micros();
Serial.println(RPM);
}
void loop() {
controll.run();
}
void sampleRPM() {
//This if sets the oldTime, this was in the findRPM loop but I put it here in case the oldtime
//varible wasnt capturing the correct microsecond on the first sample, dunno. Didnt make a difference.
if (rpmSample == 0) {
oldTime = micros();
}
rpmSample++;
}
// RPM = 60 * (1/timediff in seconds)
RPM = 60*(1000000/(micros() - oldTime )) ; // i.e. RPM = 60 seconds divided by (1000000/(timediff uS))
if (micros() < oldTime) {
// handle the overflow (or throw away this sample)
}
You can either set the timer to generate an interrupt when it overflows, and compare the time between overflows, or just read the timer value every X milliseconds and compare the timer counter increase in that period. You can also set pre-escalers. It all depends how many RPMs you are measuring and how much variance is between the minimum and the maximum speed.
If you are measuring a high RPM value, polling a pin or serving and interrupt per revolution would consume a lot of cpu time, while with a hardware timer you dont consume any cpu time to count the cicles, only to check the timer value as often as you want, or to server the timer interrupt on overflow, which can be more or less frequently depending on the pre-escaler and the overflow value.

I did mention Input Capture in one of my replies to this thread http://www.stm32duino.com/viewtopic.php … 322#p17059 but I think @nutsy hoped he could do it just using an ISR
But it does now sound like the Input Capture method would give a better value that counting over a known time period (as the number of pulses is too few)
Well the interrupt counting seems to be working well enough currently.
I thought I had a suitable protection transistor to test the real RPM signal but i might have wired it up wrong and pin 12 has died :p
I’ve designed and ordered parts for a opto isolator setup to read the rpm safely… Then ill test again with another pin…