220-380V AC Frequency Meter using Arduino

User avatar
Location: Philippines
Posts: 205
Joined: Sat Apr 23, 2016 10:32 pm

220-380V AC Frequency Meter using Arduino

Sun Oct 04, 2020 3:13 pm

This project shows how to measure AC source frequency using Arduino UNO board where frequency and period values are printed on 1602 LCD screen.
This frequency counter can easily measure frequency of AC lines with voltages 110/220/380V – 50/60Hz.

Frequency is number of cycles (complete turns) per 1 second. Its main unit of measurement is Hertz (Hz).
Period is time required to complete 1 cycle (turn), its main unit is second.
Frequency = 1/Period.

Home alternating current (AC) frequency is 50 or 60Hz, most countries use 50Hz.
For frequency of 50Hz the period is 20 milliseconds and for 60Hz the period is about 16.67 milliseconds.
Hardware Required:
This is a list of all components required to build this project.
~Arduino UNO board
~16×2 LCD screen
~330 ohm resistor
~10k ohm variable resistor or potentiometer
~PC817 optocoupler
~120k ohm -2W resistor
~10k ohm
~1N4007 diode (or equivalent)
~Jumper wires

The 16×2 LCD screen (2 rows and 16 columns) is used to display the values of frequency and period of the input voltage where:
RS —> Arduino digital pin 3
E —> Arduino digital pin 4
D4 —> Arduino digital pin 5
D5 —> Arduino digital pin 6
D6 —> Arduino digital pin 7
D7 —> Arduino digital pin 8
VSS, RW, D0, D1, D2, D3 and K are connected to Arduino GND,
VEE to the 10k ohm variable resistor (or potentiometer) output,
VDD to Arduino 5V and A to Arduino 5V through 330 ohm resistor.

VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.

The AC input is connected to the circuit as shown where diode 1N4007 is used to eliminate negative half cycles because the PC817 optocoupler maximum reverse voltage is 6V.

The optocoupler is connected to AC main through 120k ohm resistor (and also the 1N4007 diode) which limits the current that passes through the optocoupler LED (IF).
With the 120k ohm resistor and with source of 220V, the peak forward current is equal to (neglecting diode voltages):
220x√2/120k = 2.59 mA and the RMS current (half wave) = 2.59/2 = 1.3 mA.

The output of the PC817 optocoupler is connected to the Arduino as follows:
The emitter is connected to Arduino GND,
The collector is connected to Arduino digital pin 2. This pin is also for external interrupt 0.
The collector is connected to Arduino +5V pin through pull up resistor of 10k ohm.

When the optocoupler LED is forward biased, its output is (transistor collector) is attached to GND (logic 0). During signal negative cycles the PC817 output is logic 1.

With the optocoupler high voltage side is isolated from low voltage side.

The Code:
In this project I used external interrupt 0 to detect falling(going from high to low) of the optocoupler output.

When there is an interrupt the Arduino directly executes the function timer1_get().
Measuring the frequency idea is simple, Timer1 module is used to measure time between 2 successive interrupts which means we have the time between 2 successive falling events. When the function timer1_get() is called, it stores Timer1 value on a variable named: tmr1.

Timer1 module is configured to increment by 2 every 1 microsecond (prescaler = 8) and its overflow interrupt is enabled in order to reset the variable tmr1 (helps when signal is removed).
With prescaler = 8, the clock input of Timer1 module is equal to: Timer1_CLK = 16MHz/8 = 2MHz.

With these configuration the lowest frequency that the Arduino can measure is about 31Hz.

Signal period:
Period (in us) = Timer1_Value/Timer1_CLK = Timer1_Value/16000000/8
Period(in us) = 8 x Timer1_Value/16000000
Period (in ms) = 8 x Timer1_Value/16000

Signal frequency:
Frequency = 1/Period
Frequency (in Hz) = 16000000/(8 x Timer1_Value)

Arduino Code:

Code: Select all

 * Arduino frequency counter.
 * This is a free software with NO WARRANTY.
 * https://dohangout.com/
#include <LiquidCrystal.h>    // include Arduino LCD library
// LCD module connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);
void setup(void) {
  lcd.begin(16, 2);      // set up the LCD's number of columns and rows
  lcd.setCursor(0, 0);
  lcd.print("Freq =");
  lcd.setCursor(0, 1);
  lcd.print("Peri =");
  // Timer1 module configuration
  TCCR1A = 0;
  TCCR1B = 2;   // enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us)
  TCNT1  = 0;   // Set Timer1 preload value to 0 (reset)
  TIMSK1 = 1;   // enable Timer1 overflow interrupt
  EIFR |= 1;  // clear INT0 flag
  attachInterrupt(0, timer1_get, FALLING);  // enable external interrupt (INT0)
uint16_t tmr1 = 0;
float period, frequency;
void timer1_get() {
  tmr1 = TCNT1;
  TCNT1  = 0;   // reset Timer1
ISR(TIMER1_OVF_vect) {  // Timer1 interrupt service routine (ISR)
  tmr1 = 0;
// main loop
void loop() {
  // save current Timer1 value
  uint16_t value = tmr1;
  // calculate signal period in milliseconds
  // 8.0 is Timer1 prescaler and 16000 = MCU_CLK/1000
  period = 8.0 * value/16000;
  // calculate signal frequency which is = 1/period ; or = MCU_CLK/(Prescaler * Timer_Value)
  if(value == 0)
    frequency = 0;   // avoid division by zero
    frequency = 16000000.0/(8UL*value);
  lcd.setCursor(7, 0);
  lcd.print(" Hz  ");
  // print period
  lcd.setCursor(7, 1);
  lcd.print(" ms  ");
// end of code.

Return to “ELECTRICAL”