OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5770|回复: 6

采用ADC+DMA进行三通道AD转换时AD值不对,求助!

[复制链接]

4

主题

10

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2013-8-5
在线时间
0 小时
发表于 2014-5-7 11:11:05 | 显示全部楼层 |阅读模式
5金钱


void TIM2_IRQHandler(void)
{

  TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  ADC_SoftwareStartConvCmd(ADC1,ENABLE);
                 
   while(!(DMA_GetFlagStatus(DMA1_FLAG_TC1)));
  ADC_SoftwareStartConvCmd(ADC1,DISABLE);
    adc_current=adc_value[0];
    adc_voltagea=adc_value[1];
    adc_voltageb=adc_value[2];

     DMA_ClearFlag(DMA1_FLAG_TC1);
  i++;
   if(i==7)
   {
   i=0;
   Max_cu=adc_current[0];
      Min_cu=adc_current[0];
      sum_cu=adc_current[0];
   Max_voa=adc_voltagea[0];
      Min_voa=adc_voltagea[0];
      sum_voa=adc_voltagea[0];
   Max_vob=adc_voltageb[0];
      Min_vob=adc_voltageb[0];
      sum_vob=adc_voltageb[0];
      for(i=1;i<7;i++)
       {
         sum_cu=sum_cu+adc_current;
         if(adc_current>Max_cu) Max_cu=adc_current;
         if(adc_current<Min_cu) Min_cu=adc_current;
      sum_voa=sum_voa+adc_voltagea;
         if(adc_voltagea>Max_voa) Max_voa=adc_voltagea;
         if(adc_voltagea<Min_voa) Min_voa=adc_voltagea;
      sum_vob=sum_vob+adc_voltageb;
         if(adc_voltageb>Max_vob) Max_vob=adc_voltageb;
         if(adc_voltageb<Min_vob) Min_vob=adc_voltageb;
       }
   adc_cu=(sum_cu-Max_cu-Min_cu)/5;
   adc_voa=(sum_voa-Max_voa-Min_voa)/5;
   adc_vob=(sum_vob-Max_vob-Min_vob)/5;
   i=0;
   }
}

void ADC_RegularChannelConfiguration(void)
{
 ADC_InitTypeDef ADC_InitStructure;
 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
 ADC_InitStructure.ADC_ScanConvMode=ENABLE;
 ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
 ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
 ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
 ADC_InitStructure.ADC_NbrOfChannel=3;
 ADC_Init(ADC1,&ADC_InitStructure);

 ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_1Cycles5);
 ADC_RegularChannelConfig(ADC1,ADC_Channel_11,2,ADC_SampleTime_1Cycles5);
 ADC_RegularChannelConfig(ADC1,ADC_Channel_12,3,ADC_SampleTime_1Cycles5);

 ADC_DMACmd(ADC1,ENABLE);
 ADC_Cmd(ADC1,ENABLE);

 ADC_ResetCalibration(ADC1);
 while(ADC_GetResetCalibrationStatus(ADC1));
 ADC_StartCalibration(ADC1);
 while(ADC_GetCalibrationStatus(ADC1)); 
 ADC_ClearFlag(ADC1, ADC_FLAG_EOC); 
 ADC_SoftwareStartConvCmd(ADC1,DISABLE);
 
}

 

void DMA_Configuration(void)
{
 DMA_InitTypeDef DMA_InitStructure;
   
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//adc1的数据寄存器设备地址,数据手册上有
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adc_value;//一个有3个元素数组的首地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 3;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    //循环模式开启,Buffer写满后,自动回到初始地址开始传输
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

 DMA_ClearFlag(DMA1_FLAG_TC1);
    //配置完成后,启动DMA通道
  DMA_ClearITPendingBit(DMA1_IT_TC1);
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

 

void Timer2_Configuration(void)
{
 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

 

 TIM_DeInit(TIM2);
 TIM_TimeBaseStructure.TIM_Period=9;
 TIM_TimeBaseStructure.TIM_Prescaler=35999;
 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
 TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);  
    
  TIM_ClearFlag(TIM2,TIM_FLAG_Update);
 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
 TIM_Cmd(TIM2,ENABLE);

}

 

最佳答案

查看完整内容[请看2#楼]

楼猪你妹啊,发个帖子然后就失踪了,这个问题我已经在21ic上回复你了,一直都没给反馈,我把以前回复你的再贴过来吧。 1、楼猪的问题描述得不够具体,多通道采集ADC值不对太模糊,到底是采集值为0、还是采集值正确但通道出现了错位。 2、 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adc_value;//一个有3个元素数组的首地址  楼猪的这句代码虽然对问题解决影响不大,但是adc_value已经是地址了,前面 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2014-5-4
在线时间
0 小时
发表于 2014-5-7 11:11:06 | 显示全部楼层
楼猪你妹啊,发个帖子然后就失踪了,这个问题我已经在21ic上回复你了,一直都没给反馈,我把以前回复你的再贴过来吧。
1、楼猪的问题描述得不够具体,多通道采集ADC值不对太模糊,到底是采集值为0、还是采集值正确但通道出现了错位。
2、 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adc_value;//一个有3个元素数组的首地址  楼猪的这句代码虽然对问题解决影响不大,但是adc_value已经是地址了,前面加个&没什么意义,可以去掉。
3、看楼猪程序思路比较明确,定时器2的中断中手动软件触发ADC多通道转换,逻辑很清楚,但是既然是每次进定时器中断后手动启动转换,为什么还要设置ADC为连续转换模式:ADC_InitStructure.ADC_ContinuousConvMode=ENABLE; 单次转换就可以了。
4、楼猪选取了ADC的10、11、12三个通道,对应PC0、PC1、PC2三个引脚,建议楼猪检查硬件电路,这三个引脚是不是有对应的采样信号输入。

下面给出帮楼猪改好的程序:
main函数里:
#include "stm32f10x.h"
#include <stdio.h>

/* rivate define ------------------------------------------------------------*/
#define ADC1_DR_Address    ((u32)0x4001244C)
/* rivate function prototypes -----------------------------------------------*/
void ADC_Configuration(void);
void Timer2_Configuration(void);
/* rivate variables ---------------------------------------------------------*/

vu16 adc_value[3];
/*******************************************************************************
* Function Name: main
* Description : Main program
* Input       : None
* Output      : None
* Return      : None
* Attention              : None
*******************************************************************************/
int main(void)
{
        ADC_Configuration();
        Timer2_Configuration();
  
        
  while (1)
  {        
  }
}

/*******************************************************************************
* Function Name: ADC_Configuration
* Description : Configure the ADC.
* Input       : None
* Output      : None
* Return      : None
* Attention              : None
*******************************************************************************/
void Timer2_Configuration(void)
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
        TIM_DeInit(TIM2);
        TIM_TimeBaseStructure.TIM_Period=9;
        TIM_TimeBaseStructure.TIM_Prescaler=35999;
        TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);     
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
        TIM_Cmd(TIM2,ENABLE);



void ADC_Configuration(void)
{
          

          GPIO_InitTypeDef GPIO_InitStructure;
          NVIC_InitTypeDef NVIC_InitStructure;
          DMA_InitTypeDef DMA_InitStructure;
          ADC_InitTypeDef ADC_InitStructure;
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE);
          RCC_ADCCLKConfig(RCC_PCLK2_Div6);
          RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

                    /* Configure C0 ()as analog input -------------------------*/
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);  //选择端口PC0,最大输出速度50MHZ,模拟输入 
        
          /* Configure C4 (ADC12 Channel4)as analog input -------------------------*/
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);  //选择端口PC1,最大输出速度50MHZ,模拟输入 
        
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);  //选择端口PC2,最大输出速度50MHZ,模拟输入
           
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);  //选择端口PC3,最大输出速度50MHZ,模拟输入 
          
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);  //选择端口PC4,最大输出速度50MHZ,模拟输入 
  
          /* Configure one bit for preemption priority */
          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
          
          /* Enable the TIM2 Interrupt */
          NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
          NVIC_Init(&NVIC_InitStructure);         
                                                /* DMA channel1 configuration ----------------------------------------------*/
                DMA_DeInit(DMA1_Channel1);
            DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//adc1的数据寄存器设备地址,数据手册上有
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)adc_value;//一个有3个元素数组的首地址
            DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
            DMA_InitStructure.DMA_BufferSize = 3;
            DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
            DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
            DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
            DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
            //循环模式开启,Buffer写满后,自动回到初始地址开始传输
            DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
            DMA_InitStructure.DMA_Priority = DMA_Priority_High;
            DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
            DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        
                DMA_ClearFlag(DMA1_FLAG_TC1);
                    //配置完成后,启动DMA通道
                DMA_ClearITPendingBit(DMA1_IT_TC1);
                DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
                DMA_Cmd(DMA1_Channel1, ENABLE);
                
                ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
                ADC_InitStructure.ADC_ScanConvMode=ENABLE;
                ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
                ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
                ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
                ADC_InitStructure.ADC_NbrOfChannel=3;
                ADC_Init(ADC1,&ADC_InitStructure);
                
                ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_1Cycles5);
                ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_1Cycles5);
                ADC_RegularChannelConfig(ADC1,ADC_Channel_13,3,ADC_SampleTime_1Cycles5);
                
                ADC_DMACmd(ADC1,ENABLE);
                ADC_Cmd(ADC1,ENABLE);
                
                ADC_ResetCalibration(ADC1);
                while(ADC_GetResetCalibrationStatus(ADC1));
                ADC_StartCalibration(ADC1);
                while(ADC_GetCalibrationStatus(ADC1));  
                ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
                ADC_SoftwareStartConvCmd(ADC1,DISABLE);
}

中断函数里:
    #include "stm32f10x_it.h"
    vu16 adc_current[7];
    vu16 ci=0;
    vu16 Max_cu=0;
    vu16 Min_cu=0;
    vu16 sum_cu=0;
    vu16 Max_voa=0;
    vu16 Min_voa=0;
    vu16 sum_voa=0;
    vu16 Max_vob=0;
    vu16 Min_vob=0;
    vu16 sum_vob=0;
    vu16 adc_cu=0;
    vu16 adc_voa=0;
    vu16 adc_vob=0;
    extern vu16 adc_value[3];
    vu16 adc_voltagea[7];
    vu16 adc_voltageb[7];
    /** @addtogroup STM32F10x_StdPeriph_Template
      * @{
      */
    /* rivate typedef -----------------------------------------------------------*/
    /* rivate define ------------------------------------------------------------*/
    /* rivate macro -------------------------------------------------------------*/
    /* rivate variables ---------------------------------------------------------*/
    /* rivate function prototypes -----------------------------------------------*/
    /* Private functions ---------------------------------------------------------*/

    /******************************************************************************/
    /*            Cortex-M3 Processor Exceptions Handlers                         */
    /******************************************************************************/

    /**
      * @brief  This function handles NMI exception.
      * @param  None
      * @retval None
      */
    void NMI_Handler(void)
    {
    }

    /**
      * @brief  This function handles Hard Fault exception.
      * @param  None
      * @retval None
      */
    void HardFault_Handler(void)
    {
      /* Go to infinite loop when Hard Fault exception occurs */
      while (1)
      {
      }
    }

    /**
      * @brief  This function handles Memory Manage exception.
      * @param  None
      * @retval None
      */
    void MemManage_Handler(void)
    {
      /* Go to infinite loop when Memory Manage exception occurs */
      while (1)
      {
      }
    }

    /**
      * @brief  This function handles Bus Fault exception.
      * @param  None
      * @retval None
      */
    void BusFault_Handler(void)
    {
      /* Go to infinite loop when Bus Fault exception occurs */
      while (1)
      {
      }
    }

    /**
      * @brief  This function handles Usage Fault exception.
      * @param  None
      * @retval None
      */
    void UsageFault_Handler(void)
    {
      /* Go to infinite loop when Usage Fault exception occurs */
      while (1)
      {
      }
    }

    /**
      * @brief  This function handles SVCall exception.
      * @param  None
      * @retval None
      */
    void SVC_Handler(void)
    {
    }

    /**
      * @brief  This function handles Debug Monitor exception.
      * @param  None
      * @retval None
      */
    void DebugMon_Handler(void)
    {
    }

    /**
      * @brief  This function handles PendSVC exception.
      * @param  None
      * @retval None
      */
    void PendSV_Handler(void)
    {
    }

    /**
      * @brief  This function handles SysTick Handler.
      * @param  None
      * @retval None
      */



    void TIM2_IRQHandler(void)
    {

      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
      ADC_SoftwareStartConvCmd(ADC1,ENABLE);
                      
       while(!(DMA_GetFlagStatus(DMA1_FLAG_TC1)));
      ADC_SoftwareStartConvCmd(ADC1,DISABLE);
        adc_current[ci]=adc_value[0];
        adc_voltagea[ci]=adc_value[1];
        adc_voltageb[ci]=adc_value[2];

         DMA_ClearFlag(DMA1_FLAG_TC1);
      ci++;
       if(ci==7)
       {
       ci=0;
       Max_cu=adc_current[0];
          Min_cu=adc_current[0];
          sum_cu=adc_current[0];
       Max_voa=adc_voltagea[0];
          Min_voa=adc_voltagea[0];
          sum_voa=adc_voltagea[0];
       Max_vob=adc_voltageb[0];
          Min_vob=adc_voltageb[0];
          sum_vob=adc_voltageb[0];
          for(ci=1;ci<7;ci++)
           {
             sum_cu=sum_cu+adc_current[ci];
             if(adc_current[ci]>Max_cu) Max_cu=adc_current[ci];
             if(adc_current[ci]<Min_cu) Min_cu=adc_current[ci];
          sum_voa=sum_voa+adc_voltagea[ci];
             if(adc_voltagea[ci]>Max_voa) Max_voa=adc_voltagea[ci];
             if(adc_voltagea[ci]<Min_voa) Min_voa=adc_voltagea[ci];
          sum_vob=sum_vob+adc_voltageb[ci];
             if(adc_voltageb[ci]>Max_vob) Max_vob=adc_voltageb[ci];
             if(adc_voltageb[ci]<Min_vob) Min_vob=adc_voltageb[ci];
           }
       adc_cu=(sum_cu-Max_cu-Min_cu)/5;
       adc_voa=(sum_voa-Max_voa-Min_voa)/5;
       adc_vob=(sum_vob-Max_vob-Min_vob)/5;
       ci=0;
       }
    }

最后补充几句:
1、楼猪的程序里没有提供tim2的中断配置,没有提供ADC的时钟配置,没有提供PC0、PC1、PC2的GPIO口配置,我都给补上了。
2、有个问题,楼猪在中断处理函数和main函数中都调用了adc_value这个数组,不知道楼猪怎么定义的,我采取的方式是在main函数中定义,然后中断函数中用extern声明一下。
3、ADC的时钟频率不能超过14MHz,楼猪给的代码里没有ADC时钟配置,所以RCC_ADCCLKConfig(RCC_PCLK2_Div6);这句话不知道楼猪有没有用到。
4、AD采集IO口要设置成模拟输入。
5、建议楼猪用我帮楼猪改的程序试试,如果还有问题,建议楼猪把手里的板子砸了,或者在夜深人静的时候找个墙角好好的思考一下,人品出了问题是无药可救的!>
回复

使用道具 举报

4

主题

10

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2013-8-5
在线时间
0 小时
 楼主| 发表于 2014-5-7 11:11:19 | 显示全部楼层
在改变对应AD引脚后,相同电平对应的AD值和没改变引脚前是不一样的,这是什么引起的啊!!!
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-5-7 14:41:50 | 显示全部楼层
参考下论坛别人的代码吧.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

109

主题

1606

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2222
金钱
2222
注册时间
2011-12-15
在线时间
37 小时
发表于 2014-5-8 16:50:32 | 显示全部楼层
我记得我写过有关于ADC_DMA的采集程序,你可以找一下。
专业制作STM32 物联网通信模块板,模块交流群:369840039。
回复

使用道具 举报

81

主题

1002

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1876
金钱
1876
注册时间
2014-9-10
在线时间
208 小时
发表于 2014-9-30 09:19:18 | 显示全部楼层
回复【5楼】cdshkf:
---------------------------------
回复了这么长,顶一个。
小小蜗牛
回复

使用道具 举报

27

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
387
金钱
387
注册时间
2014-8-19
在线时间
0 小时
发表于 2014-10-1 21:07:36 | 显示全部楼层
回复【2楼】wukon:
---------------------------------
解决了没?
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-30 20:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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