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

今天回答一个朋友的问题吧,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 //进行相关换算,处理...}
这种方式比较简单,直接去读取转换结果就行。实际应用需要滤波,求平均之类的操作。
提示:以上源代码只为方便学习和理解,请结合实际应用修改、或增减代码。

直播精彩回顾(四)| 虹科Flow——数据管道的可观察性解决方案
iPhone8最新消息:这是iPhone8的最靠谱渲染图
简单的恒流源电路图分析
首个“液滴激光器”有助于制造更便宜的光纤通信设备
如何重新定义数据保护的安全关
ADC,DMA,多路,单次/连续转换 (标准外设库)
便携式红外热像技术在建筑物日常维护中的应用
雪佛兰沃兰体验:48V混动系统加持 智能化升级
京东配送机器人完成首单配送,机器人送货真的靠谱吗?
EMI EMS和EMC之间有什么区别?
华宇电子亮相2022世界集成电路大会
华为mate9和p9的区别,16nm工艺处理器给力升级但mate9曲屏版或跳票
C语言零基础项目:生命游戏!详细思路+源码分享
基于PLC的机器人伺服运动控制系统设计详解
用MDaemon搭建邮件服务器-设置篇
松下进一步增强加码动力电池业务的决心
谷歌发布第三季度财报,总营收461.73亿美元
华为 P20在上海发布 还有全球首款全面屏笔记本
怎么应对刘海屏机型的海报设计
相控阵雷达性能的基石:宽禁带半导体