Embedded 如何修复STM32F107读取的模拟输入振荡

Embedded 如何修复STM32F107读取的模拟输入振荡,embedded,microcontroller,processor,stm32,analog-digital-converter,Embedded,Microcontroller,Processor,Stm32,Analog Digital Converter,我必须使用处理器STM32F107从外部源读取输入值,该外部源是一个天平。该天平位于包含处理器的电路板外部,并通过PA4与之通信 这是我第一次尝试从天平读取输入 我使用此功能设置ADC: void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; /* PCLK2 is the APB2 clock */ /* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/ RCC_ADCCL

我必须使用处理器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_通道_4)的输出为715760748711759等

我做错了什么

编辑。我已经添加了这个函数(模拟lp过滤器)来稳定输入,它工作得很好。问题是如何将此函数返回的值转换为kg。使用协方差系数(通过测量已知对象确定)会给出一个和输入权重增加成正比的增长误差。有没有建议进行更好的转换

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;
}
double-fix_振荡(){
int i;
双LPOUT=0,LPACC=0;
int K=5000;

对于(i=0;i而言,可能是输入本身有噪声,也可能是其他设备引入的噪声。值得使用示波器观察信号,以确定信号上的干扰或噪声类型,因为这可能会影响最佳解决方案


如果可能,应消除任何外部干扰源,然后应用外部模拟信号条件,理想情况下使用截止频率为预期采样率一半或更低的低通滤波器。然后,如有必要,可在数字域中应用滤波。对于静态信号(电压电平),一个简单的块平均值就足够了,对于更快的移动信号,一个移动平均值(boxcar滤波器)更好。对于需要从中提取特定频率的复杂信号,需要更复杂的滤波器,但在本例中可能并非如此。

可能是输入本身有噪声,或者噪声是由其他设备引入的。使用示波器观察信号的频率是值得的确定信号上的干扰或噪声类型,因为这可能会影响最佳解决方案

如果可能,应消除任何外部干扰源,然后应用外部模拟信号条件,理想情况下使用截止频率为预期采样率一半或更低的低通滤波器。然后,如有必要,可在数字域中应用滤波。对于静态信号(电压电平),简单的块平均就足够了,对于更快的移动信号,移动平均(boxcar滤波器)会更好。对于需要从中提取特定频率的复杂信号,需要更复杂的滤波器,但在本例中可能不是这样

编辑。我添加了这个函数(模拟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;
}
这可能值得单独发布一个问题,因为它与问题标题没有明确的关系

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

关于该行的注释:

LPOUT = LPACC / K;
通过采集5000个样本,您有效地将ADC分辨率提高了约12位(以牺牲采样时间为代价),但除以K,不必要地失去了精度,这也是一个截断除法。最好在转换为Kg时直接使用不可分割的和。我意识到,除法使值看起来“稳定”但这是关于信噪比而不是绝对噪声大小的。转换为Kg并显示为所需的真实世界精度将具有相同的“稳定”结果的效果,但累积误差较小

编辑。我添加了这个函数(模拟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;
}
这可能值得单独发布一个问题,因为它与问题标题没有明确的关系

如果您的输出是非线性的,您可以使用多个校准点,并在点之间进行线性插值,但是曲线很可能由一个方程表征。在感兴趣的范围内进行大量测量,然后在电子表格工具(如Excel或OpenOffice.org Calc)中绘制这些点。图表工具包括各种类型的“趋势线”绘图,可以显示曲线的方程式。选择最简单的曲线