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

相关文章

PDF 软件如何帮助您编辑、转换和保护文件。

如何找到最好的 PDF 编辑器。 无论您是在为您的企业寻找更高效的 PDF 解决方案,还是尝试组织和编辑主文档,PDF 编辑器都可以在一个地方提供您需要的所有工具。市面上有很多 PDF 编辑器 — 在决定哪个最适合您时,请考虑这些因素。 1. 确定您的 PDF 文档软件需求。 不同的 PDF 文档软件程序可以具有不同的功能,因此在决定哪个是最适合您的 PDF 软件之前,请花点时间评估您的

C# double[] 和Matlab数组MWArray[]转换

C# double[] 转换成MWArray[], 直接赋值就行             MWNumericArray[] ma = new MWNumericArray[4];             double[] dT = new double[] { 0 };             double[] dT1 = new double[] { 0,2 };

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

数据流与Bitmap之间相互转换

把获得的数据流转换成一副图片(Bitmap) 其原理就是把获得倒的数据流序列化到内存中,然后经过加工,在把数据从内存中反序列化出来就行了。 难点就是在如何实现加工。因为Bitmap有一个专有的格式,我们常称这个格式为数据头。加工的过程就是要把这个数据头与我们之前获得的数据流合并起来。(也就是要把这个头加入到我们之前获得的数据流的前面)      那么这个头是

高斯平面直角坐标讲解,以及地理坐标转换高斯平面直角坐标

高斯平面直角坐标系(Gauss-Krüger 坐标系)是基于 高斯-克吕格投影 的一种常见的平面坐标系统,主要用于地理信息系统 (GIS)、测绘和工程等领域。该坐标系将地球表面的经纬度(地理坐标)通过一种投影方式转换为平面直角坐标,以便在二维平面中进行距离、面积和角度的计算。 一 投影原理 高斯平面直角坐标系使用的是 高斯-克吕格投影(Gauss-Krüger Projection),这是 横

VC环境下整型转换为字符串型(2)

在串口下位机的发送中,可能会用到需要发送数字,显示为字符串型的 和上一篇文字《串口中字符串转换为整型》一正一反,知识点学习会了: #include<iostream.h> #include <stdio.h> #include <string.h>   void inttostr(int m,unsigned char * str) { int length=0;   int tmp,te

时间日期与时间戳转换(Linux C)

本文主要学习三个知识点,第一是UTC时间、GMT时间的概念;第二是在Unix环境下UTC时间与时间戳的转换;第三是在C语言中如何修改时区。 本文参考了《UNP》以及 http://blog.csdn.net/foxir/article/details/43916601 http://blog.csdn.net/ljafl9988/article/details/16847935 一、

点云数据常见的坐标系有哪些,如何进行转换?

文章目录 一、点云坐标系分类1. 世界坐标系2. 相机坐标系3. 极坐标系4. 笛卡尔坐标系(直角坐标系):5. 传感器坐标系6. 地理坐标系 二、坐标系转换方法1. 地理坐标系与投影坐标系之间的转换2. 投影坐标系与局部坐标系之间的转换3. 局部坐标系与3D模型坐标系之间的转换4. 相机坐标系与其他坐标系之间的转换5. 传感器坐标系与其他坐标系之间的转换 三、坐标系转换工具 一

思科网络地址转换5

#网络安全技术实现# #任务五利用动态NAPT实现局域网访问Internet5# #1配置计算机的IP 地址、子网掩码和网关 #2配置路由器A的主机名称及其接口IP地址 Router>enable Router#conf t Router(config)#hostname Router-A Router-A(config)#int f0/0 Router-A(con

itoa()函数,10进制转换到(2~36)进制

先看下itoa()的函数说明吧: 功 能:把一整数转换为字符串   用 法:char *itoa(int value, char *string, int radix);    详细解释:itoa是英文integer to array(将int整型数转化为一个字符串,并将值保存在数组string中)的缩写.    参数:  value: 待转化的整数。            radix: