@Martin,
Well, I don’t really use Github as a blog for discussions. Maybe this should instead be moved to the software related section of the EEVblog? No idea how to do that apart from creating a new topic.
In the mean time and just to put minds at rest...
The comment you quote is true but only applies in the range below 2Hz. Let me explain:
The basic restriction is that the PIC is edge triggered. You can select whether you want the rising or falling edge initially during setup but that is it. The original frequency counter simply counted the number of edges within the gate time (e.g. 1s). For RPM measurements that is way to coarse, so I implemented a reciprocal measurement of the period at low frequencies. In that mode, my software needs to see at least 2 (say falling) edges = 1 period within the measurement time which is 1 second as the longest gate time used for very low frequencies. That condition is only guaranteed if the frequency is >= 2Hz, hence at frequencies below 2Hz to 1Hz the display flips between showing the correct value, e.g. 1.23Hz and 1Hz, depending if 1 or 2 falling edges were detected within the measurement period. The closer you get to 1Hz the more likely is it that you just see 1 instead of 1.xx. From 1Hz and below you just see zero. This is what the comment meant. It starts working from 1Hz onward but for a fully steady display you need 2Hz or more.
Ok, let's keep the discussion here as it is really covered by "Projects, Designs, and Technical Stuff".
I see the limitation below 2 Hz, but this was not my idea. Instead I want to understand how you solved it in the higher Hz ranges. You explained your reciprocal measurement with an example for 50.123 Hz:
If the frequency is above 1Hz and below 200Hz, reciprocal measurement is used where my software measures the time from the start of the first period all the way to end of the last full period within the measurement period, and counts the number of full periods, it saw. Example, at 50.123Hz, a period is 19.95ms and 49 full periods fit into 1 second, So the total accumulated time measured would be 0.9775s. 49 would then be divided by this to get the frequency. Crucially these are not 49 separate measurements where each could be affected by missing an edge. Instead this is is one continuous measurement period and all edges are detected.
In reality, the time within this software is measured in 20us increments and is stored as a 16bit integer. So 0.9775s equates to the value of 48879. This simplification introduces an error of up to 20us. The poor 8-bit PIC is then doing a 32-bit multiplication of 49 * 50000*1000 and then divides that huge number in another 32-bit operation by 48879 to get the result of 50123. This is the frequency in milliHertz which is then rounded to 2 decimals and shown as 50.12Hz. Should the PIC see only 48 instead of 49 full periods, because of just missing the first edge, it simply uses the values for 48 periods and comes to the same result. Its slightly more complex than that but in principle this is how things work.
This algorithm works up to 255Hz but I decided to draw the line at 200Hz and switch back to the original mode, because in reciprocal mode the accuracy gets rapidly worse the higher the frequency because the 20us is just too coarse for measuring smaller periods. Sadly changing the 20us inherited from the original firmware without a complete redesign of the software is not possible.
Maybe we can reuse some of your effort, so let me put my thoughts step by step:
- If you measure e.g. 1000.0 Hz for one second (i.e. 50000 ticks of 20 µs) then you will get a period length of 1000 µs and 999 full periods.
Total accumulated period time is 999000 µs, giving 49950 ticks, the reminder to the 50000 ticks (=1 second) is 50 ticks.
- If you measure e.g. 1000.1 Hz then you will get a period of 999.9 µs and 999 full periods.
Total accumulated period time is 998900 µs, giving 49945 ticks, reminder 55.
- If you measure e.g. 1000.2 Hz then you will get a period of 999.8 µs and 999 full periods.
Total accumulated period time is 998800 µs, giving 49940 ticks, reminder 60.
So the reminder to the full 1 second period of 50000 ticks increases with increasing sub-Hz frequency.
IIRC this 499xx value (the full period tick sum) is always available even for higher frequencies.
All we have to do is to calculate the length of one period (in ticks), in my 1000 Hz example i.e. 50 ticks.
This value is calculated by "one_period = 50000 / int( frequency )"
And if you calculate finally "x = reminder - one_period" you will get x = 0, 5, 10, 15,... i.e. 1/50 Hz resolution.
Same calculation for 2000,x Hz gives 0, 3, 5, 8, 10,... so even in higher ranges we have the possibility to get down to 0.1 Hz resolution.
For 9999 Hz the resolution drops to 0.2 Hz.
But in the range 200..999 Hz we could for sure get one valid decimal digit.
I never considered extending the counter the other way, i.e. below 1Hz operation. The only way to do that would be to extend the gate time / measurement time. That would be fairly easy but having to wait 10 or 100s for each display update seems not very useful.
I totally agree!