打印
[STM32F2]

求解STM32F207 AD转换误差问题

[复制链接]
3896|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
daven2012|  楼主 | 2015-6-24 15:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
求解求解STM32F207ZET6  ADC转换误差问题,
        我在新项目中第一次用STM32F207ZET6,使用了ADC1,ADC3两个独立的ADC,使用中发现无关的代码回影响ADC采样的数据精度,好像和编译后代码量有关。困扰好长时间了,不知道哪里出问题啊,谁能指点一下。
ADC1采样12个通道,连续循环采样,开DMA自动读取AD数据到数据RAM。
void ADC_Configuration(void)
{
        u8 i;

        ADC_InitTypeDef ADC_InitStructure;
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef DMA_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOC,ENABLE);
//  RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

       
       
        DMA_InitStructure.DMA_Channel=DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;//ADC1½Ó¿Ú¼Ä´æÆ÷Ê×µØÖ· ÍâÉèµØÖ·
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1_Value;//ADCConvertedValue;//ADC½á¹ûµØÖ·
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//dma´«Êä·½Ïòµ¥Ïò
  DMA_InitStructure.DMA_BufferSize = 120;//120;// 13*10  //ÉèÖÃDMAÔÚ´«Êäʱ»º³åÇøµÄ³¤¶È word
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//ÉèÖÃDMAµÄÍâÉèµÝÔöģʽ
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//ÉèÖÃDMAµÄÄÚ´æµÝÔöģʽ
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//ÍâÉèÊý¾Ý×Ö³¤
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//ÄÚ´æÊý¾Ý×Ö³¤
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//ÉèÖÃDMAµÄ´«Êäģʽ£ºÁ¬Ðø²»¶ÏµÄÑ­»·Ä£Ê½
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;//ÉèÖÃDMAµÄÓÅÏȼ¶±ð
        DMA_InitStructure.DMA_FIFOMode= DMA_FIFOMode_Disable; //DMA_FIFOMode_Enable;//0617
  DMA_InitStructure.DMA_FIFOThreshold= DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst= DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst= DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream4, &DMA_InitStructure);   
  DMA_Cmd(DMA2_Stream4, ENABLE);//Enable DMA1 channel1

  // ADC1 configuration ------------------------------------------------------
        ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;//  =/8
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //Á½¸ö²ÉÑù¼ä¸ô20¸öÖÜÆÚ
  ADC_CommonInit(&ADC_CommonInitStructure);

  //----------------------------------
        ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;//DISABLE; //
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 12;
  ADC_Init(ADC1, &ADC_InitStructure);
       
LED3_turn();//(其他地方程序完全不变)使用这条指令和不使用这条指令,
对我的AD转换出的结果差别有0.5V(检测的输出电压53.0v变53.5v),
这是一条控制LED开关指令,原来放在中断里,也有影响,换其他一条指令也一样,
比如一条ADC_EOCOnEachRegularChannelCmd(ADC1, DISABLE);而且,
在KEIL 设置编译代码优化级别不同也会出现上面检测电压不偏差问题,
真不知道怎么回事,ST 的FAE真难请啊!

  // ADC1 regular channel configuration
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);//²ÉÑùÖÜÆÚ
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 3, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 4, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 5, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 7, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 8, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 11, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 12, ADC_SampleTime_144Cycles);//ADC_SampleTime_56Cycles);

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);  
  ADC_DMACmd(ADC1, ENABLE);// Enable ADC1   
  ADC_Cmd(ADC1, ENABLE);// Enable ADC1
  ADC_SoftwareStartConv(ADC1);// Start ADC1 Software Conversion
       
}

uint32_t AnalogFilter(uint16_t ADCDataTab[], uint16_t nChannel)   
{
   /* ¶¨ÒåÁÙʱ±äÁ¿*/
    uint8_t i;   
    uint32_t averagevalue=0;
    uint32_t maxvalue=0;
    uint32_t minvalue=0xFFFFFFFF;               
     

                #define maxchn  12  //ͨµÀÊý
                #define maxcou  10        //»º´æÊý
    for (i=0;i<maxcou;i++) //166us*100=16.67ms
    {
        averagevalue += *(ADCDataTab+nChannel+i*maxchn);
        if(*(ADCDataTab+nChannel+i*maxchn)>maxvalue)                   //Ñ°ÕÒ×î´óÖµ
        {  
            maxvalue=*(ADCDataTab+nChannel+i*maxchn);
        }      
        if(*(ADCDataTab+nChannel+i*maxchn)<minvalue)                   //Ñ°ÕÒ×îСÖ
        {
            minvalue=*(ADCDataTab+nChannel+i*maxchn);
        }
    }
    averagevalue=(averagevalue-maxvalue-minvalue)>>3;             //ȡƽ¾ùÖµ
                                  
    return averagevalue;                                                                             //·µ»ØÂ˲¨Öµ
}


void GetSystemVoltage(void)
{        
                u32 TempData;
                u16 bb;       
        TempData  = AnalogFilter(ADC1_Value,0);
         TempData = TempData *6270/4096;                                       
         outvol =(u16)TempData;       

}


沙发
lwsn| | 2015-6-24 15:59 | 只看该作者
发现无关的代码回影响ADC采样的数据精度

怎么会这样

使用特权

评论回复
板凳
airwill| | 2015-6-24 19:12 | 只看该作者
检测的输出电压53.0v变53.5v

也就 1%, 不知道这 1% 是12位结果里相当于多少? 总之这个偏差也并不一定很大.
关于 ADC 的精度, 其实很多情况下是外面的因素导致的, 除了信号源里的噪声, 还比如电源电压AVCC波动, VREF 的波动和阻抗, 信号源阻抗....
别以为那些 FAE 就一定很专业, 芯片内部的事情他们很专业, 具体应用里的情况也就未必了.

使用特权

评论回复
地板
598330983| | 2015-6-24 22:07 | 只看该作者
误差很大吗,试试0到全程可以实现不。

使用特权

评论回复
5
daven2012|  楼主 | 2015-6-25 15:07 | 只看该作者
误差大概30个点,0.5v显示的直流电压偏差已经很大了,主要是不清楚什么情况会引起AD值的偏差,

使用特权

评论回复
6
daven2012|  楼主 | 2015-6-25 15:18 | 只看该作者
airwill 发表于 2015-6-24 19:12
检测的输出电压53.0v变53.5v

也就 1%, 不知道这 1% 是12位结果里相当于多少? 总之这个偏差也并不一定很大. ...

我想不是外面的因素导致的,我这里改的只是一条LED的指令,硬件不变就这样结果,(换另外一台机子也是一样的故障,应该和硬件没多大关系)

使用特权

评论回复
7
airwill| | 2015-6-25 21:12 | 只看该作者
大概30个点,如果没有特别注意处理好模拟信号和电压基准, 这点误差属于常见情况.
如果只是 "改的只是一条LED的指令" 引起了大的误差, 那就看看这个LED 如何导致信号及其基准方面的偏差 (假如基准来自 AVDD, 那就有可能的了)

使用特权

评论回复
8
mintspring| | 2015-6-25 21:22 | 只看该作者
是不是串扰了,很少发生这种事情

使用特权

评论回复
9
daven2012|  楼主 | 2015-6-26 14:25 | 只看该作者
airwill 发表于 2015-6-25 21:12
大概30个点,如果没有特别注意处理好模拟信号和电压基准, 这点误差属于常见情况.
如果只是 "改的只是一条LE ...

改别的指令也是一样的问题,会是哪里出的问题呢?

使用特权

评论回复
10
尤彼卡| | 2015-6-29 21:25 | 只看该作者
是不是基准电压的问题

使用特权

评论回复
11
冰河w| | 2015-6-29 21:46 | 只看该作者

误差大概30个点,不是很大吧,楼主问题,弄出来了吗

使用特权

评论回复
12
daven2012|  楼主 | 2015-7-21 09:25 | 只看该作者
没解决

使用特权

评论回复
13
daven2012|  楼主 | 2015-8-5 11:54 | 只看该作者
没加以太网程序时,AD采样稳定,加上后就开始不正常了。在程序不变的情况下,如果DP83848的50MHZ时钟由单片机接过去的话,时钟线直接连接或中间串1K的电阻,采样的AD值也会有产生明显的变化,不清楚AD为什么受以太网模块影响

使用特权

评论回复
14
dexis| | 2015-8-9 09:40 | 只看该作者
daven2012 发表于 2015-8-5 11:54
没加以太网程序时,AD采样稳定,加上后就开始不正常了。在程序不变的情况下,如果DP83848的50MHZ时钟由单片 ...

供电波动了呗

使用特权

评论回复
15
豆腐块| | 2015-8-9 09:52 | 只看该作者
供电波动了?可不可以详细说一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

9

帖子

0

粉丝