0

我必须使用处理器 STM32F107 从平衡的外部源读取输入值。该天平位于包含处理器的电路板外部,并通过 PA4 与其通信。

这是我第一次尝试从天平读取输入。

我使用这个函数来设置 ADC:

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 种不同的结果。例如,重量为 70kg,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;
}
4

4 回答 4

2

It is possible either that the input is inherently noisy or that noise is introduced by other equipment. It is worth observing the the signal with an oscilloscope to determine the kind of interference or noise on the signal since that may affect the best solution.

If possible you should eradicate any source of external interference, then external analogue signal condition should be applied, ideally by a low-pass filter with a cut-off frequency of half your intended sample rate or less. Then you are in a position to apply filtering in the digital domain if necessary. For static signals (voltage levels), a simple block average will suffice, for faster moving signals a moving average (boxcar filter) would be better. For complex signals from which you need to extract certain frequencies, more complex filters are needed, but that is probably not the case in this instance.

于 2013-08-01T08:05:08.647 回答
2

你看过 STM32 提高 ADC 精度的应用笔记吗?还有一个提高分辨率的应用说明,以及其他一些说明。

您应该在此处查看此链接。然后您可以单击“文档”并选择“应用说明”并搜索“准确度”。

STMicro 的应用说明通常很有帮助,因为他们喜欢尽早推出产品,然后在后面附加文档/支持。

于 2013-08-09T19:29:41.143 回答
1

编辑。我添加了这个函数(模拟 lp 过滤器)来稳定输入并且它工作正常。问题是如何将此函数返回的值转换为千克。使用一个常数系数(通过测量一个已知对象来确定)给出一个与输入权重成正比的增长误差。任何建议有更好的转换?

这可能值得发布一个单独的问题,因为它与问题标题没有明确的关系。

如果您的输出是非线性的,您可以使用多个校准点,并在点之间进行线性插值,但是曲线很可能可以通过方程来表征。在感兴趣的范围内进行多次测量,然后在 Excel 或 OpenOffice.org Calc 等电子表格工具中绘制这些点。图表工具包括各种类型的“趋势线”绘图,并可以显示曲线的方程。选择具有适当拟合的最简单的曲线类型。如果您需要使用具有两个以上项的多项式,请确保显示具有足够小数位的方程项,因为这些可能很关键。您可以通过使用方程式生成曲线并查看它与趋势线的匹配程度来测试您是否具有足够的精度。绘制方程对于任何曲线都可能是一个好主意,以测试足够的精度。编写代码时,请确保使用的数据类型也具有足够的精度。

关于该行的注释:

LPOUT = LPACC / K;

通过采集 5000 个样本,您有效地将 ADC 分辨率提高了大约 12 位(以采样时间为代价),但是通过除以 K,您不必要地失去了该精度,并且它也是一个截断除法。换算成公斤时,最好直接使用不相除的总和。我意识到除法使值看起来“稳定”,但它与信噪比有关,而不是绝对噪声幅度。转换为 Kg 并显示为所需的实际精度将具有“稳定”结果的相同效果,但累积误差更小。

于 2013-08-01T22:04:36.680 回答
0

您可能会发现这是一种有用的平均方法:

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

这实现了一个真正的低通滤波器,其时间常数为 TIME_CONSTANT x 采样频率。如果 ADCreading 有阶跃变化,FilteredValue 会逐渐变为新值。理论上它永远不会到达它,因为它实现了一个逆指数滤波器。TIME_CONSTANT 的值越大,噪声抑制效果越好,但稳定所需的时间越长。

于 2013-09-06T11:07:13.627 回答