Introduction: Power Supply Frequency and Voltage Measurement Using Arduino


The goal of this project is to measure supply frequency and voltage, which is between 220 to 240 Volts and 50Hz here in India. I used an Arduino for capturing signal and calculating frequency and voltage, you may use any other microcontroller or board you have. The circuit requires a handful of components and is fairly accurate for all practical purposes.

Step 1: Components Required

  • Arduino Uno
  • IC LM358
  • Step down transformer(220V to 12V)
  • Capacitors:
    • 0.1uF
    • 2 x 1uF
  • Resistors:
    • 3 x 1kOhm
    • 2 x 100kOhm
    • 1.5kOhm
    • 3.3kOhm
    • 6.8kOhm
  • 3 x 1N4148 diode
  • Bread Board and Jumper wire(optional)

Step 2: Schematic Diagram

In the above circuit, the transformer primary is connected to the supply mains and the primary is connected to our measuring circuit

Step 3: Understanding the Circuit

According to the functionality, this circuit can be divide into four parts:

A: The Zero Crossing Detector circuit

This circuit generates a 5V square pulse whenever the sinewave goes from positive to negative. Resistor R1 combined with D1 and D2 limits the input voltage swing at the diode junction to -0.6V to +5.6V( assuming diode forward voltage to be 0.6V). Furthermore, you can increase the input voltage range of the circuit by increasing the value of R1.

The resistor R2 and R3 form a voltage divider to limit the negative voltage swing to -0.24Volts as the input common-mode voltage of LM358 is limited to -0.3Volts.

The resistor R4, R5, capacitor C1 and the op-amp(here used as a comparator) forms the Schmitt Trigger circuit where the resistor R4 and R5 set the hysteresis at input +49.5mV above ground. The output of the Schmitt Trigger is fed to the Arduino PIN2 for further processing.

B: Isolation and Voltage Step Down

As the name suggests this part isolates and steps down the voltage to approximately 12Vrms. The stepped-down voltage is further fed to the instrumentation circuit.

C: Peak Detector circuit

This circuit determines the maximum peak voltage of the input signal. Resistor divider R6 and R7 reduce the input voltage by a factor of 0.23( 12Vrms is reduced to 2.76Vrms). The diode D3 conducts only the positive half cycle of the signal. The voltage across C2 increases up to the peak value of the rectified signal, which is fed to Arduino analog pin A0 to further calculate the voltage.

In addition, you may replace this circuit with a precision peak detector circuit like these mentioned here. But for my demonstration purposes, the above circuit will be sufficient.

D: Arduino

In this part, the Arduino captures the square pulses generated by the Schmitt Trigger circuit and reads the analog voltage from the peak detector circuit. The data is further processed to determine the time period( hence frequency) of the square pulse( which is equal to the ac supply time person) and voltage of the supply.

Step 4: Calculation of Frequency and Voltage

Calculation of frequency:

With the help of Arduino, we can measure the time period T of the signal. The square wave pulses from the zero-crossing detector are fed to pin 2, from there we can measure time period of each pulse. We can use Arduino's internal timer(specifically Timer1) to calculate the time period between two Rising edges of the square pulse with the help of interrupts. The timer increments by 1 per clock cycle(without prescaler = 1 ) and the value is stored in register TCNT1. Hence the 16Mhz clock increments the counter by 16 every microsecond. Similarly for prescaler = 8 the timer gets incremented by 2 every microsecond. Hence the time period between two rising edge

T = (TCNT1 value) / time taken for each count

Where, time taken for each count = prescaler / (Arduino clock speed (16MHz)

Hence, frequency f = 1/T = (Arduino clock speed (16MHz) / ( Prescaler * TCNT! value)

Hence the timer speed (Hz) is given by = (Arduino clock speed (16MHz)) / prescaler

and the frequency of the signal is given by = (Arduino clock speed

Correspondingly, we can calculate frequency f from the relation f = 1/T.

Calculation of voltage:

The onboard ADC of Arduino has a resolution of 10 bits( possible values = 2^10 = 1024), returning values in the range of 0-1023. To calculate the corresponding analog voltage V we have to use the following relation

V = (ADC Reading) * 5/1023

To calculate the supply voltage Vs(rms) we must take into account the Transformer Ratio, Resistor divider R6R7 and the peak detector circuit. We can simply put together the various factors/ratio as:

Transformer ratio = 12/230 = 0.052

Resistor divider = R7/(R6 + R7) = 0.23

At peak detector circuit = 1.414

Vs(rms) = V/(1.414*0.052*0.23) = (ADC Reading) * 0.289

It should be noted that this value is far from the actual value, mainly due to error in the actual transformer ratio and the diode forward voltage drop. One way to circumvent this is to determine the factor after assembling the circuit. That is by measuring the supply voltage and the voltage across the capacitor C2 separately with a multimeter, then calculating Vs(rms) as follows:

Vs(rms) = ((Supply Voltage * 5)/(Voltage across C2 *1023))*(ADC Reading)

in my case, Vs(rms) = 0.33*(ADC Reading)

Step 5: Arduino Code

#define volt_in A0		//analog voltage read pin
volatile uint16_t t_period;
uint16_t ADC_value = 0;
float volt, freq;

void isr()
	t_period = TCNT1;	//store TCNT1 value in t_period
	TCNT1 = 0;		//reset Timer1
	ADC_value = analogRead(volt_in);	//read analog voltage

float get_freq()
	uint16_t timer = t_period;
		return 0;			// to avoid division by zero
		return 16000000.0/(8UL*timer); // frequency is given by f = clk_freq/(prescaler*timeperiod)
} void setup() { TCCR1A = 0; TCCR1B = bit(CS11); //set prescaler to 8 TCNT1 = 0; //reset Timer1 value TIMSK1 = bit(TOIE1); //enable Timer1 overflow interrupt EIFR |= bit(INTF0); // clear INT0 interrupt flag Serial.begin(9600); } void loop() { attachInterrupt(0, isr, RISING); //enable external interrupt (INT0) delay(1000); detachInterrupt(0); freq = get_freq(); volt = ADC_value*0.33; String buf; buf += String(freq, 3); buf += F("Hz\t"); buf += String(volt); buf += F("Volts"); Serial.println(buf); }

Step 6: Conclusion

You can assemble the circuit in a breadboard and tweak the code and add an SD Card to store the data, which can later be analysed. One such example is, you can analyse the voltage and frequency at peak hours.

The circuit I assembled in the breadboard used LM324(quad opamp) instead of LM358(dual opamp) as I didn't have that IC at that moment and nationwide lockdown due to COVID-19 pandemic made it difficult for me to get a new IC. Nevertheless, it would not affect the working of the circuit.

Feel free to comment below for any suggestions and queries.