How to make an AC voltmeter using 7-segment & PIC16F73

Published by MKDas on

After making a DC voltmeter in our previous post, you may looking for AC voltmeter. Yes, in this article, we’ll learn how to make an AC voltmeter using 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. Skill required to work with electricity. Do work with your own risk. Author will not be responsible for any misuse or harmful act. This website contents is also copyright protected. Anything copied and directly posted in your website and claiming it as yours is prohibited and nonsensical. Author published all the articles as opensource to help you making your project and learning purpose only. Learn and make one for yourself. If need any help feel free to ask the author. Author will be helpful to 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 making AC voltmeter.

What is the difference between AC and DC voltage sensing?

In the circuit side, there is no change. All you need to do is the calculation and using a proper technique. Although you can use Op-Amp based isolation circuits for high voltage or floating voltage measurement but 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 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 reading 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 more accurate result. That means, more the sample, 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 a time consumption is an issue here. So we have to select the number of total sample 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 for 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 reading to find the peak point again several point 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!


MKDas

Mithun K. Das; B.Sc. in EEE from KUET. Blog: https://labprojectsbd.com

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

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