Как стабилизировать отображение выходного сигнала АЦП на 7 сегментах

Я разрабатываю простой вольтметр. Я использую 8-битный АЦП PIC16F72 и компилятор Mikro C с мультиплексным 7-сегментным дисплеем. Я получаю значение АЦП на 7-сегментном дисплее, но оно постоянно колеблется (например, 1670 мВ колеблется между 1660 и 1680 мВ). Я пробовал все аппаратно, добавляя колпачок на АЦП, землю и т. Д.

Вот мой код:

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();
     }
}

Нужен ли какой-нибудь программный фильтр??

введите описание изображения здесь

Вы заявляете, что пробовали «все», можете ли вы добавить схему, чтобы мы могли более четко увидеть, что у вас есть?
Есть ли конденсатор ~ 100 нФ на шинах питания рядом с выводами питания PIC?

Ответы (2)

Одним из возможных программных решений является очень простая в реализации экспоненциальная скользящая средняя ( http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average ). Для этого требуется только одна глобальная переменная и несколько строк кода. Это немного больше работы, но это также можно сделать с помощью кода с фиксированной точкой (например, int) для гораздо большей эффективности (я бы не беспокоился об этом, если все, что вы делаете, это считывание АЦП и его отображение).

Например:

//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;
}

Вы видите сглаживание этого наименее значащего бита, поскольку он пытается решить, быть ли ему 1 или 0; это то, с чем вам придется иметь дело, масштабируя входной сигнал АЦП, если вы не можете игнорировать колебания дисплея.

Этот последний бит всегда будет немного дрожать, если только он не измеряет ОЧЕНЬ стабильные напряжения и не улавливает НИКАКИХ шумов от внешних источников. Вы можете сделать его немного тише, если уменьшите входное сопротивление, если дизеринг является результатом внешнего шума. Однако каждый раз, когда измеряемое вами напряжение не стабильно в пределах 1,2%, вы увидите такое сглаживание в наименее значащем бите.

При 1670 мВ ваш АЦП дает вам данные = 85 +- 1. Умножьте на ваши ~ 19,6, данные 84 = 1646,4 (1646), данные 85 = 1666 и данные 86 = 1685,6 (1686), так что вы получите увидеть что-нибудь от 1646 до 1686 в зависимости от того, выбирает ли ваш младший бит 1 или 0.

Масштабируйте вход в АЦП с помощью операционного усилителя с коэффициентом усиления 19,6, и вы сможете избавиться от программного умножения и считывать прямые напряжения ... И ваше дизеринг должно быть уменьшено.