I have been reading through a lot of posts about measuring the frequency of the mains supply lines, and there seems to be no real consensus on how to do it with an Arduino. I was wondering, could I just step 120 V down to 6 or 12 V, filter it with a diode, drop it across a voltage divider and count the pulses on an analog input, then do a little math in code to get a relatively accurate value for my supply frequency?
What I want to accomplish ultimately is to have a readout of an engine shaft RPM and attached alternator frequency. It seems simple, but the massive amounts of other similar debates makes me think otherwise.
Well, I will be measuring around 60 Hz, if I'm at 59 or 61, I won't be too concerned. This will be used to govern the speed of an engine powering an alternator for small power generation. The closer I can keep the frequency to 60 Hz the better, but a Hz one way or the other won't matter too much.
Great, thanks for the replies. I rigged up a quick test circuit to monitor the half rectified pulses output by a voltage divider and diode filter on the serial monitor. It works well to show the pulse train with the appropriate delay timing. Now I'm at a loss on how to translate that train into a meaningful frequency.
What function do I use to count the pulses so I can do a conversion operation on them to output hertz?
Cool, I'm going to have to study this for a bit because I don't get all that's going on there. Will using an interrupt cause any problems with other functions the controller will be running? For example, once I start sampling the frequency, I will output it to a display. Attaching and detaching interrupts won't affect those processes will it?
InPhase277:
Cool, I'm going to have to study this for a bit because I don't get all that's going on there. Will using an interrupt cause any problems with other functions the controller will be running? For example, once I start sampling the frequency, I will output it to a display. Attaching and detaching interrupts won't affect those processes will it?
Should be fine. No need to detach the interrupt, just let it run. It's about as fast as an interrupt can be, just incrementing a variable and at a very low rate besides. Shouldn't interfere with anything.
It could be fancied up some, a 1-second timer interrupt could pick up the count, and put it in another variable for the main code. So the whole thing would run under the covers in the ISRs.
InPhase277:
Where can I find this atomic.h header? Safely, I mean.
It's part of AVR-Libc, which is part of the Arduino IDE. That sketch will run as-is on your Arduino.
When sharing variables between an ISR and interruptible code like in main(), it is important that the variables are accessed "atomically" meaning the main code has to complete a read or write of the variable in a non-interrupted fashion. All the ATOMIC_BLOCK macro does is to ensure that the two lines of code in the block are executed without being interrupted.
One problem that can arise if this is not done is that data can get corrupted. The variable cycleCount is a two-byte int, therefore it may take two operations to read or write it. If an interrupt occurred when only one byte was read or written, and the code in the interrupt also updated the variable, its value would be corrupted.
The other thing that should always be done with variables shared between an ISR and other code is that they need to be declared volatile. This ensures the compiler places the variable in memory instead of in a register, which will sometimes happen for efficiency.
OK, I tried the code with a circuit fed from a 12 V transformer, through a diode bridge rectifier and stepped down to 3 V through a voltage divider. I get the expected 120 Hz ripple to display on the serial monitor, but the problem is it isn't very stable, even if I run it through some averaging code. It may jump to 125 or 138, or any random number above 120 Hz. It especially happens when something on that same circuit comes on or off (e.g. fridge). At first I thought it was the lagging phasing of the transformer as voltage varied on the supply side, but my multimeter shows a rock-solid 120 Hz no matter what.
Is there something inherently wrong with my circuit idea, or is the Arduino interrupt flaky, or what?
OK, I tried the code with a circuit fed from a 12 V transformer, through a diode bridge rectifier and stepped down to 3 V through a voltage divider. I get the expected 120 Hz ripple to display on the serial monitor, but the problem is it isn't very stable, even if I run it through some averaging code. It may jump to 125 or 138, or any random number above 120 Hz. It especially happens when something on that same circuit comes on or off (e.g. fridge). At first I thought it was the lagging phasing of the transformer as voltage varied on the supply side, but my multimeter shows a rock-solid 120 Hz no matter what.
Is there something inherently wrong with my circuit idea, or is the Arduino interrupt flaky, or what?
The 3V full wave signal would have a slow rise time and since it's full wave rectified sine, the Arduino would mostly be detecting a high level.
Ideally, it would be best to have a 1/2 wave signal (60Hz) connected to the Arduino. If you used a 1K resistor in series with the 12V and clamped it to 5V with a zener diode, then the signal would be more like a 60 Hz square wave with 50% duty cycle. This should be easier to detect and count by using a digital input.
The circuit in Reply #7 looks good - it would also produce a 60 Hz square wave. An optional 10K pull-up on pin D2 would provide a stronger signal and sharper edges.
Thanks everyone! That circuit and FreqPeriod library from reply #7 was the best way to go. It is spot on and any fluctuation is in the 1/100s of Hz. And it of course reads much higher frequencies too, so it will be handy on many audio projects as well. 8)