The circuit I've built simply takes the mains and outputs half-wave rectified AC (top half of the sine wave) at 5v peak. For what the Arduino does with this see the above link. The schematic is at:
Now, what I don't understand is why periodically I get a totally erroneous reading. The meter needle bounces across the scale and then back to near the subsequent reading. Sometimes these events are some time apart and sometimes the thing seems to get caught in a brief frenzy of them.
I think there is always at least one correct reading after every bad one, so I could maybe say if delta
greater than N then use last reading, or something. But this would be a bit of a fudge.
I've pasted two sequences of measurements each containing an erroneous reading
as examples below.
I believe you are seeing the value of micros() wrapping.
long now = micros();
The value of long climbs normally until it reaches 2^31 at which time it becomes a huge negative number, which gradually increments back to zero.
You should probably use unsigned longs for these values, and have some code to deal with when now < lastTime which will happen each time micros() wraps from 2^32 to 0.
Too add a little more explanation, micros() overflows every 70 minutes. If you are using a signed variable to store it, that means you're going to see the "overflow" every 45 minutes.
Both, many thanks for the advice! I'm a complete newbie to software development, so I'll take some time to look into your suggestion and to try to implement this change.
Whilst it sounds like the issue you outlined would certainly cause problems, I'm not seeing this issue after, say, 45 minutes of being powered up. It can start after a much shorter period of time has elapsed, and then the interval between the errors appears "random" and, again, much shorter.
I've seen this problem in my work also. When I borrowed an oscilloscope and watched it the problem (naturally) didn't happen. I finally just decided it was some transient that was running down the wire and caused my problem. I then measured the frequency more often and kept a rolling average for a short period. That solved my problem. How many times you measure and how long you hold the average for is a function of what you need to do so some experimentation may be in order. I currently go for a full second to get my numbers.
gardner:
I believe you are seeing the value of micros() wrapping.
Errors can occur almost immediately after the program has started running. I added another Serial.print to show the current value of 'long now = micros()' at the time of an error.
The larger errors appear to be an additional 1.2% (relative to the background error) or off by nearly one count in a hundred.
And the code counts to 100:).
Perhaps there are occasional glitches ( higher frequency noise ) in the shape of power line, so there are three crossings of 1.1v on one side of the sine curve, and the comparator noticed two of them - so your count reached 100, half a cycle too soon.
Could you put a low-pass filter on the input?
This has a negligible chance of changing the result - you are doing a little more than reqd with interrupts disabled..
you could move the now = millis(); to before the cli();
So, I don't doubt that long rollover could cause a problem, but this is not my main concern right now
It is about to become a problem. Fix the data-type.
No matter have careful you are, your application is always going to have some "jitter". Some things that will cause jitter: millis sometimes skips a value; Serial.print is blocking; your code has many expensive math operations.
Any given reading may be a bit high or a bit low. If your code is correct, the long term average should be dead-on. You need to let your application run for several minutes and calculate an average frequency. If that is 50 Hz, you know your basic strategy is sound. Then you can work on reducing the jitter.
On a side-note, I suggest a change at the top of loop...
void loop() {
cli();
if (count >= 100) {
count -= 100;
sei();
[glow=lime,2,300]long now = micros(); // Move this after interrupts have been restored[/glow]
The fact that all the frequencies are above 50Hz makes me wonder whether there is a flaw in your measurement technique. Either the measurement interval is slightly too long, or you're somehow getting double-accounting of samples at the start/end of a sample interval, or the input event is being triggered more than once per AC wave. How many AC cycles do each of those frequency calculations include? Have you confirmed that the long term average frequency of detected events is actually 50Hz?