OpenEdv-开源电子网

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

求助:ADC多通道采样 DMA 出现问题

[复制链接]

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
发表于 2016-9-25 14:54:50 | 显示全部楼层 |阅读模式
1金钱
我用的是精英版F103ZET,做ADC多通道采集,发现了一个问题:就是ADC采集只有最后两个通道有效,比如,这种情况,只能采集到ADC通道0和1的电压模拟量:
[mw_shl_code=applescript,true]ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5 );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 2, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 3, ADC_SampleTime_239Cycles5  );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 5, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 6, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 7, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 8, ADC_SampleTime_239Cycles5  );[/mw_shl_code]

但是,如果我把采集的顺序倒过来,就只能采集到通道6和7了:
[mw_shl_code=applescript,true]ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5  );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5  );
[/mw_shl_code]



好像用了DMA之后,只保存了最后两次的数据,请问是为什么呢?

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 14:55:41 | 显示全部楼层
这是adc.c
[mw_shl_code=applescript,true] #include "adc.h"
#include "delay.h"
                                                                                                                                  
void  Adc_Init(void)
{        
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟


        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

        //PA1 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);       

        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;        //disable是模数转换工作在单通道模式,enable是多通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;        //disable是模数转换工作在单次转换模式,enable是多次转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 8;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   


    //ADC1的0、1、2、3四个通道
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5  );               
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5  );
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5  );


  ADC_DMACmd(ADC1, ENABLE);       //使能ADC1的DMA传输
        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
       
       
        ADC_ResetCalibration(ADC1);        //使能复位校准   
        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
       
        ADC_StartCalibration(ADC1);         //开启AD校准
        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束

        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能

}                                  
//获得ADC值
//ch:通道值 0~3


u16 Get_Adc(u8 ch)   
{
          //设置指定ADC的规则组通道,一个序列,采样时间
        ADC_RegularChannelConfig(ADC1, ch, 1 , ADC_SampleTime_239Cycles5 );        //ADC1,ADC通道,采样时间为239.5周期                                      
  
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能       
         
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
}





u16 Get_Adc_Average(u8 ch,u8 times)
{
        u32 temp_val=0;
        u8 t;
        for(t=0;t<times;t++)
        {
                temp_val+=Get_Adc(ch);
                delay_ms(5);
        }
        return temp_val/times;
}          

[/mw_shl_code]
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 14:56:51 | 显示全部楼层
看了之前有人发过类似的帖子,按照他们所说的设置过,感觉没什么用...
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 14:57:59 | 显示全部楼层
这是dma.c
[mw_shl_code=applescript,true]#include "dma.h"
#include "usart.h"

//DMA_Channel1-->ADC1   
//cndtr对应所开的信道数目         
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{        DMA_InitTypeDef DMA_InitStructure;   
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr =  cpar;  //DMA外设ADC基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //内存作为数据传输的目的地
    DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的数据单元大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //循环工作模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
}
[/mw_shl_code]
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 15:03:59 | 显示全部楼层
我用ADC采集模拟量来控制PWM的输出
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 15:11:33 | 显示全部楼层
之前做ADC单通道采集是没问题的,但是一加入DMA就不行了,难道是思路不对吗?
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 16:36:48 | 显示全部楼层
我改为两个通道,也只有一个通道输出了PWM波
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 17:08:36 | 显示全部楼层
是不是配置有问题?
回复

使用道具 举报

11

主题

48

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
339
金钱
339
注册时间
2016-3-31
在线时间
41 小时
发表于 2016-9-25 20:56:00 | 显示全部楼层
// 使能 DMA 通道
        DMA_Cmd(DMA1_Channel1 , ENABLE);

DMA没使能吧???
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 21:31:47 | 显示全部楼层
yzz 发表于 2016-9-25 20:56
// 使能 DMA 通道
        DMA_Cmd(DMA1_Channel1 , ENABLE);

这个在主函数里使能了
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-25 21:59:14 | 显示全部楼层
有没有可能是因为多个通道的数据都放在缓存区里,但是后读取的数据取代了先读取的数据的位置?或者是因为缓存区大小不够?
回复

使用道具 举报

5

主题

40

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
229
金钱
229
注册时间
2016-7-30
在线时间
82 小时
发表于 2016-9-26 09:03:00 | 显示全部楼层
主函数也贴出来看看怎么调用的
回复

使用道具 举报

9

主题

63

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-9-20
在线时间
31 小时
 楼主| 发表于 2016-9-26 11:34:27 | 显示全部楼层
是因为adc.c里面这一段函数的原因吗?
[mw_shl_code=applescript,true]u16 Get_Adc(u8 ch)  
{
    //设置指定ADC的规则组通道,一个序列,采样时间
    ADC_RegularChannelConfig(ADC1, ch, 1 , ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期                  
   
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能   
      
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果
}[/mw_shl_code]
回复

使用道具 举报

1

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2013-4-8
在线时间
8 小时
发表于 2016-10-22 01:40:11 | 显示全部楼层
DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的数据单元大小,check it
回复

使用道具 举报

4

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
104
金钱
104
注册时间
2016-3-17
在线时间
19 小时
发表于 2016-10-29 14:37:55 | 显示全部楼层
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
{
  uint32_t tmpreg1 = 0, tmpreg2 = 0;
  /* Check the parameters */
  assert_param(IS_ADC_ALL_PERIPH(ADCx));
  assert_param(IS_ADC_CHANNEL(ADC_Channel));
  assert_param(IS_ADC_REGULAR_RANK(Rank));///////////////////#define IS_ADC_REGULAR_RANK(RANK) (((RANK) >= 0x1) && ((RANK) <= 0x10))
  assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime));
回复

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
52
金钱
52
注册时间
2016-5-14
在线时间
13 小时
发表于 2016-11-1 23:45:04 | 显示全部楼层
airlovelj 发表于 2016-9-25 15:03
我用ADC采集模拟量来控制PWM的输出

请问一下你用adc采集什么的模拟量来控制pwm输出么
qq  719698753 细聊
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-2 10:17:34 | 显示全部楼层
问题还是出在你的内存缓冲区那里,也就是说比如你开辟了一个缓冲区char data_cache[8*10];//8个通道,可放10次的采集数据。
这个缓冲区大小在DMA配置时要写对。
活到老,学到老。
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-2 10:20:43 | 显示全部楼层
上面说错了,因为你在DMA配置数据宽度为16bit,所以声明缓冲区时数据类型应为uint16_t data_cache[8*10];
如果只保存采集一次的数据,可申明为:
uint16_t data_cache[8];
活到老,学到老。
回复

使用道具 举报

1

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2016-8-15
在线时间
13 小时
发表于 2016-11-11 11:00:20 | 显示全部楼层
kingnike 发表于 2016-11-2 10:17
问题还是出在你的内存缓冲区那里,也就是说比如你开辟了一个缓冲区char data_cache[8*10];//8个通道,可放1 ...

请问 我在用ADC1的五个通道采集时,使用DMA传输到我设置的一个数组里面,在主函数发送时结果全是0(我输入的是直流电压3.3V) 这个问题是什么原因呢
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-11 11:20:31 | 显示全部楼层
wys995624 发表于 2016-11-11 11:00
请问 我在用ADC1的五个通道采集时,使用DMA传输到我设置的一个数组里面,在主函数发送时结果全是0(我输 ...

这个要分几个阶段来分布查找原因。
1、你的外围VREF是否稳定供电。
2、你的ADC引脚电压是否和外设电压对得上。
3、ADC采集功能是否配置正确(可先不启动DMA来看ADC是否能正确采集)。
4、DMA是否配置正确。(上面三步都正确,几乎可确定就是DMA的问题了)。
活到老,学到老。
回复

使用道具 举报

1

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2016-8-15
在线时间
13 小时
发表于 2016-11-11 11:28:06 | 显示全部楼层
kingnike 发表于 2016-11-11 11:20
这个要分几个阶段来分布查找原因。
1、你的外围VREF是否稳定供电。
2、你的ADC引脚电压是否和外设电压 ...

谢谢您  第三步我试过 ADC可正常采集3.3V 采集出来的值是3.29V,所以第一步的问题就不存在了  第四步我反复看过 自认为没出问题 也借鉴了许多例程代码  第二步是什么意思呢 能再解释一下吗 我没懂
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-11 11:34:54 | 显示全部楼层
wys995624 发表于 2016-11-11 11:28
谢谢您  第三步我试过 ADC可正常采集3.3V 采集出来的值是3.29V,所以第一步的问题就不存在了  第四步我反 ...

第二步主要是看你的ADC引脚电压是不是你要采集的那个电压,说白了就是检查你的外围电路。

如果还是不行,那就检查你的接收数组,用串口打印出来看一下。是否DMA传输过来结果。
活到老,学到老。
回复

使用道具 举报

1

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2016-8-15
在线时间
13 小时
发表于 2016-11-11 11:50:51 | 显示全部楼层
kingnike 发表于 2016-11-11 11:34
第二步主要是看你的ADC引脚电压是不是你要采集的那个电压,说白了就是检查你的外围电路。

如果还是不 ...

好的 我先检查一下引脚电压问题 如果没问题那么就是DMA那里出现问题了 谢谢您宝贵的建议
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-11 13:41:07 | 显示全部楼层
wys995624 发表于 2016-11-11 11:50
好的 我先检查一下引脚电压问题 如果没问题那么就是DMA那里出现问题了 谢谢您宝贵的建议

不用客气,大家共同学习进步。
活到老,学到老。
回复

使用道具 举报

1

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2016-8-15
在线时间
13 小时
发表于 2016-11-11 20:12:02 | 显示全部楼层
kingnike 发表于 2016-11-11 13:41
不用客气,大家共同学习进步。

还有一个问题就是 DMA是否会一直传输ADC_DR中的值 当ADC_DR的值没变时,DMA也会传输吗
回复

使用道具 举报

4

主题

290

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1130
金钱
1130
注册时间
2015-8-4
在线时间
107 小时
发表于 2016-11-14 09:42:29 | 显示全部楼层
wys995624 发表于 2016-11-11 20:12
还有一个问题就是 DMA是否会一直传输ADC_DR中的值 当ADC_DR的值没变时,DMA也会传输吗

ADC采样完成一次,触发一次DMA传输。应该是这样。跟ADC_DR的值变不变没关系。
活到老,学到老。
回复

使用道具 举报

1

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2016-8-15
在线时间
13 小时
发表于 2016-11-15 20:25:42 | 显示全部楼层
kingnike 发表于 2016-11-14 09:42
ADC采样完成一次,触发一次DMA传输。应该是这样。跟ADC_DR的值变不变没关系。

好的 谢谢你
回复

使用道具 举报

2

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
145
金钱
145
注册时间
2016-10-13
在线时间
39 小时
发表于 2016-11-16 09:55:14 | 显示全部楼层
楼主问题解决了吗,我也遇到同样的问题,用DMA采集出来的都是0.
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-25 06:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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