0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ADC,DMA,多路,单次/连续转换 (标准外设库)

黄工的嵌入式技术圈 来源:黄工的嵌入式技术圈 作者:黄工的嵌入式技术 2020-03-04 11:26 次阅读

今天回答一个朋友的问题吧,ADC如何使用DMA采集多通道模拟电压。

1写在前面

这个问题其实之前写过一些相关文章,原理我之前也有相关描述。如果想要彻底弄明白其原理,建议阅读《参考手册》、结合标准外设库来理解。

现在很多人习惯使用STM32CubeMX来直接生成初始化代码,如果没有掌握STM32CubeMX、HAL库,使用STM32CubeMX生成的代码,或许就不能满足你的应用。

同时,STM32CubeMX生成的代码,想要根据代码进一步了解其原理,其实很难

ADC转换一些基础原理,我这里就不过多描述了,请直接看下面标准外设库源码、及后面给的注释。

下面写2点:ADC软件单次触发转换,和连续转换。

2

ADC,DMA,单次触发转换

这里以ADC,使用DMA,通过软件单次触发转换为例。主要需注意几个相关参数即可。

1.GPIO配置

2.DMA配置

3.ADC配置

4.ADC单次触发转换

5.源代码

/* 静态变量 ------------------------------------------------------------------*/static volatile uint16_t sADC_Buf[3];/************************************************函数名称 : ADC_GPIO_Configuration功 能 : ADC引脚配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; /* 使能时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure);}/************************************************函数名称 : ADC_DMA_Configuration功 能 : ADC DMA配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; /* 使能时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]); //内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //传输方向:外设 -> 内存 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;//数据宽度 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //正常模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure);}/************************************************函数名称 : ADC_Configuration功 能 : ADC参数配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Configuration(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 使能时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* ADC配置 */ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; //浏览模式(多通道) ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转化模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐 ADC_InitStructure.ADC_NbrOfConversion = 3; //转换通道数 ADC_Init(ADC1, &ADC_InitStructure); /* 通道配置 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); //使能ADC的DMA功能 ADC_Cmd(ADC1, ENABLE); //使能ADC}/************************************************函数名称 : ADC_Initializes功 能 : ADC初始化参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Initializes(void){ ADC_GPIO_Configuration(); ADC_DMA_Configuration(); ADC_Configuration();}/************************************************函数名称 : ADC_Get功 能 : 转换参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Get(void){ DMA_Cmd(DMA2_Stream0, DISABLE); //关闭DMA //内存地址 DMA_MemoryTargetConfig(DMA2_Stream0, (uint32_t)sADC_Buf, DMA_Memory_0); DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0); //清除标志位 DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA ADC_SoftwareStartConv(ADC1); //启动转换 while(RESET == DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0)); //等待转换完成 //得到3条通道转换结果:sADC_Buf //进行相关换算,处理...}

提示:以上源代码只为方便学习和理解,请结合实际应用修改、或增减代码。

3

ADC,DMA,连续转换

我这里写的连续,是ADC连续转换,同时,DMA循环存储。大部分配置和上面差不多,这种方式也用的比较多,写给大家。

1.DMA配置

2.ADC配置

3.源代码

/* 静态变量 ------------------------------------------------------------------*/static volatile uint16_t sADC_Buf[3];/************************************************函数名称 : ADC_GPIO_Configuration功 能 : ADC引脚配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; /* 使能时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure);}/************************************************函数名称 : ADC_DMA_Configuration功 能 : ADC DMA配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; /* 使能时钟 */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));//外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&sADC_Buf[0]); //内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //传输方向:外设 -> 内存 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;//数据宽度 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure);}/************************************************函数名称 : ADC_Configuration功 能 : ADC参数配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Configuration(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 使能时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); /* ADC配置 */ ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; //浏览模式(多通道) ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转化模式 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐 ADC_InitStructure.ADC_NbrOfConversion = 3; //转换通道数 ADC_Init(ADC1, &ADC_InitStructure); /* 通道配置 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_3Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); //使能ADC的DMA功能 ADC_Cmd(ADC1, ENABLE); //使能ADC ADC_SoftwareStartConv(ADC1); //启动转换}/************************************************函数名称 : ADC_Initializes功 能 : ADC初始化参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Initializes(void){ ADC_GPIO_Configuration(); ADC_DMA_Configuration(); ADC_Configuration();}/************************************************函数名称 : ADC_Get功 能 : 转换参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/void ADC_Get(void){ //得到3条通道转换结果:sADC_Buf //进行相关换算,处理...}

这种方式比较简单,直接去读取转换结果就行。实际应用需要滤波,求平均之类的操作。

提示:以上源代码只为方便学习和理解,请结合实际应用修改、或增减代码。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • adc
    adc
    +关注

    关注

    95

    文章

    5652

    浏览量

    539483
  • 模拟电压
    +关注

    关注

    6

    文章

    58

    浏览量

    18150
  • GPIO
    +关注

    关注

    16

    文章

    1135

    浏览量

    50578
  • stm32cubemx
    +关注

    关注

    5

    文章

    260

    浏览量

    14448
收藏 人收藏

    评论

    相关推荐

    求助,关于STM8L051Halt低功耗与DMA问题求解

    如题,最近在做一个项目,主要需要实现的是多路ADC采集电压,通过DMA读取到RAM。不加低功耗模式(halt)的时候是正常的,但是一旦加上Halt模式之后,ADC
    发表于 04-26 06:33

    STM32 ADC+DMA多通道转换数据错位的原因?怎么解决?

    ]​,即为ADC采样的值。 2、​HAL配置:​ ​扫描模式使能,连续转换模式使能,DMA连续
    发表于 04-10 07:24

    stm32F103中ADC多通道转换使用DMA,串口调试助手没有数据传输的原因?

    (ADC_GetCalibrationStatus(ADC1) == SET);//获取指定ADC的校准状态 //使能指定的ADC1的软件转换
    发表于 04-08 07:17

    STM32F1用AD采样和AD+DMA连续采样的结果有偏差是怎么回事?

    请教大家一个问题, 硬件是一样的,采样电阻接地。 负载不工作:AD采样时,可以采样到0x 00;AD+DMA连续采样,采样到 0x 0F到0x 12抬高了采样值,负载开启时:AD
    发表于 03-29 06:17

    STM32F205利用DMA实现多通道ADC采样,但是每启动一转换才能更新一结果是为什么?

    1、ADC配置采样12个规则通道,采用、扫描模式,允许DMA,配置每次转换结束都有DMA r
    发表于 03-27 06:37

    STM32 ADC+DMA多路采集,使用DMA时,是不是要额外加上4倍的DMA传输时间?

    4通道采集时,按1-2-3-4-1顺序转换,一路通道的转换时间是(采样时间+12.5)周期,还是4 *(采样时间+12.5)周期?使用DMA时,是不是要额外加上4倍的
    发表于 03-26 07:44

    M252LG6AE通过DMA采集ADC多路信号,会出现采样电压偏低的现象怎么解决?

    现象:目前项目采用M252LG6AE芯片,需要通过DMA采集ADC多路信号,因为没有找到如何设置芯片设置连续DMA传输的方法,所以使用的是通
    发表于 01-17 07:37

    AD7790正常工作模式不分频转换的时间是多少?

    是多少?转换的电压是哪个时刻的电压,时启动时采集到的电压,还是转换过程中电压的均值,还是其他?这部分不太了解希望能帮忙讲清转换的时间与采
    发表于 12-11 06:39

    ADC通过SPI读取转换结果时一只能读取一个转换结果,不能连续读取吗?

    我选了几款带SPI接口的ADC(如AD7680,AD7982等),看SPI时序时,发现在CS/CNV拉低时,一只能读取一个转换结果,而不能连续读取,要读取下一个时必须得再次拉低CS/
    发表于 12-05 08:15

    请问标准外设和HAL的区别是什么?

    标准外设和HAL的区别是什么?
    发表于 10-23 08:01

    MSP432的DMA乒乓模式怎么使用来连续传输ADC采集数据?

    就是用MSP432P401R的DMA乒乓模式怎么连续传输ADC采集的数据。 下面是程序,不能实现功能,有些错误,请大神指教。 #include \"u_dma.h\"
    发表于 10-07 09:05

    STM32U5系列片内ADC1和ADC4实现过程(下)

    现在对ADC4基于DMA链表模式做演示,其实就一个节点。 选择ADC4的4个内部信号通道,扫描模式,连续转换
    的头像 发表于 07-30 09:30 804次阅读
    STM32U5系列片内<b class='flag-5'>ADC</b>1和<b class='flag-5'>ADC</b>4实现过程(下)

    STM32U5系列片内ADC1和ADC4实现过程(上)

    请求模式做演示。 随意选择ADC1的4个通道,扫描模式,连续转换DMA传输转换结果并令DMA
    的头像 发表于 07-30 09:27 697次阅读
    STM32U5系列片内<b class='flag-5'>ADC</b>1和<b class='flag-5'>ADC</b>4实现过程(上)

    STM32U5 ADC+DMA配置演示

    随意选择ADC1的4个通道,扫描模式,连续转换DMA传输转换结果并令DMA工作在
    的头像 发表于 07-29 16:19 855次阅读
    STM32U5 <b class='flag-5'>ADC+DMA</b>配置演示

    stm32g030多路adc DMA采集程序

    stm32g030_多路adc_DMA采集程序
    发表于 06-19 09:43 24次下载