Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] AC rms voltage measurement problem in precision

Status
Not open for further replies.

archusvijay1

Member level 3
Joined
Mar 12, 2014
Messages
61
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
553
Hi,

I am trying to measure 50Hz AC RMS voltage using PIC18F4520 microcontroller. Schematic shows how I am giving the input to ADC. adding a DC offset of 2.5 to the transformer output. there is also a zero crossing detector to take the samples for just one complete cycle correctly. But the measured values are not constant. so I measured 50 cycles and took average.. still there is variation. Please find the code below as I've given only the necessary part of code.I got rms values 214,221,228,229,231,215,222 etc. Is there anything wrong with the code. I've attached the circuit also. in that VOLT IN1 goes to the microcontroller pin and the outputof Q1(BC547) goes to zero crossing detector pin.

Code:
void adcInit(void){
    
    ADCON0=0x00; 
    ADCON1=0X07;                // SET ANALOG CHANNELS
    TRISA=0xFF;
    PSPMODE=0;
    TRISEbits.TRISE0=1;
    TRISEbits.TRISE1=1;
    TRISEbits.TRISE2=1;
    ADCON2=0b10001010;         // SET COVERSION CLOCK       //101=15        //010=32
    ADCON0=0x01;                // TURN ON ADC MODULE
}

unsigned int getAdcCount(unsigned char channel){
    //unsigned int count;
    if(channel>13) return 0;  //Invalid Channel

   ADCON0=0x00;

   ADCON0=(channel<<2);   //Select ADC Channel

   ADON=1;  //switch on the adc module
//   DelayMs(3);          // WAITING FOR THE ACQUISITION TIME
   GODONE=1;  //Start conversion

   while(GODONE); //wait for the conversion to finish

   ADON=0;  //switch off adc
   //count = ADRES;
    return ((ADRESH<<8)+ADRESL);
}



void main() {

    unsigned char uctemp = 0;
    double U32Volt;
    unsigned int i = 0;
    CM0 = 1; //turn off comparator
    CM1 = 1; // turn off comparator
    CM2 = 1; // turn off comparator
    adcInit();
    gprs_set_flag = 0;
    EB_ZC_PIN_DIR = INPUT_PIN;
    OUT_ZC_PIN_DIR = INPUT_PIN;
    INV_ZC_PIN_DIR = INPUT_PIN; //zero crossing pins as inputs
    
    while (1) {
     
        U32Volt = 0;
        for (i = 0; i < 50; i++) {                     //50 times averaging
            invVolt = Measure_Rms_value(INVVOLT_CHANNEL, 1);       // taking rms value
            U32Volt += invVolt;
        }
        U32Volt = (U32Volt * 3.24) / 50;                //3.24 multiplicaion factor
        DelayS(1);

    }
}



double Measure_Rms_value(unsigned channel, double Mul_factor) {
    unsigned int i;
    unsigned int sample_Val;
    float offset_Val = 533; //775;//512;       // for 3.3v ref offset val=775; for 5v ref, offset value=512
    double sum_Val = 0;
    float filtered_Val = 0, sq_Val = 0, Rms_val = 0;
    unsigned char neg_cycle_flag;
    unsigned int adc_counts = 1000;
    unsigned int timeout = 0;
     if (channel == INVVOLT_CHANNEL) {
        unsigned int invZC = 0;
        timeout = 0;
        if(INV_ZC_PIN==1)                 // if positive half cycle: wait here
        {
            while (INV_ZC_PIN == 1) {
            timeout++; 
            if (timeout >= 1000) {
                timeout = 0;
                break;
            }
        }
       }
        while (INV_ZC_PIN == 0) {                       // wait until negative cycle is finished
            timeout++;
            if (timeout >= 1000) {
                timeout = 0;
                return 0;
            }
        }
        while (adc_counts--) {                        // start taking measurement for one cycle
            invZC++;
            sample_Val = getAdcCount(channel);
            offset_Val = (offset_Val + ((sample_Val - offset_Val) / 1024));
            filtered_Val = sample_Val - offset_Val;
            sq_Val = filtered_Val * filtered_Val;
            sum_Val += sq_Val;

            if (INV_ZC_PIN == 0) {                // negative cylce: zero crossing pin becomes low
                neg_cycle_flag = 1;
            }
            if (neg_cycle_flag == 1 && INV_ZC_PIN == 1) {
                neg_cycle_flag = 0;
                break;
            }
        }

        Rms_val = Mul_factor * (sqrt(sum_Val / invZC)); //
        sum_Val = 0;
        return Rms_val;
    }

    return 0;
}

Someone please help me out

thanks.
 

Attachments

  • AC _VOLT.JPG
    AC _VOLT.JPG
    68.7 KB · Views: 130

hi,
Please suggest me where is the complaint?
 

Hi,

You need a fixed known sample rate. Don't use software delay to generate the timing, use hardware (timer, counter) to generate the sample rate.

Maybe select 10kHz. I mean exactely 10.000Hz.
Then take 200 samples to calculate the RMS.

Klaus
 

Thanks for the reply. what you exactly meant by 200 samples. Is it the ADC should be configured to read 200 samples/sec or I should take 200 samples in 10Hz?
 

Use timer interrupt for every 100us that starts conversion. This will exact 10kHz as Klaus mentioned.
 

Hi,

200 samples are 200 ADC conversion results.
How do you come to 10Hz?

*****

If your signal frequency is 50Hz sine, then the ADC sample rate needs to be a fixed integer multiple of this frequency. But at least 3x.
(2 x is just off the nyquist limit)

Now decide how often you want an RMS calculation output.
Let's say every 100ms (must be an integer multiple of a fullwave = 20ms)

Then decide what sample rate you need. It must be an integer multiple of the signal frequency, but at least 3x)
Lets say you use 1000 smpl/s. This means 100 samples within the 100ms.

Then calculate the RMS value with 100 ADC values.

Klaus
 

Use timer interrupt for every 100us that starts conversion. This will exact 10kHz as Klaus mentioned
So I should take exactly 200 samples with an interval of 100 uS between each samples? Am I right?
 

Hi,

So I should take exactly 200 samples with an interval of 100 uS between each samples? Am I right?
This is one of numerous solutions.
So, yes, you can try if this is a good solution for you...

Now decide how often you want an RMS calculation output.
We don't know what's your decision. Some applications need a calculation avery 20ms, for others a calculation per minute is sufficient. --> You really should decide.

Then decide what sample rate you need.
The same us here. Mathematically 3 samples per fullwave are sufficient, but only on a pure, undistorted sinewave. The more distortion, the more samples per period you need.
The sample rate is limited by the ADC you use.
--> It's on you to decide the sample rate.

Klaus
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top