打印
[STM32F0]

STM32F030 多通道ADC DMA读取问题

[复制链接]
14926|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
自信d面对|  楼主 | 2014-2-23 00:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 自信d面对 于 2014-2-23 00:47 编辑

描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。
#define         ADC1_DR_Address      0x40012440        
__IO uint16_t RegularConvData_Tab[2];                                
__IO uint16_t ADC_ConvertedValueLocal1[AD_Array_Size];      
__IO uint16_t ADC_ConvertedValueLocal2[AD_Array_Size];      
uint8_t AD_Array_count=0;
void ADC1_DMA_Init(void)
{
        ADC_InitTypeDef     ADC_InitStruct;
        DMA_InitTypeDef     DMA_InitStruct;
        GPIO_InitTypeDef    GPIO_InitStruct;
        NVIC_InitTypeDef    NVIC_InitStruct;
        
        /* ADC1 DeInit */
        ADC_DeInit(ADC1);        
        
        /* Enable  GPIOA clock */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
        /* ADC1 Periph clock enable */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  
        /* DMA1 clock enable */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
        
        /* Configure PA.1  as analog input */
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_2;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(GPIOA, &GPIO_InitStruct);         
        
        //DMA NVIC
        NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
               
        /* DMA1 Channel1 Config */
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;//ÉèÖÃÍâÉèµØÖ·
        DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RegularConvData_Tab;//ÅäÖÃÄÚ´æÓ³ÉäµØÖ·
        DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                                
        DMA_InitStruct.DMA_BufferSize = 2;                                                                                                                                
        DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                       
        DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        
        DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;      
        DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;                                                                                       
        DMA_InitStruct.DMA_Priority = DMA_Priority_High;                                                                       
        DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                                                                                                        
        DMA_Init(DMA1_Channel1, &DMA_InitStruct);
  
        /* DMA1 Channel1 enable */
        DMA_Cmd(DMA1_Channel1, ENABLE);                                                                                                                                               
        /*Enables the specified DMAy Channelx interrupts */
        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);                                                                                       
       /* ADC DMA request in circular mode */
        ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);                                                        
       /* Enable ADC_DMA */
        ADC_DMACmd(ADC1, ENABLE);
        
        /* Initialize ADC structure */
        ADC_StructInit(&ADC_InitStruct);
        
        /* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits  */
        ADC_InitStruct.ADC_Resolution  = ADC_Resolution_12b;
        ADC_InitStruct.ADC_ContinuousConvMode  = ENABLE;
        ADC_InitStruct.ADC_ExternalTrigConvEdge  = ADC_ExternalTrigConvEdge_None;
        ADC_InitStruct.ADC_DataAlign  = ADC_DataAlign_Right;
        ADC_InitStruct.ADC_ScanDirection  = ADC_ScanDirection_Backward;
        ADC_Init(ADC1, &ADC_InitStruct);  

        ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_55_5Cycles);        
        ADC_ChannelConfig(ADC1, ADC_Channel_2, ADC_SampleTime_55_5Cycles);        
        
       /* ADCУ׼ */
        ADC_GetCalibrationFactor(ADC1);
      /* Enable ADC1 */
       ADC_Cmd(ADC1, ENABLE);     
      
      while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
      /* ADC1 regular Software Start Conv */
      ADC_StartOfConversion(ADC1);
}
DMA中断函数
void DMA1_Channel1_IRQHandler(void)
{
        if(DMA_GetFlagStatus(DMA1_FLAG_TC1) != RESET)
        {                     
                if(AD_Array_count>=AD_Array_Size)
                {
                        DMA_ClearFlag(DMA1_FLAG_TC1);
                }
                else
                {
                        ADC_ConvertedValueLocal1[AD_Array_count]=RegularConvData_Tab[0];
                        ADC_ConvertedValueLocal2[AD_Array_count]=RegularConvData_Tab[1];
                        DMA_ClearFlag(DMA1_FLAG_TC1);
                        AD_Array_count++;
                }               
        }
}

问题,PA1接低电平,PA2接高电平,通过串口显示DMA读取的数据应该是低,高,但实际结果却是(每组结果显示两次)
0000
0000
4095
4095

4093
4095
0000
0000

4093
4095
0000
0000

4095
4095
0000
0000
……
……

只有第一组数据是正确的(低高),此后数据都是相反的(高低),怎么回事?
沙发
自信d面对|  楼主 | 2014-2-23 01:05 | 只看该作者
求大神帮帮忙解决

使用特权

评论回复
板凳
自信d面对|  楼主 | 2014-2-23 01:37 | 只看该作者
我用三通道DMA采集PA0,PA1,PA2的管脚电压。对应ADC Channel为0,1,2.但是在DMA的目标buffer里,bufer[0],bufer[1],bufer[2]分别对应的数据分别是PA0,PA2,PA1,而不是PA0,PA1,PA2。在STM32F103里面的设置函数里可以设置转换顺序,但是STM32F0里面是默认的。哪个大侠知道怎么修改DMA对应的转换顺序吗?

这是我看到的一个人的问题,和我现在的一样

使用特权

评论回复
地板
keji1| | 2014-2-23 12:05 | 只看该作者
帮顶

使用特权

评论回复
5
alien6670| | 2014-3-26 22:37 | 只看该作者
我也遇到这个问题,怎么会事啊?有没有解决,分析一下!

使用特权

评论回复
6
自信d面对|  楼主 | 2014-3-27 00:04 | 只看该作者
alien6670 发表于 2014-3-26 22:37
我也遇到这个问题,怎么会事啊?有没有解决,分析一下!

估计是单片机设计的问题,我目前没找到原因,只是使用的前测试好

使用特权

评论回复
7
gurong60| | 2014-9-8 21:00 | 只看该作者
自信d面对 发表于 2014-2-23 01:37
我用三通道DMA采集PA0,PA1,PA2的管脚电压。对应ADC Channel为0,1,2.但是在DMA的目标buffer里,bufer[0],b ...

我也遇到相同问题,@香水城  

使用特权

评论回复
8
香水城| | 2014-9-9 14:44 | 只看该作者
gurong60 发表于 2014-9-8 21:00
我也遇到相同问题,@香水城

你的乱序是怎样的?和3楼一样么?本该是0--> 1--> 2的转换,DMA传到数组里看到的结果是0 --> 2 --> 1?
这样的话只有一个解释:

1. F0虽然没有像F1中那样可以自由选择通道转换的顺序,但是有个反向和正向的简单选择。如果选择了反向转换,即按照 2--> 1 --> 0的顺序。出来的结果应该是
2、 1、 02、 1、 0......

2.但是如果什么原因使得前2个转换数据漏掉,或者之前多传了一个“calibration值”,那么数组里可能就会看到
x、2、1 0、 2、 10、 2、 1...

使用特权

评论回复
9
gurong60| | 2014-9-9 23:41 | 只看该作者
香水城 发表于 2014-9-9 14:44
你的乱序是怎样的?和3楼一样么?本该是0--> 1--> 2的转换,DMA传到数组里看到的结果是0 --> 2 --> 1?
...


应该是第二种了,如何让它不丢呢,ADC代码如下


  /* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits  */
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward;
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_71_5Cycles);  
  ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_71_5Cycles);
  ADC_ChannelConfig(ADC1, ADC_Channel_2 , ADC_SampleTime_71_5Cycles);

  
  /* ADC Calibration */
  ADC_GetCalibrationFactor(ADC1);
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);     
  
  /* Wait the ADRDY falg */
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
  
  /* ADC1 regular Software Start Conv */
  //ADC_StartOfConversion(ADC1);
    DMA_Cmd(DMA1_Channel1, ENABLE);

使用特权

评论回复
10
香水城| | 2014-9-10 09:58 | 只看该作者
F0的ADC在使用之前需要校准。这个7位的校准值也是放在ADC_DR中的,它也会触发DMA请求。

可以参照F0的ADC-DMA例程,先做ADC校准、然后再设置DMA,再使能ADC的DMA。

使用特权

评论回复
11
putron09| | 2015-3-5 14:19 | 只看该作者
顶一下,非常好,原来F0的 ADC需要先校正

使用特权

评论回复
12
powder| | 2015-10-18 20:45 | 只看该作者
香水城 发表于 2014-9-10 09:58
F0的ADC在使用之前需要校准。这个7位的校准值也是放在ADC_DR中的,它也会触发DMA请求。

可以参照F0的ADC-D ...

我没有用dma,直接调用ADC1_GetVol( 1 , ADC_Channel_9),我的adc用管脚PB1,按理应该是ADC_Channel_9。实际上却在ADC_Channel_0;adc用管脚PA0,按理应该是ADC_Channel_0。实际上却在ADC_Channel_9,怎么会变了?
更郁闷的是程序修改了其它与这个调用ADC1_GetVol无关的地方,原来的adc用ADC_Channel_0,却没有跟随变化了?而adc用管脚PA0,按理应该是ADC_Channel_0。还在ADC_Channel_9。

使用特权

评论回复
13
飘落枫叶| | 2015-10-20 16:06 | 只看该作者
仔细看看ADC通道转换顺序。030不像103,103是可以随意设置,但是030通道转换顺序是固定的,要么从前到后,要么从后到前。

使用特权

评论回复
14
lydiave| | 2015-12-20 21:36 | 只看该作者
赞!

使用特权

评论回复
15
Zpc| | 2015-12-24 10:48 | 只看该作者
不错,学习。我只用了一个端口,在定时中断里定时启动采集,也可以用DMA存到数组里。

使用特权

评论回复
16
ereck| | 2015-12-28 10:54 | 只看该作者
学习了,不错

使用特权

评论回复
17
川上客simon| | 2016-7-19 14:24 | 只看该作者
本帖最后由 川上客simon 于 2016-7-19 14:27 编辑

为什么我的ADC代码是从数组中间开始的啊?数组中显示的数值依次是 ADC0,ADC5,ADC4,ADC3,ADC2,ADC1
附代码:

void ADC1_DMA_Init(void)
{
        ADC_InitTypeDef     ADC_InitStruct;
  DMA_InitTypeDef     DMA_InitStruct;
        GPIO_InitTypeDef    GPIO_InitStruct;
//        NVIC_InitTypeDef    NVIC_InitStruct;
        
        /* ADC1 DeInit */
        ADC_DeInit(ADC1);        
        
        /* Enable  GPIOA clock */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
        /* ADC1 Periph clock enable */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  
        /* DMA1 clock enable */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
        
        /* Configure PA.1  as analog input */
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1 |GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(GPIOA, &GPIO_InitStruct);         
/*      
        //DMA NVIC
        NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
*/               
        /* DMA1 Channel1 Config */
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;//ÉèÖÃÍâÉèµØÖ·
        DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)RegularConvData_Tab;//ÅäÖÃÄÚ´æÓ³ÉäµØÖ·
        DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                                
        DMA_InitStruct.DMA_BufferSize = 60;                                                                                                                                
        DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                       
        DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        
        DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;      
        DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;                                                                                       
        DMA_InitStruct.DMA_Priority = DMA_Priority_High;                                                                       
        DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                                                                                                        
        DMA_Init(DMA1_Channel1, &DMA_InitStruct);
  
        /* DMA1 Channel1 enable */
        DMA_Cmd(DMA1_Channel1, ENABLE);                                                                                                                                               
        /*Enables the specified DMAy Channelx interrupts */
//        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);                                                                                       
        /* ADC DMA request in circular mode */
        ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);                                                        
        /* Enable ADC_DMA */
        ADC_DMACmd(ADC1, ENABLE);
        
        /* Initialize ADC structure */
        ADC_StructInit(&ADC_InitStruct);
        
        /* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits  */
        ADC_InitStruct.ADC_Resolution  = ADC_Resolution_12b;
        ADC_InitStruct.ADC_ContinuousConvMode  = ENABLE;
        ADC_InitStruct.ADC_ExternalTrigConvEdge  = ADC_ExternalTrigConvEdge_None;
        ADC_InitStruct.ADC_DataAlign  = ADC_DataAlign_Right;
        ADC_InitStruct.ADC_ScanDirection  = ADC_ScanDirection_Backward;
        ADC_Init(ADC1, &ADC_InitStruct);  
   
        ADC_ChannelConfig(ADC1, ADC_Channel_0, ADC_SampleTime_55_5Cycles);
        ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_55_5Cycles);        
        ADC_ChannelConfig(ADC1, ADC_Channel_2, ADC_SampleTime_55_5Cycles);        
        ADC_ChannelConfig(ADC1, ADC_Channel_3, ADC_SampleTime_55_5Cycles);        
        ADC_ChannelConfig(ADC1, ADC_Channel_4, ADC_SampleTime_55_5Cycles);
        ADC_ChannelConfig(ADC1, ADC_Channel_5, ADC_SampleTime_55_5Cycles);     
        /* ADCУ׼ */
        ADC_GetCalibrationFactor(ADC1);
        /* Enable ADC1 */
        ADC_Cmd(ADC1, ENABLE);
      
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
        /* ADC1 regular Software Start Conv */
        ADC_StartOfConversion(ADC1);
}

使用特权

评论回复
18
598330983| | 2016-7-20 00:16 | 只看该作者
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从外设读取发送到内存

使用特权

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

本版积分规则

5

主题

30

帖子

0

粉丝