I built a frequency counter using an ESP32 to measure frequency in Hz.

To measure mains frequency, I used a PC817 optocoupler. First I drove the LED of the optocoupler using 3.3 V PWM signal and measured it. The results were accurate.

Then I used a 200 kΩ resistor and a diode in reverse (for protection) to drive the optocoupler from mains 230V AC.

The microcontroller measured ~900 Hz. I reduced the resistor from 200k to 47k and the meter measured ~200 Hz,

The optocoupler has a 10k pull up.

Why does it behave this way? Is AC interfering with the measurements of the microcontroller?


Update: I used PWM on opto again and surprisingly it was not behaving the way it should and reading was messy. Used another (817) opto, it was fine but also got drunk after receiving a dose of 230 V AC

  • 1
    \$\begingroup\$ Have you got an oscilloscope to debug the problem? \$\endgroup\$
    – Justme
    Aug 16, 2022 at 22:29
  • \$\begingroup\$ @Justme unfortunately no \$\endgroup\$
    – asim
    Aug 16, 2022 at 22:31
  • \$\begingroup\$ Try splitting your current limiting resistor into two resistors, each with half the total required resistance - 24k or so each with one connected to the opto's anode and the other to the cathode. This will balance the common-mode impedance at the opto's anode and cathode. \$\endgroup\$
    – vir
    Aug 16, 2022 at 22:44
  • 3
    \$\begingroup\$ I wonder if the problem is the way that your frequency counter is implemented. If you do something like just count the number of 0-to-1 transitions every second, you're going to get a very inaccurate result. If you tell us about the algorithm you're using, we can make some suggestions for how to improve it. \$\endgroup\$ Aug 16, 2022 at 23:36
  • 2
    \$\begingroup\$ Your PC/laptop soundcard can be used as an oscilloscope. Google soundcard oscilloscope \$\endgroup\$
    – Kartman
    Aug 17, 2022 at 4:15

2 Answers 2


Your transistor signal may be changing state a bit too slowly for the ESP input. When it's half-way switched you may get some rapid switching due to noise on the mains or mains interference with your input.

Two things I can think of:

  1. Add a little delay into your code any time the input changes state. 0.5 ms might be enough. This would give time for the signal to get stronger before allowing the next read. It would, of course, limit the maximum frequency you could measure.
  2. Another way is to use a Schmitt trigger on the input but this requires additional electronics - if the ESP doesn't have any Schmitt trigger inputs.
  3. Create a Schmitt trigger in software. Wire an output to the input via a weak pulling resistor - say 100k versus your 10k. Now when the input goes high switch the output high. This means that the transistor collector voltage will have to go that bit lower before the input will register a low. Similarly when the input goes low switch the output low. This avoids the delay penalty of solution 1.

Hmmm. That was three things.

  • \$\begingroup\$ Third one could be the charm, can there be noise on mains waveform? Failing to imagine that... \$\endgroup\$
    – asim
    Aug 16, 2022 at 22:51
  • 2
    \$\begingroup\$ Sure. Switching power-supplies, motors, dimmers, all sorts of stuff. picotech.com/library/application-note/… for example. (I haven't read it.) \$\endgroup\$
    – Transistor
    Aug 16, 2022 at 22:54
  • \$\begingroup\$ Use a high speed optocoupler with Schmitt trigger, like H11L1 mouser.com/datasheet/2/308/H11L3M_D-1810362.pdf, or VOH1016 mouser.com/datasheet/2/427/voh1016ab-1767805.pdf \$\endgroup\$
    – PStechPaul
    Aug 17, 2022 at 4:27
  • 1
    \$\begingroup\$ Agree that noise is the problem, but I would prefer to clean up the signal before the optocoupler rather than after it (or possibly, both). Add a capacitor parallel to the diode, effectively creating a low-pass filter. \$\endgroup\$
    – Paul
    Aug 17, 2022 at 10:39

There is another way. As long as you have an actual load on the mains (which can be a resistor), you can use a linear Hall sensor to measure the magnetic field around the cable.

The advantage of this method is that if you don't have a fast enough sampling rate, you can leverage aliasing to your advantage, as long as your sampling rate isn't a divisor of 50 Hz. Here are some measurements I took with a smartphone next to the cable. The sinusoid corresponds to the mains' frequency. Note the units on the X-axis. enter image description here

The noise there is due to me holding it by hand, but doing the same measurement on cables feeding a laptop charger, for example, you can see very different waveforms, and different makers have very different signatures. Some approximate a sum of more-or-less triangular waves, for example.

This was just a test to see if it was viable. The final version runs on an Arduino and we get very clean signals in real-time, without aliasing; but we are doing a very light processing.

Your optocoupler may be fast enough to work as my Hall sensor. If that is the case, you would just have to sample the waveform fast (or slow!) enough and do the math to compute the spectrum.

  • \$\begingroup\$ Sounded like a good idea, used LM358 on a hall sensor, could only detect magnets, same with LM339 comparator, same thing with LM358 as primary amplifier and LM339 as secondary comparator turning on LED, failed to detect AC magnetic field \$\endgroup\$
    – asim
    Aug 17, 2022 at 17:47
  • \$\begingroup\$ My load was ~700 watt and used single live wire not both, no detection, might be because of cheap hall sensor from the bldc fan (it is linear can confirm), will buy a better one to see if it makes a difference \$\endgroup\$
    – asim
    Aug 17, 2022 at 17:52
  • \$\begingroup\$ 700W should be very detectable, check with a smartphone first to make sure it is live (locate the sensor with a magnet), and which side of the wire has the stronger field. We bought a sensor with amplification built in because it was easier than to solder one. \$\endgroup\$
    – Davidmh
    Aug 18, 2022 at 6:55
  • \$\begingroup\$ non linear(with built in amp) sensors perform the worst because they are designed to detect magnets and have certain thresholds to prevent false triggers therefore not very suitable \$\endgroup\$
    – asim
    Aug 18, 2022 at 14:39
  • \$\begingroup\$ @asim this is a linear sensor with an op-amp and an analog output. I can't read the specifications because there is some tape, but it looks like this one. We definitely get continuous values, and can detect changes in the orientation due to the Earth's magnetic field. We have a very clean signal around 50 Hz. \$\endgroup\$
    – Davidmh
    Aug 18, 2022 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.