After making a DC voltmeter in our previous post, you may be looking for an AC voltmeter. Yes, in this article, we’ll learn how to make an AC voltmeter using a Seven Segment display and PIC16F73 micro-controller. Many people just make AC into DC using rectifiers and capacitors. But it is not a good idea. Here, we will see what should we do.

Disclaimer: Electricity is always dangerous. Proper skill is required to work with electricity. Do work at your own risk. The author will not be responsible for any misuse or harmful act or any mistake you make. The contents of this website are unique and copyright protected. Kindly don’t do any nonsensical act copying and claiming it as yours. Most of the articles published here are kept as open-source to help you. Take the knowledge for free and use it, but if you are interested you can buy the ready resources offered here. If you need any help or guide feel free to comment below, the author will try to help you. Thanks.

First of all, I’ll request to read the other post ‘How to make a DC voltmeter using 7-segment and PIC16F73‘ first to start learning to make an AC voltmeter.

Table of Contents

What is the difference between AC and DC voltage sensing?

On the circuit side, there is no change. All you need to do is calculate and using the proper technique. Although you can use Op-Amp based isolation circuits for high voltage or floating voltage measurement in general cases, you can use the voltage divider technique like the DC voltmeter one:

Voltage divider technique
For AC voltmeter

Like the DC voltage, the AC one is not fixed in amplitude. So here, we need to do something to find that changing voltage. Many people just make it DC using rectifiers and capacitors. But it is not a good idea. Here, we will see what should we do.

Measuring the AC signal:

In an AC signal, we have an alternating voltage signal. But there is a factor, the peak point is not different for a fixed AC voltage. That means, if we can find the peak point, we can find the RMS value from this equation:

V rms = Vpeak x 0.707

AC signal

If we take several readings within a short time and from those reading, find the peak point by comparing with the previous one. Then we can easily find the peak value of an AC signal.

That means, if Vn is the recent value and Vn-1 is the previous value, we will keep taking reading until Vn < Vn-1;

When this point is found, the peak will be Vn.

It is this simple to find the peak point.

Adding additional feature to make accurate result

Again, if we take the average reading of some peak points and find an average value we’ll get a more accurate result. That means, more the sample, the more the average value.

But here, we need to keep in mind that we already need several (100+) samples to find the peak point, so time consumption is an issue here. So we have to select the number of total samples limited.

Circuit diagram:

Circuit diagram

Coding:

Now we will write the code to measure AC voltage.

/*******************************************************************************
* Program for "High voltage AC voltmeter"                                      *
* Program written by_ Engr. Mithun K. Das                                      *
* MCU:PIC16F73; X-Tal:8MHz; mikroC pro for PIC v7.6.0                          *
* Date:05-05-2020                                                              *
*******************************************************************************/
char segment_array[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//cmmon cathode_non dot

sbit digit0 at RC0_bit;
sbit digit1 at RC1_bit;
sbit digit2 at RC2_bit;
sbit digit3 at RC3_bit;

char digits[5];
void display_7segment(int number)
{
   digits[3]=number/1000u;
   digits[2]=(number/100u)%10u;
   digits[1]=(number/10u)%10u;
   digits[0]=(number/1u)%10u;
}

void InitTimer0()
{
  OPTION_REG     = 0x85;
  TMR0           = 100;
  INTCON         = 0xA0;
}

int position=0;
void Interrupt() iv 0x0004 ics ICS_AUTO
{
  if (TMR0IF_bit)
  {
    TMR0IF_bit   = 0;
    TMR0         = 100;

    digit0 = 1;
    digit1 = 1;
    digit2 = 1;
    digit3 = 1;
    if(position>3)position=0;

    if(position==1)PORTB = segment_array[digits[position]]+128; //dot point
    else PORTB = segment_array[digits[position]];

    if(position==3)
    {
        digit0 = 0;
        digit1 = 1;
        digit2 = 1;
        digit3 = 1;
    }
    else if(position==2)
    {
        digit0 = 1;
        digit1 = 0;
        digit2 = 1;
        digit3 = 1;
    }
    else if(position==1)
    {
        digit0 = 1;
        digit1 = 1;
        digit2 = 0;
        digit3 = 1;
    }
    else if(position==0)
    {
        digit0 = 1;
        digit1 = 1;
        digit2 = 1;
        digit3 = 0;
    }
    position++;
  }
}



void Get_AC_Voltage(void);
unsigned int max_point=0,mm=0,k=0,temp=0,adc_rd0=0,ac_voltage;
void main()
{
 TRISA=0xFF;//all input
 TRISB=0x00;//all output
 TRISC=0x00;//all output
 PORTB=0x00;
 PORTC=0x00;//clear ports
 ADCON1=0x00;//all analog in
 InitTimer0();//5ms timer
 while(1)
 {

    Get_AC_Voltage(void);
    display_7segment(ac_voltage);

 }
}

void Get_AC_Voltage(void)
{
      int mm;
      max_point = 0;//clear all data
      adc_rd0 = 0;//clear data
      for(mm=0;mm<10;mm++)
      {
          for(k=0;k<500;k++)
          {
               ADCON0 = 0b00000001;//AN0 selected
              if(temp = ADC_Read(0),temp>max_point)
              {
                  max_point = temp;
              }
          }
          max_point = abs(ceil((long)(max_point-128)));
          adc_rd0+= max_point*1.53;
      }
      adc_rd0/=10;

      ac_voltage = adc_rd0;
}

Here only difference from the DC voltmeter one is the AC voltage measurement technique. Here is that sub-function to do the job:

void Get_AC_Voltage(void)
{
      int mm;
      max_point = 0;//clear all data
      adc_rd0 = 0;//clear data
      for(mm=0;mm<50;mm++)
      {
          for(k=0;k<500;k++)
          {
               ADCON0 = 0b00000001;//AN0 selected
              if(temp = ADC_Read(0),temp>max_point)
              {
                  max_point = temp;
              }
          }
          max_point = abs(ceil((long)max_point));
          adc_rd0+= max_point*1.53;
      }
      adc_rd0/=50;
      ac_voltage = adc_rd0;

You can see that in two different loops, we are finding the peak point and then finding an average value of 50 peak points. There is one difference you may have noticed already.

abs(ceil (….);

As the value is changing frequently, we are taking the absolute value by abs and then the complete value by ceil. It helps reducing false reading.

Final result:

Test result

You can see that there is a small delay with the change in input voltage. As we are taking several readings to find the peak point again several points to find the average value, so it is taking some time.

Reducing the average finding sample rate will make it more responsive and increasing the peak finding sample will be able to measure higher voltages.

The project was very interesting and I hope you are now able to make one for yourself. If you need any help, I’m here. Thank you very much, Enjoy!

Loading

JLCPCB – Only $2 for PCB Prototype (Any Color)

24 Hours fast turnaround, Excellent quality & Unbeatable prices

$18 Welcome Bonus for new registrations Now!!! https://jlcpcb.com


Check this out: 5 coolest multimeters you can buy


MKDas

I'm Mithun from Bangladesh. Electronics is my passion, love to work with electronics. This is my personal blog. Besides my regular works, I write some articles here. Most of them are open-source and everything is presented in the easiest way so that anyone can understand and learn it. Thanks.

3 Comments

Chandana · July 31, 2020 at 2:07 am

Many Thanks for Valuable Article

enrique · October 25, 2020 at 11:34 pm

From Colombia. Thank you very much, for sharing this excellent work, please can you explain to me, I do not understand the conversions very well and why it adds up to 128 and 1.53 and / 50

    Mithun K. Das · November 1, 2020 at 2:22 pm

    128 to remove 2.5V, 1.53 from ADC calculation and /50 for getting the average value of 50 samples.

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *