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的精确值。


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


STM32上进行ADC采样时,可以通过均值滤波器对采样数据进行平滑处理,以减小采样误差和噪声的影响。以下是一种简单的ADC均值滤波方法: 1. 定义一个数组,用于存储一定数量的采样数据。 2. 每次进行ADC采样时,将采样值存入数组,并计算数组所有元素的平均值。 3. 将平均值作为当前采样值,进行后续处理。 下面是一个示例代码,假设要对8个采样数据进行均值滤波: ``` #define SAMPLE_COUNT 8 // 采样数据数量 uint16_t samples[SAMPLE_COUNT]; // 采样数据数组 uint16_t sample_index = 0; // 采样数据索引 // ADC采样完成断处理函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { // 读取采样值 uint16_t sample_value = HAL_ADC_GetValue(hadc); // 将采样值存入数组 samples[sample_index] = sample_value; // 计算数组所有元素的平均值 uint32_t sum = 0; for (int i = 0; i < SAMPLE_COUNT; i++) { sum += samples[i]; } uint16_t avg = sum / SAMPLE_COUNT; // 将平均值作为当前采样值 // 进行后续处理... // ... // 更新采样数据索引 sample_index = (sample_index + 1) % SAMPLE_COUNT; } ``` 在以上代码,`samples`数组用于存储8个采样数据,`sample_index`表示当前采样数据的索引。每次ADC采样完成后,将采样值存入数组,并计算数组所有元素的平均值。最后,将平均值作为当前采样值,进行后续处理。每次更新采样数据索引时,使用取模运算来实现循环存储。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值