как исправить колебания аналогового входа, считанного STM32F107

Я должен прочитать входное значение из внешнего источника, который является балансом с использованием процессора STM32F107. Этот баланс является внешним по отношению к плате, содержащей процессор, и взаимодействует с ним через PA4.

Вот моя первая попытка прочитать ввод с баланса.

Я использую эту функцию для настройки АЦП:

void ADC_Configuration(void) {

    ADC_InitTypeDef ADC_InitStructure;
   /* PCLK2 is the APB2 clock */
   /* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/
   RCC_ADCCLKConfig(RCC_PCLK2_Div6);
   /* Enable ADC1 clock so that we can talk to it */
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
   /* Put everything back to power-on defaults */
   ADC_DeInit(ADC1);

   /* ADC1 Configuration ------------------------------------------------------*/
   /* ADC1 and ADC2 operate independently */
   ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
   /* Disable the scan conversion so we do one at a time */
   ADC_InitStructure.ADC_ScanConvMode = DISABLE;
   /* Don't do contimuous conversions - do them on demand */
   ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
   /* Start conversin by software, not an external trigger */
   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
   /* Conversions are 12 bit - put them in the lower 12 bits of the result */
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   /* Say how many channels would be used by the sequencer */
   ADC_InitStructure.ADC_NbrOfChannel = 1;

   /* Now do the setup */
    ADC_Init(ADC1, &ADC_InitStructure);
   /* Enable ADC1 */
   ADC_Cmd(ADC1, ENABLE);
   /* Enable ADC1 reset calibaration register */
   ADC_ResetCalibration(ADC1);
   /* Check the end of ADC1 reset calibration register */
   while(ADC_GetResetCalibrationStatus(ADC1));
   /* Start ADC1 calibaration */
   ADC_StartCalibration(ADC1);
   /* Check the end of ADC1 calibration */
   while(ADC_GetCalibrationStatus(ADC1));
}

И я использую эту функцию для получения ввода:

u16 readADC1(u8 channel) {

   ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_1Cycles5);

   // Start the conversion
   ADC_SoftwareStartConvCmd(ADC1, ENABLE);
   // Wait until conversion completion
   while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
   // Get the conversion value

   return ADC_GetConversionValue(ADC1);
}

Проблема в том, что при N измерениях одного и того же веса я получаю N разных результатов. Например, вес составляет 70 кг, а вывод readADC1 (ADC_Channel_4) — 715 760 748 711 759 и т. д.

Что я делаю не так?

Редактировать. Я добавил эту функцию (имитирующую lp-фильтр) для стабилизации входного сигнала, и она отлично работает. Проблема заключается в том, как преобразовать значение, возвращаемое этой функцией, в килограммы. Использование коэффициента константы (определяемого путем измерения известного объекта) дает растущую ошибку, пропорциональную увеличению веса входных данных. Любое предложение иметь лучшую конверсию?

double fix_oscillations(){
    int i;
    double LPOUT=0,LPACC=0;
    int K = 5000;

    for(i=0;i<5000;i++){
       LPACC = LPACC + readADC1(ADC_Channel_4) - LPOUT;
       LPOUT = LPACC / K;
    }
    return LPOUT;
}

person Mario Lepore    schedule 31.07.2013    source источник
comment
Время добавить немного усреднения/фильтрации...   -  person Carl Norum    schedule 01.08.2013
comment
Если вы хотите, чтобы люди читали ваш код, поможет общее и последовательное соглашение об отступах и немного вертикального пробела.   -  person Clifford    schedule 02.08.2013


Ответы (4)


Возможно, вход сам по себе зашумлен или шум внесен другим оборудованием. Стоит наблюдать за сигналом с помощью осциллографа, чтобы определить вид помех или шума в сигнале, так как это может повлиять на наилучшее решение.

Если возможно, вы должны устранить любой источник внешних помех, затем следует применить внешнее аналоговое условие сигнала, в идеале с помощью фильтра нижних частот с частотой среза, равной половине предполагаемой частоты дискретизации или меньше. Тогда вы сможете применить фильтрацию в цифровом домене, если это необходимо. Для статических сигналов (уровни напряжения) будет достаточно простого блочного среднего, для более быстрых движущихся сигналов будет лучше использовать скользящее среднее (фильтр с коробкой). Для сложных сигналов, из которых необходимо извлечь определенные частоты, необходимы более сложные фильтры, но в данном случае это, вероятно, не так.

person Clifford    schedule 01.08.2013
comment
Я добавил новую информацию к вопросу. Можешь взглянуть? Спасибо за поддержку. - person Mario Lepore; 01.08.2013
comment
АКА «поставьте больший конденсатор на вход» :) - person Martin James; 02.08.2013

Вы видели примечания по применению STM32 для повышения точности АЦП? Также есть примечания по применению для увеличения разрешения, а также несколько других.

Вы должны взглянуть на эту ссылку здесь. Затем вы можете нажать «Документация», выбрать «Примечания по применению» и выполнить поиск «Точность».

Заметки по применению STMicro часто бывают полезны, так как им нравится выпускать свои продукты раньше, чем позже, а затем добавлять послесловие документации/поддержки.

person bunkerdive    schedule 09.08.2013
comment
Вы также можете поискать AN2668, в котором описывается использование передискретизации для увеличения разрешения. - person bunkerdive; 21.06.2021

Редактировать. Я добавил эту функцию (имитирующую lp-фильтр) для стабилизации входного сигнала, и она отлично работает. Проблема заключается в том, как преобразовать значение, возвращаемое этой функцией, в килограммы. Использование коэффициента константы (определяемого путем измерения известного объекта) дает растущую ошибку, пропорциональную увеличению веса входных данных. Любое предложение иметь лучшую конверсию?

Вероятно, стоило опубликовать отдельный вопрос, поскольку он не имеет прямого отношения к заголовку вопроса.

Если ваши выходные данные нелинейны, вы можете использовать несколько точек калибровки с линейной интерполяцией между точками, однако вполне вероятно, что кривая может быть охарактеризована уравнением. Выполните ряд измерений в интересующем диапазоне, а затем отобразите эти точки в программе для работы с электронными таблицами, такой как Excel или OpenOffice.org Calc. Инструменты построения графиков включают в себя различные типы построения «линий тренда» и могут отображать уравнение кривой. Выберите самый простой тип кривой с адекватной подгонкой. Если вам нужно прибегнуть к многочлену с более чем двумя членами, убедитесь, что вы отображаете члены уравнения с достаточным количеством десятичных знаков, поскольку они могут быть критическими. Вы можете проверить, достаточно ли у вас точности, используя уравнение для создания кривой и посмотреть, насколько хорошо она соответствует линии тренда. Построение уравнения, вероятно, является хорошей идеей для любой кривой в качестве теста на достаточную точность. Когда вы пишете код, убедитесь, что вы используете тип данных с достаточной точностью.

Примечание к строке:

LPOUT = LPACC / K;

взяв 5000 выборок, вы фактически увеличили разрешение АЦП примерно на 12 бит (за счет времени выборки), но, разделив на K, вы потеряли эту точность без необходимости, и это также усеченное деление. Целую сумму лучше использовать непосредственно при переводе в кг. Я понимаю, что деление делает значение «стабильным», но речь идет о соотношении сигнал: шум, а не об абсолютной величине шума. Преобразование в кг и отображение с требуемой реальной точностью будет иметь тот же эффект «стабилизации» результата, но с меньшей кумулятивной ошибкой.

person Clifford    schedule 01.08.2013
comment
Но если я не разделю на K, я не смогу устранить ошибку. Рассмотрение только суммы означает продолжение ошибки. Верно? - person Mario Lepore; 02.08.2013
comment
@BoonTobias: Нет. Как я уже сказал, речь идет о соотношении сигнал/шум. Скажем, реальное значение было 4,5, но у вас есть целые выборки 4,5,3,6, сумма равна 18 - нулевая ошибка (4,5 * 4 = 18), если вы разделите целое число на 4, результат будет 4, а не 4,5, так что теперь Ваша ошибка 0,5. Единицы АЦП произвольны и не связаны с реальным значением. Взяв, скажем, 8-битный АЦП с диапазоном от 0 до 255 и суммировав 4 отсчета, мы получим диапазон от 0 до 1023 — фактически 12-битный АЦП с лучшим отношением сигнал/шум. Преобразуйте это значение с более высоким разрешением напрямую в единицы реального мира. - person Clifford; 02.08.2013
comment
Мое деление находится между двойным LPOUT и целым числом K. Так что я полагаю, что не теряю точности. - person Mario Lepore; 03.08.2013
comment
@BoonTobias: Так и есть, моя ошибка. Это по-прежнему бессмысленно, если вы собираетесь применить дальнейшее преобразование в кг. Вы также можете свернуть это в одно выражение. Вы также можете учитывать снижение производительности операций с плавающей запятой процессора без FPU. - person Clifford; 04.08.2013

Вы можете найти это полезным способом усреднения:

float FilteredValue;
#define TIME_CONSTANT 100
FilteredValue += ((float)ADCreading - FilteredValue)/TIME_CONSTANT;

Это реализует настоящий фильтр нижних частот с постоянной времени TIME_CONSTANT x Sample Frequency. Если в ADCreading происходит ступенчатое изменение, FilteredValue постепенно изменится на новое значение. Теоретически он никогда не достигнет его, так как реализует обратный экспоненциальный фильтр. Чем больше значение TIME_CONSTANT, тем лучше подавление шума, но тем больше времени потребуется для стабилизации.

person user1358841    schedule 06.09.2013