stm32AD单通道与多通道转换(DMA)

2024-06-04 18:32

本文主要是介绍stm32AD单通道与多通道转换(DMA),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第三章AD转换

本章的内容分两部分,第一是AD的单通道转换,第二是AD的多通道转换。首先先将单通道转换。

STM32中自带的AD最大的转换频率是14MHZ,共有16个转换通道,每个转

ADC123_IN10表明PC0管脚可以作为AD1,AD2,AD3的第10通道。

下面我们将PC0配置成AD1的通道10为例进行讲解。

3.1首先我们应将PC0设置成模拟输入:

#include "adc.h"

/*为何定义ADC1_DR_Address 为((u32)0x40012400+0x4c)

,因为存放AD转换结果的寄存器的地址就是0x4001244c*/

#define ADC1_DR_Address ((u32)0x40012400+0x4c)

/*定义变量ADC_ConvertedValue,放AD1通道10转换的数据*/

__IO uint16_t ADC_ConvertedValue;

static void ADC1_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable ADC1 and GPIOC clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1

RCC_APB2Periph_GPIOC,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

|

3.2设置完端口后下一步当然是对AD进行初始化:

这里需要补充一个知识点DMA,DMA就相当与CPU的一个秘书,他的作用就是帮CPU减轻负担的。说的再具体点就是帮CPU来转移数据的。我们都知道,AD每次转换结束后会将转换的结果放到一个固定的寄存器里,以往我们如果想将该寄存器中的值赋给某一变量时会用到赋值语句,如果不用DMA,则赋值语句便要CPU来完成,CPU本来就要忙着处理其他事情,现在还要来解决赋值语句这么简单的问题,肯到会蛋疼。所以需要DMA这个秘书来帮他解决这个问题。由于DMA只是个秘书,所以比较笨,你只有把任务交代清楚了她才能很好的完成任务。那么怎样来给DMA吩咐任务呢,聪明的人肯定想到了,那当然是“DMA_Init(DMA1_Channel1, &DMA_InitStructure)”这个函数啦。下面就来一步步的来给DMA交代任务。

/* 函数名:ADC1_Mode_Config

* 描述 :配置ADC1的工作模式为MDA模式

* 输入 : 无

* 输出 :无

* 调用 :内部调用

*/

static void ADC1_Mode_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

ADC_InitTypeDef ADC_InitStructure;

/* 将与DMA有关的寄存器设我初始值 */

DMA_DeInit(DMA1_Channel1);

/*定义DMA外设基地址, 这里的ADC1_DR_Address 是用户自己定义的,即为存放转换结果的寄存器 ,他的作用就是告诉DMA取数就到ADC1_DR_Address 这里来取。*/

DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address;

/*定义内存基地址,即告诉DMA要将从AD中取来的数放到ADC_ConvertedValue中 */

DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue;

/*定义AD外设作为数据传输的来源,即告诉DMA是将AD中的数据取出放到内存中,不能反过来*/

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

/*指定DMA通道的DMA缓存的大小,即告诉DMA开辟几个内存空间,由于我们只取通道10的AD数据所以只需开辟一个内存空间*/

DMA_InitStructure.DMA_BufferSize = 1;

/*设定寄存器地址固定,即告诉DMA,只从固定的一个地方取数*/

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

/*设定内存地址固定,即每次DMA,,只将数搬到固定的内存中*/

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

/*设定外设数据宽度,即告诉DMA要取的数的大小*/

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

/*设定内存的的宽度*/

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

/*设定DMA工作再循环缓存模式,即告诉DMA要不停的搬运,不能偷懒*/ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

/*设定DMA选定的通道软件优先级*/

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

/* Enable DMA channel1,CPU有好几个DMA秘书,现在只用 DMA1_Channel1

这个秘书*/

DMA_Cmd(DMA1_Channel1, ENABLE);

/*设置ADC工作在独立模式*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

/*规定AD转换工作在单次模式,即对一个通道采样*/

ADC_InitStructure.ADC_ScanConvMode = DISABLE ;

/*设定AD转化在连续模式*/

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

/*不使用外部促发转换*/

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; /*采集的数据在寄存器中以右对齐的方式存放*/

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

/*设定要转换的AD通道数目*/

ADC_InitStructure.ADC_NbrOfChannel = 1;

ADC_Init(ADC1, &ADC_InitStructure);

/*配置ADC时钟,为PCLK2的8分频,即9MHz*/

RCC_ADCCLKConfig(RCC_PCLK2_Div8);

/*配置ADC1的通道11为55.5个采样周期 */

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */

ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

/*复位校准寄存器 */

ADC_ResetCalibration(ADC1);

/*等待校准寄存器复位完成 */

while(ADC_GetResetCalibrationStatus(ADC1));

/* ADC校准 */

ADC_StartCalibration(ADC1);

/* 等待校准完成*/

while(ADC_GetCalibrationStatus(ADC1));

/* 由于没有采用外部触发,所以使用软件触发ADC转换 */

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

配置完以上的程序,那么AD每转换一次,DMA都会将转换结果搬到变量

ADC_ConvertedValue中,而不需用每次都用赋值语句来取值AD转换的值。

第二部分:AD多路采样

#include "adc.h"

#define ADC1_DR_Address ((u32)0x40012400+0x4c)

/*定义数组变量ADC_ConvertedValue[2],分别放AD1通道10和11转换的数据*/

__IO uint16_t ADC_ConvertedValue[2];

/*

* 函数名:ADC1_GPIO_Config

* 描述 :使能ADC1和DMA1的时钟,设置PC0,PC1为模拟输入

* 输入 : 无

* 输出 :无

* 调用 :内部调用

*/

static void ADC1_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable DMA clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/* Enable ADC1 and GPIOC clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

/* 函数名:ADC1_Mode_Config

* 描述 :配置ADC1的工作模式为MDA模式

* 输入 : 无

* 输出 :无

* 调用 :内部调用

*/

static void ADC1_Mode_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

ADC_InitTypeDef ADC_InitStructure;

/* DMA channel1 configuration */

DMA_DeInit(DMA1_Channel1);

/*定义DMA外设基地址,即为存放转换结果的寄存器*/

DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address; /*定义内存基地址*/

DMA_InitStructure.DMA_MemoryBaseAddr

=(u32)&ADC_ConvertedValue;

/*定义AD外设作为数据传输的来源*/

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

/*指定DMA通道的DMA缓存的大小,即需要开辟几个内存空间,本实验有两个转换通道,所以开辟两个*/

DMA_InitStructure.DMA_BufferSize = 2;

/*设定寄存器地址固定*/

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /*设定内存地址递加,即每次DMA都是将该外设寄存器中的值传到两个内存空间中*/

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /*设定外设数据宽度*/

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

/*设定内存的的宽度*/

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

/*设定DMA工作再循环缓存模式*/

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

/*设定DMA选定的通道软件优先级*/

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

/* Enable DMA channel1 */

DMA_Cmd(DMA1_Channel1, ENABLE);

/*设置ADC工作在独立模式*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

/*规定AD转换工作在扫描模式,即对多个通道采样*/ ADC_InitStructure.ADC_ScanConvMode = ENABLE ;

/*设定AD转化在连续模式*/

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

/*不使用外部促发转换*/

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

/*采集的数据在寄存器中以右对齐的方式存放*/

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

/*设定要转换的AD通道数目*/

ADC_InitStructure.ADC_NbrOfChannel = 2;

ADC_Init(ADC1, &ADC_InitStructure);

/*配置ADC时钟,为PCLK2的8分频,即9MHz*/

RCC_ADCCLKConfig(RCC_PCLK2_Div8);

/*配置ADC1的通道10和11的转换先后顺序以及采样时间为为55.5个采样周期 */

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */

ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

/*复位校准寄存器 */

ADC_ResetCalibration(ADC1);

/*等待校准寄存器复位完成 */

while(ADC_GetResetCalibrationStatus(ADC1));

/* ADC校准 */

ADC_StartCalibration(ADC1);

/* 等待校准完成*/

while(ADC_GetCalibrationStatus(ADC1));

/* 由于没有采用外部触发,所以使用软件触发ADC转换 */

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

!!!!!单通道采样与多通道采样的不同点都在

第二段程序中用红色标出来了,注意比较。

总结:DMA就是一个无私奉献的搬运工,想将外设寄存器中的值放入内存中原本需要CPU来完成,现在DMA来帮CPU完成,这在一定程度上解放了CPU.




这篇关于stm32AD单通道与多通道转换(DMA)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1030783

相关文章

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

C语言中的数据类型强制转换

《C语言中的数据类型强制转换》:本文主要介绍C语言中的数据类型强制转换方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C语言数据类型强制转换自动转换强制转换类型总结C语言数据类型强制转换强制类型转换:是通过类型转换运算来实现的,主要的数据类型转换分为自动转换

Java实现XML与JSON的互相转换详解

《Java实现XML与JSON的互相转换详解》这篇文章主要为大家详细介绍了如何使用Java实现XML与JSON的互相转换,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. XML转jsON1.1 代码目的1.2 代码实现2. JSON转XML3. JSON转XML并输出成指定的

Java实现将Markdown转换为纯文本

《Java实现将Markdown转换为纯文本》这篇文章主要为大家详细介绍了两种在Java中实现Markdown转纯文本的主流方法,文中的示例代码讲解详细,大家可以根据需求选择适合的方案... 目录方法一:使用正则表达式(轻量级方案)方法二:使用 Flexmark-Java 库(专业方案)1. 添加依赖(Ma

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

Python使用PIL库将PNG图片转换为ICO图标的示例代码

《Python使用PIL库将PNG图片转换为ICO图标的示例代码》在软件开发和网站设计中,ICO图标是一种常用的图像格式,特别适用于应用程序图标、网页收藏夹图标等场景,本文将介绍如何使用Python的... 目录引言准备工作代码解析实践操作结果展示结语引言在软件开发和网站设计中,ICO图标是一种常用的图像

Python3脚本实现Excel与TXT的智能转换

《Python3脚本实现Excel与TXT的智能转换》在数据处理的日常工作中,我们经常需要将Excel中的结构化数据转换为其他格式,本文将使用Python3实现Excel与TXT的智能转换,需要的可以... 目录场景应用:为什么需要这种转换技术解析:代码实现详解核心代码展示改进点说明实战演练:从Excel到