打印
[STM32F3]

STM32F373使用SDADC结合DMA采样电压,采集的数据偏大且波动大

[复制链接]
7975|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
深枭|  楼主 | 2014-8-29 10:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 深枭 于 2014-9-26 17:55 编辑

————————2014-9-26————————
    咳咳,有点久了,还是来现在说明一下:
    当时我要采集一个峰峰值为0.5V的正弦交流信号(由仪表输出,仪表电池供电,浮空的,没有和stm32有连接关系),均值为零的那种。
    然后我就采用直接从stm32的Vref引出一条线,和交流信号输出负端相连,抬高电压,再来测量交流信号——SDADC差分输入。
    不晓得这样会不会影响?是否会拉低Vref?或者使Vref不稳定?


使用SDADC1的差分输入模式。VREFSD+采用片内1.22V做参考电压,在VREFSD+和VREFSD-之间以1uF+10nF相连,VREFSD-接GND。
配置DMA,一次采样1024个点;定时器TIM19触发。基本情况就是这些。
下面通过测量直流0.5V说明问题:
应该测得的数据为(0.5/1.22)*2^16=26859,实测数据为下图所示

这。。。。。。。。。。误差太大,而且波动也太剧烈了,根本不能做后续工作啊,怎么搞?

代码基本为库文件中所提供的例子,为了保证测量的数据与程序的对应,就直接上程序了,注释部分不删除,可能有点乱。如下所示
》》》》》》注释部分略多,请自动忽略》》》》》》:L:L:L:L:L:L
希望大神帮忙解决疑惑啊!
uint32_t SDADC1_Config(void)
{
  SDADC_AINStructTypeDef SDADC_AINStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  DMA_InitTypeDef   DMA_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
   uint32_t SDADCTimeout = 0;
        
        /* Enable DMA2 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
     
  /* ECG_SDADC APB2 interface clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDADC1 ,ENABLE);//| RCC_APB2Periph_SDADC2, ENABLE);
  
  /* PWR APB1 interface clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  /* Enable ECG_SDADC analog interface */
  PWR_SDADCAnalogCmd(PWR_SDADCAnalog_1, ENABLE);
//        PWR_SDADCAnalogCmd(PWR_SDADCAnalog_2, ENABLE);
//        PWR_SDADCAnalogCmd(PWR_SDADCAnalog_3, ENABLE);
  
  /* Set the SDADC divider: The SDADC should run @6MHz */
  /* If Sysclk is 72MHz, SDADC divider should be 12 */
  RCC_SDADCCLKConfig(RCC_SDADCCLK_SYSCLK_Div12);
        
          /* GPIOE Peripheral clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);// | RCC_AHBPeriph_GPIOB, ENABLE);//8-20注释,发现错误,将GPIOA改为GPIOB,只要2路ADC的话,GPIOB也没用了
  
  /* ECG_SDADC channel pin configuration: PE8,PE9,PE11,PE12*/
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9 ;//| GPIO_Pin_11 | GPIO_Pin_12;// | GPIO_Pin_13 | GPIO_Pin_14;//8-20注释
  GPIO_Init(GPIOE, &GPIO_InitStructure);
        
//        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1;//8-20注释
//        GPIO_Init(GPIOB, &GPIO_InitStructure);
        
  DMA_StructInit(&DMA_InitStructure);
        /* Config the DMA2 channel 3 */
  DMA_DeInit(DMA2_Channel3);
  DMA2_MEM_LEN=length;
  DMA_InitStructure.DMA_PeripheralBaseAddr  = SDADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr      = (uint32_t)InjectedConvData;
  DMA_InitStructure.DMA_DIR                 = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize          = DMA2_MEM_LEN;
  DMA_InitStructure.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc           = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize      = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode                = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority            = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M                 = DMA_M2M_Disable;
  DMA_Init(DMA2_Channel3, &DMA_InitStructure);
        
  /* Enable DMA2 Channel3 Transfer half and Complete interrupt */
  DMA_ITConfig(DMA2_Channel3, DMA_IT_TC, ENABLE);
  
  /* Enable DMA2 Channel3 */
  DMA_Cmd(DMA2_Channel3, ENABLE);
        
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
               
  SDADC_DeInit(SDADC1);
//        SDADC_DeInit(SDADC2);
  /* Select External reference: The reference voltage selection is available
     only in SDADC1 and therefore to select the VREF for SDADC2/SDADC3, SDADC1
     clock must be already enabled */
  SDADC_VREFSelect(POT_SDADC_VREF);
  /* Insert delay equal to ~10 ms (4 ms required) */
  delay_ms(5);
  
  /* ENABLE ECGSDADC */
  SDADC_Cmd(SDADC1, ENABLE);
//        SDADC_Cmd(SDADC2, ENABLE);
  
  /* Enter initialization mode */
  SDADC_InitModeCmd(SDADC1, ENABLE);
//        SDADC_InitModeCmd(SDADC2, ENABLE);
        
  SDADCTimeout = SDADC_INIT_TIMEOUT;
  /* wait for INITRDY flag to be set */
  while((SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
  if(SDADCTimeout == 0)
  {
    /* INITRDY flag can not set */
    return 1;
  }
        
//        SDADCTimeout = SDADC_INIT_TIMEOUT;
//  /* wait for INITRDY flag to be set */
//  while((SDADC_GetFlagStatus(SDADC2, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
//        if(SDADCTimeout == 0)
//  {
//    /* INITRDY flag can not set */
//    return 1;
//  }
        
  SDADC_AINStructure.SDADC_InputMode = SDADC_InputMode_Diff;
  SDADC_AINStructure.SDADC_Gain = POT_SDADC_GAIN;
  SDADC_AINStructure.SDADC_CommonMode = SDADC_CommonMode_VSSA;
  SDADC_AINStructure.SDADC_Offset = 0;
  SDADC_AINInit(SDADC1, SDADC_Conf_0, &SDADC_AINStructure);
//        SDADC_AINInit(SDADC2, SDADC_Conf_0, &SDADC_AINStructure);
  
  
  /* select ECG_SDADC channel to use conf0 */
  SDADC_ChannelConfig(SDADC1, SDADC_Channel_8, SDADC_Conf_0);
//        SDADC_ChannelConfig(SDADC2, SDADC_Channel_4, SDADC_Conf_0);
        
        /* select SDADC Channel */
  SDADC_InjectedChannelSelect(SDADC1, SDADC_Channel_8 );
//        SDADC_InjectedChannelSelect(SDADC2, SDADC_Channel_4 );
  
        /* 3、4路SDADC configuration */
//        SDADC_AINInit(SDADC1, SDADC_Conf_1, &SDADC_AINStructure);//8-20注释
//        SDADC_AINInit(SDADC2, SDADC_Conf_1, &SDADC_AINStructure);        
//        SDADC_ChannelConfig(SDADC1, SDADC_Channel_6, SDADC_Conf_1);
//        SDADC_ChannelConfig(SDADC2, SDADC_Channel_2, SDADC_Conf_1);
        
        /* Select the SDADC injected channel */
//  SDADC1->JCHGR |= (uint32_t) (SDADC_Channel_6 & 0x0000FFFF);//8-20注释
//        SDADC2->JCHGR |= (uint32_t) (SDADC_Channel_2 & 0x0000FFFF);
        
//        SDADC_InjectedContinuousModeCmd(SDADC1,ENABLE);
//        SDADC_InjectedContinuousModeCmd(SDADC2,ENABLE);
        
//  /* Select an external trigger */
    SDADC_ExternalTrigInjectedConvConfig(SDADC1, SDADC_ExternalTrigInjecConv_T19_CC2);

  /* Select rising edge */
   SDADC_ExternalTrigInjectedConvEdgeConfig(SDADC1, SDADC_ExternalTrigInjecConvEdge_Rising);

  
   /*JSYNC: Launch a injected conversion synchronously with SDADC1
        0: Do not launch injected conversion synchronously with SDADC1
        1: Launch an injected conversion in this SDADC at the same moment that an injected conversion is
        launched in SDADC1
        This bit can be modified only when INITRDY=1 (SDADC_ISR) or ADON=0 (SDADC_CR2).*/
//        SDADC_InjectedSynchroSDADC1(SDADC2,ENABLE);
        
   /* Enable DMA transfer for injected conversions */
  SDADC_DMAConfig(SDADC1, SDADC_DMATransfer_Injected, ENABLE);
        
//        SDADC_FastConversionCmd(SDADC1,ENABLE);
//        SDADC_FastConversionCmd(SDADC2,ENABLE);
        
//        /* configure calibration to be performed on conf0 */
//  SDADC_CalibrationSequenceConfig(SDADC1, SDADC_CalibrationSequence_1);
//        /* configure calibration to be performed on conf0 */
//  SDADC_CalibrationSequenceConfig(SDADC2, SDADC_CalibrationSequence_1);
        
  /* Exit initialization mode */
  SDADC_InitModeCmd(SDADC1, DISABLE);
//        SDADC_InitModeCmd(SDADC2, DISABLE);
        
        
        
        ///////////////////////////校准/////////////////////////////////////         
//  /* configure calibration to be performed on conf0 */
//  SDADC_CalibrationSequenceConfig(SDADC1, SDADC_CalibrationSequence_2);
  SDADC_CalibrationSequenceConfig(SDADC1, SDADC_CalibrationSequence_1);
  /* start ECG_SDADC Calibration */
  SDADC_StartCalibration(SDADC1);
  /* Set calibration timeout: 5.12 ms at 6 MHz in a single calibration sequence */
  SDADCTimeout = SDADC_CAL_TIMEOUT;
  /* wait for ECG_SDADC Calibration process to end */
  while(SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_EOCAL) == RESET && (--SDADCTimeout != 0));
  if(SDADCTimeout == 0)
  {
    /* EOCAL flag can not set */
    return 2;
  }
//        SDADC_SoftwareStartInjectedConv(SDADC1);

  
        
//        ////////////////////////////校准////////////////////////////////////        
////         /* configure calibration to be performed on conf0 */
////  SDADC_CalibrationSequenceConfig(SDADC2, SDADC_CalibrationSequence_2);
//  /* start ECG_SDADC Calibration */
//  SDADC_StartCalibration(SDADC2);
//        /* Set calibration timeout: 5.12 ms at 6 MHz in a single calibration sequence */
//  SDADCTimeout = SDADC_CAL_TIMEOUT;
//  /* wait for ECG_SDADC Calibration process to end */
//  while(SDADC_GetFlagStatus(SDADC2, SDADC_FLAG_EOCAL) == RESET && (--SDADCTimeout != 0));
//        if(SDADCTimeout == 0)
//  {
//    /* EOCAL flag can not set */
//    return 2;
//  }        
               
        return 0;
}

/**
  * @brief  Configure timer TIM3: It is used as trigger for SDADC conversion
  * @param  None
  * @retval None
  */
void TIM19_Config(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef        TIM_OCInitStructure;
  
  /* Enable TIM19 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM19, ENABLE);
  
  TIM_DeInit(TIM19);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
        
  TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/100/SAMPLING_FREQ-1;                        //自动装载值72M/SAMPLING_FREQ,相当于得到定时器的频率为SAMPLING_FREQ
  TIM_TimeBaseStructure.TIM_Prescaler = 99;                                                                                                                                                        //预分频CK_CNT=fCK_PSC/(0+1)
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
//  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
  TIM_TimeBaseInit(TIM19, &TIM_TimeBaseStructure);
  
  /* Channel2 Configuration in PWM mode */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;               
//  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;                  
  TIM_OCInitStructure.TIM_Pulse = SystemCoreClock/100/SAMPLING_FREQ/2;                                        //保证从0向上计数时,在TIM_Period/2处产生一个上升沿,保证在定时器频率下,每个周期触发SDADC一次,触发频率为SAMPLING_FREQ
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;;         
  TIM_OC2Init(TIM19, &TIM_OCInitStructure);
//        TIM_OC2Init(TIM3, &TIM_OCInitStructure);
  
//        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
//  
//  TIM_ITConfig(TIM3, TIM_IT_CC1 , ENABLE);
//  
//  TIM_ARRPreloadConfig(TIM3, ENABLE);
        
  /* TIM19 enable counter */
  TIM_Cmd(TIM19, ENABLE);
}
沙发
mmuuss586| | 2014-8-29 10:29 | 只看该作者
1、看下电源电压是否稳定;
   模拟电源和数字电源都看下;
2、VREF脚加个10uf的电容;
3、看你的数据
   我看稳定性还好,查下输入本身是否稳定,还有地线的处理;
   如果是直流信号,建议做下平均值滤波看看;

使用特权

评论回复
板凳
深枭|  楼主 | 2014-8-29 10:55 | 只看该作者
mmuuss586 发表于 2014-8-29 10:29
1、看下电源电压是否稳定;
   模拟电源和数字电源都看下;
2、VREF脚加个10uf的电容;

1、用万用表测量,VDD(3V3)=3.305V,参考电压VREFSD+引脚为1.23V;
2、参考电源之间接1uF和10nF不够吗?
3、这是JDATA里的值,当我转换成电压时,最大值有0.521V,最小值有0.509。

使用特权

评论回复
地板
深枭|  楼主 | 2014-8-29 11:03 | 只看该作者
另:我是采用USB转3.3V给芯片供电,不知会有影响否?

使用特权

评论回复
5
hudi008| | 2014-8-29 23:59 | 只看该作者
中值滤波

使用特权

评论回复
6
hudi008| | 2014-8-29 23:59 | 只看该作者
滑动滤波

使用特权

评论回复
7
hudi008| | 2014-8-30 00:01 | 只看该作者
这样就能消除干扰了

使用特权

评论回复
8
hudi008| | 2014-8-30 00:01 | 只看该作者
或者使用基准电压芯片的

使用特权

评论回复
9
hudi008| | 2014-8-30 00:02 | 只看该作者

使用特权

评论回复
10
mmuuss586| | 2014-8-30 09:41 | 只看该作者
深枭 发表于 2014-8-29 10:55
1、用万用表测量,VDD(3V3)=3.305V,参考电压VREFSD+引脚为1.23V;
2、参考电源之间接1uF和10nF不够吗 ...

做下平均值滤波看看,跳动多少;
100次,1000次都试下;

使用特权

评论回复
11
wangdezhi| | 2014-8-30 10:50 | 只看该作者
电源不稳定

使用特权

评论回复
12
wangdezhi| | 2014-8-30 10:50 | 只看该作者

使用特权

评论回复
13
1398117027| | 2014-8-30 11:45 | 只看该作者
看过一个文档,借用DMA实现滤波

使用特权

评论回复
14
figoxwm| | 2014-10-24 11:00 | 只看该作者
先保证电源稳定先。

使用特权

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

本版积分规则

1

主题

3

帖子

0

粉丝