野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11845|回复: 8

关于adc通过多次测量以求精准的问题

[复制链接]
发表于 2017-2-28 20:24:05 | 显示全部楼层 |阅读模式
就是我用的是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的相关位我发现都是硬件配置,我可以通过软件来配置吗?

希望各位前辈能够帮我解决下问题,多谢。


回复

使用道具 举报

发表于 2017-3-1 08:24:22 | 显示全部楼层
429里面的IO很多都已经复用,如果发现有误差先确认下IO是否只是用于ADC功能
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-3-1 13:39:55 | 显示全部楼层
fire 发表于 2017-3-1 08:24
429里面的IO很多都已经复用,如果发现有误差先确认下IO是否只是用于ADC功能

谢谢火哥回复。使用的IO的确是只用于adc功能。存在误差较小,硬件上板子应该没什么问题。
只是很想知道能否实现求均值保证精度的算法。
还有我挂出来的那个程序为什么会卡死。
回复 支持 反对

使用道具 举报

发表于 2017-3-3 11:04:21 | 显示全部楼层
你肯定是初始化配置错了!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-3-3 12:06:40 | 显示全部楼层
wmaxwell 发表于 2017-3-3 11:04
你肯定是初始化配置错了!

谢谢
但是为什么程序是卡死在while那里呢?是不是仿真的时候程序卡死的地方不一定是真正程序运行卡死的地方。
回复 支持 反对

使用道具 举报

发表于 2017-3-3 13:01:43 | 显示全部楼层
贴一下你的初始化code,也许能帮你看出bug
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-3-6 21:19:02 | 显示全部楼层
wmaxwell 发表于 2017-3-3 13:01
贴一下你的初始化code,也许能帮你看出bug

就是用野火的例程改的呀。
管脚:
  1. static void Rheostat_ADC_GPIO_Config(void)
  2. {
  3.                 GPIO_InitTypeDef GPIO_InitStructure;
  4.        
  5.         // 使能 GPIO 时钟
  6.         RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);
  7.                
  8.         // 配置 IO
  9.         GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;
  10.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            
  11.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
  12.         GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);               
  13. }
复制代码

用的是C3管脚,ADC1通道十三。
然后是ADC配置:
  1. static void Rheostat_ADC_Mode_Config(void)
  2. {
  3.         ADC_InitTypeDef ADC_InitStructure;
  4.   ADC_CommonInitTypeDef ADC_CommonInitStructure;
  5.        
  6.   // 开启ADC时钟
  7.         RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);

  8.   // -------------------ADC Common 结构体 参数 初始化------------------------
  9.         // 独立ADC模式
  10.   ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  11.   // 时钟为fpclk x分频       
  12.   ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  13.   // 禁止DMA直接访问模式       
  14.   ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  15.   // 采样时间间隔       
  16.   ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  
  17.   ADC_CommonInit(&ADC_CommonInitStructure);
  18.        
  19.   // -------------------ADC Init 结构体 参数 初始化--------------------------
  20.   // ADC 分辨率
  21.   ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //配置分辨率
  22.   // 禁止扫描模式,多通道采集才需要       
  23.   ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  24.   // 连续转换       
  25.   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  26.   //禁止外部边沿触发
  27.   ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  28.   //使用软件触发,外部触发不用配置,注释掉即可
  29.   //ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  30.   //数据右对齐       
  31.   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  32.   //转换通道 1个
  33.   ADC_InitStructure.ADC_NbrOfConversion = 1;                                    
  34.   ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);
  35.   //---------------------------------------------------------------------------
  36.        
  37.   // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为56个时钟周期
  38.   ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
  39.         // ADC 转换结束产生中断,在中断服务程序中读取转换值
  40.        

  41.         ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);
  42.   // 使能ADC
  43.   ADC_Cmd(RHEOSTAT_ADC, ENABLE);  
  44.   //开始adc转换,软件触发
  45.   ADC_SoftwareStartConv(RHEOSTAT_ADC);
  46. }
复制代码


初始化大概就是这样了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-3-6 21:24:33 | 显示全部楼层
然后今天想加一个按键中断以实现换挡位。发现主函数里写有初始化按键的程序后,ad测得好像就不准了。

然后另外想请教下32的bug规律。我在查程序问题的时候,把主程序的按键程序注释了。然后还有中断文件里的按键中断忘了改,发现也出现了ad测量错误的情况。可是如果我主函数没有初始化按键,那么中断应该就没有用啊,不应该就对程序没有影响吗?(语法没有报错)但是发现有影响,这是为什么呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-3-9 20:22:47 | 显示全部楼层
嗯,我现在还是不知道问题出在哪里,但是我通过在中断里重复计数的方法实现了求平均值:
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);

}       
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2025-1-15 08:02 , Processed in 0.031785 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表