历史上的今天
返回首页

历史上的今天

今天是:2025年01月25日(星期六)

2021年01月25日 | ADC,DMA,多路,单次/连续转换

2021-01-25 来源:eefocus

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


1写在前面

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


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


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


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


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

2ADC,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

  //进行相关换算,处理...

}


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


3ADC,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;

推荐阅读

史海拾趣

启臣微(Chip)公司的发展小趣事

作为一家高新技术企业,启臣微深知绿色生产的重要性。公司采用先进的生产工艺和设备,实现了生产过程中的节能减排。同时,公司还积极参与环保公益活动,倡导绿色生活方式,为社会的可持续发展贡献了自己的力量。

意普(ESPE)公司的发展小趣事

随着工业自动化和智能化的不断发展,意普(ESPE)公司开始将光电保护技术与智能制造相结合,推出了多款智能光电保护产品。这些产品具有更高的检测精度和更快的反应速度,能够更好地保护操作人员的安全。同时,公司还积极参与工业互联网和物联网的建设,推动光电保护技术的智能化发展。

Advanced Technology Corp公司的发展小趣事

随着科技的飞速发展,ATC公司始终保持着对技术创新的热情与追求。公司不断投入研发资源,引进先进设备和技术人才,致力于开发更具创新性和实用性的电子产品。经过多年的努力,ATC公司在多个技术领域取得了重要突破,推出了一系列具有行业影响力的创新产品,赢得了市场的广泛认可。

Ceramics公司的发展小趣事

“绿色陶瓷”公司以其环保理念为核心,致力于研发和生产环保型陶瓷电子材料。该公司采用可再生资源和低能耗生产工艺,成功降低了产品对环境的影响。同时,绿色陶瓷还积极推广循环经济模式,通过回收再利用废旧陶瓷材料,实现了资源的最大化利用。这一环保理念不仅赢得了消费者的青睐,也为公司在电子行业的可持续发展奠定了坚实基础。

Cree(科瑞)公司的发展小趣事

进入21世纪,Cree在功率器件领域取得了重大突破。2004年,Cree开始大范围采用氮化镓(GaN)材料,并成功将其应用于大功率RF器件产品设计。这些GaN射频器件主要服务于美国军工领域,如“萨德”导弹防御系统,其超宽的频率覆盖和大功率射频功率技术无人能及。这一技术的成功应用,不仅提升了Cree的技术实力,也为其打开了新的市场空间。

EOZ Secme公司的发展小趣事

随着环保意识的不断提高,EOZ Secme积极响应绿色环保的号召。公司在生产过程中采用了多项环保措施,减少了对环境的污染。同时,EOZ Secme还积极参与社会公益事业,通过捐款、赞助等方式回馈社会。这些举措不仅提升了公司的社会形象,也为其赢得了更多消费者的认可和支持。

问答坊 | AI 解惑

3G时代,能否替代原有的固定宽带

3G时代,能否替代原有的固定宽带 2009年元月,中国3张3G牌照发放   电信 cdma2000  推出天翼品牌,声称测试速度已经达到3.3Mbps,年底升级到9Mbps。   联通 WCDMA   声称速度达到7.2Mbps,号称最成熟的3G制式。   ...…

查看全部问答>

我有个兄弟,三十一二了,突然问我他可以学编程搞编程吗?他没读过大学,没有任何基础,但他想拥有改变,不知道现不现实!

我有个兄弟,三十一二了,突然问我他可以学编程搞编程吗?他没读过大学,没有任何基础,但他想拥有改变,不知道现不现实! 他的担心有以下几点: 1。没有学历,就算把编程学好了,公司不一定给机会给他 2。岁数不小了,学编程能够学到怎样的程度 ...…

查看全部问答>

求助:通过单片机的控制来演奏音(不是蜂鸣器的那种)

想通过单片机里存的根据钢琴简谱的数组(又两部分组成:音符(1,2,3,4,5,6,7)和音长)输出曲子,想问一下有没有这样的芯片或是模块什么的,可以根据单片机7个io口(相当于音符1,2,3,4,5,6,7)输出的脉冲控制其发声(发1,2,3,4,5, ...…

查看全部问答>

通过按键实现直流电机的正反转和加减速!

本程序主要实现了通过按键选择电机的正转或反转,选择完后,通过up键,加快电机的转速(增大占空比),down键来降低电机的转速。本例程的扩展部分:将按键用外接的电位器来控制,类似于汽车转动方向盘,电机就转到,转动角度越大,转动的速度就越大 ...…

查看全部问答>

STR710仿真器调试问题

大家好:  我用IAR调试STR710的一个例子程序时,项目文件当Options-Debugger设置为软件仿真Simulator时编译和调试都没什么问题。当用第三方仿真器(Third-Party Driver为万利的STLINK仿真器),并进行相应的设置时出现了如下的 ...…

查看全部问答>

请教个简单的问题 关于ALTERA的DE2开发板

要用DE2开发板上面插一个无线收发芯片 进行数据接收 请问芯片的驱动程序是写C程序还是写verilog程序啊 我问了不同的人 给我不同的答案 我自己也搞不清啊 我是初学的…

查看全部问答>

提问:IAR Embedded Workbench出现的编译错误提示!

我用IAR Embedded Workbench编译器 出现错误 main.c Fatal Error[Cp001]: Copy protection check, No valid license found for this product [20] Error while running C/C++ compiler 请问是什么原因? 谢谢…

查看全部问答>

这是什么型号?

有一个芯片,SOP8,芯片上的印字:第一行是:11201A;第二行是:B17 求教哪位大师,知道这是啥型号吗?急!…

查看全部问答>