1
\$\begingroup\$

I am designing a simple voltmeter. I am using 8 bit ADC of PIC16F72 and Mikro C compiler with a multiplexed 7 segment display. I am getting ADC value on 7 segment display but its continuously fluctuating (for example 1670mV fluctuates in between 1660 & 1680mV). I have tried everything in hardware, adding a cap on ADC and ground etc.

Here is my code:

void StabilizeVoltage()
{
     unsigned int ADS;
     if (flgAC)
      {
      ADS = ADC_Get_Sample(0);
      Voltage_FLOAT =(float)ADS *19.6078431372549;
      a= Voltage_FLOAT;
      Voltage_INT=a;
      //if(63<Voltage_INT && Voltage_INT<78 )
       if(Voltage_INT <=1050 )
      {
      Relay1=0;
      Relay2=0;
      Relay3=0;
      Relay4=0;
      }
      else if (1050<Voltage_INT && Voltage_INT<=1150)
      {
      Relay1=1;
      Relay2=0;
      Relay3=0;
      Relay4=0;
      }
      else if (1150<Voltage_INT && Voltage_INT<=1350)
      {
      Relay1=1;
      Relay3=1;
      Relay2=0;
      Relay4=0;
      }
      else if (1350<Voltage_INT && Voltage_INT<=1450)
      {
      Relay1=1;
      Relay3=1;
      Relay2=1;
      Relay4=0;
      }
      else if (1450<Voltage_INT )
      {
      Relay1=1;
      Relay3=1;
      Relay2=1;
      Relay4=1;
      }
      }
      flgAC = 1;
}
void main()
{
      InitIO();
      ADC_Init();
      InitTimer2();
      InitDisplay();
     while(1)
     {
         UpdateDisplay();
         StabilizeVoltage();
     }
}

Do I need any software filter ??

enter image description here

\$\endgroup\$
  • \$\begingroup\$ You state that you tried 'everything', can you add a circuit diagram so we can see more clearly what you have so far? \$\endgroup\$ – jippie Aug 17 '14 at 14:59
  • \$\begingroup\$ Is there a ~100nF cap across the power rails near the PIC power pins? \$\endgroup\$ – jippie Aug 17 '14 at 15:48
2
\$\begingroup\$

One possible software solution is the very simple to implement exponential moving average (http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average). It only requires one global variable and a few lines of code. It is a little more work to accomplish but this can also be done with fixed point code (ie. int) for much greater efficiency (I wouldn't worry about it if all your doing is reading an ADC and displaying it).

For example:

//K is the filter coefficient and must be smaller than 1 and greater than zero (0<K<1)
//The smaller the K is, the more the filter will smooth, but it will also take longer
//to reach its value when the input changes.
#define K 0.01f

float filter( float aData )
{
    static float memory;
    memory = memory*(1-K) + aData*K;
    return memory;
}
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

You're seeing dithering of that least-significant bit as it tries to decide whether to be a 1 or a 0; it's something you'll need to deal with by scaling the input to the ADC, unless you can ignore the display fluctuation.

That last bit will always dither a little unless it's measuring voltages that're VERY stable and it's not picking up ANY noise from outside sources. You may get it a bit quieter if you can lower your input impedance, if the dithering is the result of outside noise. Any time the voltage you measure isn't stable within 1.2%, you'll see that sort of dithering in the least-significant bit, though.

At 1670mv, your ADC is giving you data=85 +- 1. Multiplied by your ~19.6, data of 84 = 1646.4 (1646), data of 85 = 1666, and data of 86 = 1685.6 (1686), so you'll see anything from 1646 to 1686 depending upon whether your least-significant bit chooses 1 or 0.

Scale the input to the ADC with an opamp with a gain of 19.6, and you can do away with your software multiplication & read direct voltages... AND your dithering should be alleviated.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.