stm32中的adc多次采样求均值减少误差的方法

就是我用的是f429挑战者的板子。用adc接地的时候发现有零点误差,于是就移植了网上一个f103的例程,通过多次测量求均值的方法来实现adc的精准测量。
思路大概就是先定义一个get_adc_average的函数,在函数里用
for(t=0;t<times;t++)
    {
       
        temp_val+=Get_Adc();
        
    }
实现求平均值。然后Get_Adc()程序如下:

u16 Get_adc()  
{
      //设置指定ADC的规则组通道,一个序列,采样时间
    ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);;    //ADC1,ADC通道,采样时间为239.5周期                     
  ADC_Cmd(RHEOSTAT_ADC, ENABLE);
        ADC_SoftwareStartConv(RHEOSTAT_ADC);    //使能指定的ADC1的软件转换启动功能   
     
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果
}

编译正常。然后运行的时候发现屏幕显示一次数后就不跳变了。

然后用野火的仿真器硬件仿真。发现程序卡死在while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));一直出不来。
参考官方库,发现对ADC_GetFlagStatus就是:

if ((ADCx->SR & ADC_FLAG) != (uint8_t)RESET)
  {
    /* ADC_FLAG is set */
    bitstatus = SET;
  }
  else
  {
    /* ADC_FLAG is reset */
    bitstatus = RESET;
  }

  return  bitstatus;
然后在看while内的内容,就是要求执行else后的程序段, 就是要求(ADCx->SR & ADC_FLAG)=0
其中根据我设置好的ADC_FLAG_EOC是0x02,即二进制的10.而sr寄存器对应的该位的确是EOC.
还有在f429的参考手册中EOC置位表示转化已完成。所以这样配置应该没有错啊。
然后吊诡的事情是当我把while里面的!去掉的时候再次硬件调试,发现程序依旧卡死在while里面。
然后分析到这里就分析不下去了,所以就在这里问如下三个问题:
1. 为什么会卡在这里并且怎么解决?
2.为什么我将!去掉之后仍然是这种情况
3.对于sr的相关位我发现都是硬件配置,我可以通过软件来配置吗?


我把这个问题放在论坛上好几天,但是没有人来回答我。于是我开始自己想办法。

既然程序是卡在while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));,那么我能不能不调用这个语句而实现连续读取adc值得功能呢?

答案是肯定的。

我们可以将adc的读取函数写在adc转化中断里。因为每次adc读取完毕都可以触发中断,也就是触发中断的时候一定是完成adc转化的时候,所以就自然不用用while来判断adc是否转化完毕。具体的配置就是adc使能转化完毕中断,adc采用连续转化模式。

中断里的代码如下:

if(ADC_GetITStatus(RHEOSTAT_ADC,ADC_IT_EOC)==SET)
    {
        if(i!=10)
        {
  // 读取ADC的转换值
        V+= ADC_GetConversionValue(RHEOSTAT_ADC);
       i++;
        }
        else
            {
                ADC_ConvertedValue=V/(float)(10.0);
              i=0;
              V=0;
            
          }
    }
    ADC_ClearITPendingBit(RHEOSTAT_ADC,ADC_IT_EOC);

}   

这里在函数里定义char i和float V;i用来实现计算转化次数的功能,然后V用来实现存储每次数据的功能。而ADC_ConvertedValue则是在main.c里定义的一个外部变量。这里就用中断实现了求平均值来求adc的精确值。


然后这回其实最大的收获是以后在移植程序出现问题的时候,会不在纠结问题出在那里,而是试图去尝试自己写一段代码来解决问题。


猜你喜欢

转载自blog.csdn.net/STM_32starter/article/details/58641673