Grid Frequency Monitor

I came across a cute little project in a back issue of Elektor, January 2012. It described a LED bar display that shows the current mains frequency. Now during the day, when the grid's load varies, the frequency varies with it. Its target controller is a 8051 family member and the software was written in Bascom. These are two things missing from my inventory. However, I was intrigued by the concept and decided to build my own.

The hardware is pretty simple. With an external crystal oscillator, my favorite controller PIC16F628A has 13 I/O lines. Two I/Os are needed for the crystal and the reset input is also not available. The line frequency is monitored via the RB0 interrupt so there are 12 outputs to connect LEDs to. This leads to the following configuration: 2x red, 2x yellow, 4x green, 2x yellow and 2x red:

I chose a measurement range of 49.90 to 50.10 Hz in 20 mHz steps. I had a transformer handy and quickly built an experimenter's board with all the parts. The power supply capacitor is very small (47 µF) because the circuit draws very little current. The schematic is very simple: power supply, PIC and 12 LEDs. I used some SMD components because they fit so nicely in a 0.1" pattern, especially the 0805 size. The mains side needs some attention: removed some copper pads to provide separation between mains connected parts.

Now the hardware was complete I could delve into the MPASM IDE. Eventually I got to this program (assembly file). As always, the interrupt vector is at the start of the program, the reset jumps to START. Here everything is initialized. Once running, only the interrupt routines are executed. First the lamp test which runs only as long as its flag (LAMPTST, duh!) is set. Every RB0 interrupt the TIMER1 LSB is saved to calculate a moving average. Because I wanted to keep it in a single byte the number of averages is 4. This takes away some of the jitter always present in the mains waveform. The measured time of 20,000 µs is 0x4E20, so the LSB used as X[i] for the moving average is around 0x20. Because this gets out of range at higher frequencies (and shorter time) I added 0x28 (also to compensate for additional delay in the code) and RRL'd the value so that the range is halved. Once the moving average is calculated (found the principle somewhere on the net) the LED to switch on is looked up with 11 compares. Of course the final compare isn't needed, same as with the lamp test. As always, getting the routine working properly needed some simulating. The decoding of the final result is done only once every half second thereby discarding lots of measurements but making the display readout much nicer as the flickering of LEDs is removed. Oh, and there are no subroutines.

Getting the measurement working properly also involved a test jig:

This little circuit divides the output of my signal generator by 1000 reducing its frequency from 50.000 kHz to 50.000 Hz in 1 mHz steps. It plugs directly onto the pins on the board next to the PIC. With it I finally could produce these readouts:

Bugs/issues: when powered on, the lamp test is not always shown. I decided not to pursue this issue because it isn't that important to have a lamp test, innit? Edit: this was fixed by doing lamp test before enabling global interrupts (GIE).

Finally, why "Netzlupe"? Well, this was the name of the program in Elektor magazine. It's nice and short and perfectly descriptive even if it's in German:

Thoughts on improvement: the measurement range could be expanded by appointing two output lines to external PNP transistors and switching two banks of 10 LEDs alternatingly. This would just not fit on a eurocard experimenter's board short side by needing 39 islands and only having 38 holes available. And if you really don't want to build a device like this, just go to the official European mains frequency monitor. Which has a 1 mHz accuracy to boot! Only thing missing there is a nice big frequency display, but the scale is awesome!

See also analog Netzlupe!

Back to the homepage

Date: 24 July 2017, updated 24 February 2019 (v1.8: bugfixes, sanity check)

This software is licensed under the CC-GNU GPL.