你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

新手求助,多重ADC采集单通道通过DMA传输到内存数组中的...

[复制链接]
lyl5530330 提问时间:2018-5-24 22:43 /
本帖最后由 lyl5530330 于 2018-5-24 22:45 编辑

各位大神,小弟初学stm32,现在在项目中遇到一个问题,比如说我采集一个信号,只有一个通道,通过ADC123多重采样通过DMA传输到数组中,再通过串口输出可见,我采的是一个2V的直流电平,采到的图在附件,由图可以看出采到的数据有问题,大神能帮我看下程序嘛

以下是main函数:
  1. #define NUM 100
  2. int main(void)
  3. {
  4.         u16 adcx1,adcx2,adcx3;
  5.         u8 i,t,z=0;
  6.         u32 adc_value[NUM];
  7.         delay_init(168);
  8.         uart_init(115200);
  9.         LED_Init();
  10.         MYDMA_DMA_DIR_PeripheralToMemoryConfig(DMA2_Stream0,DMA_Channel_0,(u32)&ADC->CDR,(u32)adc_value,NUM);
  11.         MYADC_configure();

  12.         
  13. while(1)        
  14. {
  15.         
  16.         for(i=0;i<NUM;i++)
  17.                 {                        
  18.                         adcx1=adc_value[i]&0xffff0000>>16;
  19.                         USART_SendData(USART1,(adcx1&0xff00)>>8);
  20.                         while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
  21.                         USART_SendData(USART1,adcx1&0xff);
  22.                         while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
  23.                         
  24.                         adcx2=adc_value[i]&0xffff;
  25.                         USART_SendData(USART1,(adcx2&0xff00)>>8);
  26.                         while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
  27.                         USART_SendData(USART1,adcx2&0xff);
  28.                         while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
  29.          }
  30.         
  31.                 delay_ms(2000);
  32.           LED0=!LED0;
  33. }
  34.         
  35. }
复制代码
以下是adc配置函数
  1. #include "adc.h"
  2. #include "sys.h"

  3. void MYADC_configure()//从adc中
  4. {
  5.        
  6.         GPIO_InitTypeDef GPIO_InitStructure;
  7.         ADC_CommonInitTypeDef ADC_CommonInitStructure;
  8.         ADC_InitTypeDef ADC_InitStructure;
  9.        
  10.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3|RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2, ENABLE);
  12.        
  13.         GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
  14.         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;
  15.         GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL ;
  16.         GPIO_Init(GPIOA,&GPIO_InitStructure);
  17.        
  18.        
  19.         //复位ADC
  20.         ADC_DeInit();
  21.         //配置通用寄存器ADC_CCR
  22.         ADC_CommonInitStructure.ADC_Mode=ADC_TripleMode_Interl;//三重交替模式
  23.         ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;
  24.         ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_2;//DMA模式2
  25.         ADC_CommonInitStructure.ADC_Prescaler=ADC_Prescaler_Div4;//84/4=21M
  26.         ADC_CommonInit(&ADC_CommonInitStructure);
  27.         //配置ADC3
  28.         ADC_InitStructure.ADC_Resolution=ADC_Resolution_12b;//分辨率12位
  29.         ADC_InitStructure.ADC_ScanConvMode=DISABLE;//关闭扫描模式
  30.         ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//开启连续转换 CR2
  31.         ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;//不采用边沿触发
  32.         ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//右对齐
  33.         ADC_InitStructure.ADC_NbrOfConversion=1;//采样通道1个
  34.         ADC_Init(ADC1,&ADC_InitStructure);
  35.        
  36.         ADC_Init(ADC2,&ADC_InitStructure);

  37.         ADC_Init(ADC3,&ADC_InitStructure);
  38.        
  39.         //始能ADC       
  40.         ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3
  41.         ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3
  42.         ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3
  43.        
  44.         ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
  45.        
  46.         ADC_Cmd(ADC1, ENABLE);
  47.         ADC_Cmd(ADC2, ENABLE);
  48.         ADC_Cmd(ADC3, ENABLE);

  49.        
  50.         ADC_SoftwareStartConv(ADC1);
  51.         ADC_SoftwareStartConv(ADC2);
  52.         ADC_SoftwareStartConv(ADC3);
  53.        

  54.        
  55. }
复制代码
  1. <span style="background-color: rgb(255, 255, 255);">
  2. </span>
复制代码

复制代码
以上就是代码部分

捕获.PNG
收藏 1 评论12 发布时间:2018-5-24 22:43

举报

12个回答
lyl5530330 回答时间:2018-5-24 22:46:32
DMA的不知道为啥没显示,我补充一下:
  1. #include "dma.h"
  2. #include "sys.h"

  3. void MYDMA_DMA_DIR_PeripheralToMemoryConfig(DMA_Stream_TypeDef *DMA_Streamx,u32 chanlx,u32 par,u32 memory,u16 ndtr)//(数据流,通道,外设基地址,存储器基地址,传输量,不管是多少位的,传输量只是数据的个数,这里设置为数组的长度)
  4. {
  5.                 DMA_InitTypeDef  DMA_InitStructure;
  6.        
  7.         if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
  8.         {
  9.           RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
  10.                
  11.         }else
  12.         {
  13.           RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
  14.         }
  15.   DMA_DeInit(DMA_Streamx);
  16.         while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置
  17.                
  18.                  /* 配置 DMA Stream */
  19.   DMA_InitStructure.DMA_Channel = chanlx;  //通道选择
  20.   DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址,S0PAR
  21.   DMA_InitStructure.DMA_Memory0BaseAddr = memory;//DMA 存储器地址 S0M0AR
  22.   DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralToMemory ;//外设到存储器
  23.   DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量 ,NDTR
  24.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式,S0CR
  25.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式,S0CR
  26.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  27.   DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
  28.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 循环模式,S0CR
  29.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级,S0CR
  30.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  31.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  32.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
  33.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
  34.   DMA_Init(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
  35.         DMA_Cmd(DMA_Streamx, ENABLE);
  36.          
  37. }



复制代码

wenyangzeng 回答时间:2018-5-25 07:22:49
本帖最后由 wenyangzeng 于 2018-5-25 16:25 编辑

1、楼主在主循环里不停地发送数据,如果ADC未转换结束,则可能会发送错误的数据。
2、只使用1个ADC,为何要打开3个ADC(ADC1、ADC2、ADC3)且使能三重交替模式?
3、DMA配置貌似未配置完整。ST官方代码可以参考:
ADC_DMA.rar (15.8 KB, 下载次数: 24)

评分

参与人数 1蝴蝶豆 +4 收起 理由
zero99 + 4

查看全部评分

MrJiu 回答时间:2018-5-25 09:48:28
直接使用官方的hal库,然后用cube配置岂不是更加好

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

wolfgang 回答时间:2018-5-25 10:03:35
1、ADC参考电压没对导致结果偏大
2、先不要测变化量,先要测个归零量,稳定量,避免因采样的方式带来的误差
3、直流电平最好选择电池,开关电源有波纹,并不是想象的那么平;
4、幅度大于波纹,看看是否采样过快或过慢,造成数据不准
5、3个ADC都送一个DMA, 但DAM设置用的是 DMA_PeripheralInc = DMA_PeripheralInc_Disable

这与 “如果DMA选用的通道(CHx)有多个外设连接,需要使用外设递增模式:DMA_PeripheralInc_Enable;” 不同。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

西边的云彩 回答时间:2018-5-25 10:38:54
正好需要,感谢
lyl5530330 回答时间:2018-5-25 14:15:10
wenyangzeng 发表于 2018-5-25 07:22
1、楼主在主循环里不停地发送数据,如果ADC未转换结束,则可能会发送错误的数据。
2、只使用1个ADC,为何要 ...

谢谢,您发的这个附件我下载下来是空的。。。。
我以为三个ADC都要打开转换所以就打开三个ADC软件转换了。
那这个循环里面该怎么写呢?有没有一个函数是开启/关闭从ADC-CDR寄存器的DMA传输的呢,就像ADC_DMACmd(ADC3,DISABLE);在使用串口传输的时候就不让DMA取数了
lyl5530330 回答时间:2018-5-25 14:15:36
MrJiu 发表于 2018-5-25 09:48
直接使用官方的hal库,然后用cube配置岂不是更加好

怎么用啊。。新手表示用不来
lyl5530330 回答时间:2018-5-25 14:16:20
wolfgang2015 发表于 2018-5-25 10:03
1、ADC参考电压没对导致结果偏大
2、先不要测变化量,先要测个归零量,稳定量,避免因采样的方式带来的误差 ...

嗯嗯,我改用一下外设递增的模式试一下
lyl5530330 回答时间:2018-5-25 14:17:20
本帖最后由 lyl5530330 于 2018-5-25 14:19 编辑
wolfgang2015 发表于 2018-5-25 10:03
1、ADC参考电压没对导致结果偏大
2、先不要测变化量,先要测个归零量,稳定量,避免因采样的方式带来的误差 ...

但是三个ADC转换的数据都是存在ADC-CDR寄存器中的呀,这个也需要递增吗,如果改成外设递增的话那么传出来的数就全是0了
wolfgang 回答时间:2018-5-25 14:30:58
"
ADC_InitStructure.ADC_NbrOfConversion=1;//采样通道1个
"

这个设置与下面的配置有冲突把,如果是一个采样通道,相关DMA内容也要调整。
简单的方法你把ADC、DMA的内容Debug 出来,自然就明了



        ADC_Init(ADC1,&ADC_InitStructure);
        
        ADC_Init(ADC2,&ADC_InitStructure);

        ADC_Init(ADC3,&ADC_InitStructure);
        
        //始能ADC        
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3
        ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3
        ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 1, ADC_SampleTime_480Cycles ); //配置通道优先级 SMPR2,SQR3

lyl5530330 回答时间:2018-5-25 14:34:59
wolfgang2015 发表于 2018-5-25 14:30
"
ADC_InitStructure.ADC_NbrOfConversion=1;//采样通道1个
"

什么意思呀,就只有一个通道的嘛
wenyangzeng 回答时间:2018-5-25 16:21:21
本帖最后由 wenyangzeng 于 2018-5-25 16:24 编辑
lyl5530330 发表于 2018-5-25 14:15
谢谢,您发的这个附件我下载下来是空的。。。。
我以为三个ADC都要打开转换所以就打开三个ADC软件转换了 ...

楼主应该在DMA中断里设置一个标志位,主循环检测到标志位后才发送数据并清标志位。
演示代码在ST官方资料库里很多的。
ADC_DMA.rar (15.8 KB, 下载次数: 7)

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版