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

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

3天内不再提示

CKS32F4xx系列ADC多通道DMA电压采集

jf_pJlTbmA9 来源:中科芯MCU 作者:中科芯MCU 2023-11-06 16:53 次阅读

在上一讲单通道ADC电压采集的基础上,本节主要介绍CKS32F4xx系列产品基于DMA传输的ADC多通道电压采集转换实现。

DMA传输在ADC中的应用

DMA是直接存储器存取,通常在使用ADC时,需要通过MCU内核不停的读取数据,如果使用DMA,那么读取的过程会绕过MCU,减轻MCU内核的处理压力,这样有利于资源的充分利用,提高ADC数据的处理效率。由于ADC规则通道组只有一个数据寄存器中,当转换多个通道时,使用DMA还可以避免丢失已经存储在ADC_DR寄存器中的数据。在使能DMA模式的情况下,每完成规则通道组中的一个通道转换后,都会生成一个DMA请求,便可将转换的数据从ADC_DR寄存器传输到用指定的目标内存位置。这样取代单通道实验使用中断服务的读取方法,可以实现多通道ADC应用中高速高效的采集。

软件设计要点

跟单通道例程一样,编写两个ADC驱动文件,bsp_adc.h和bsp_adc.c,用来存放ADC所用IO引脚的初始化函数以及ADC和DMA相关配置函数,主要流程为:

(1)初始化配置ADC目标引脚为模拟输入模式;

(2)使能ADC时钟和DMA时钟;

(3)配置DMA从ADC数据寄存器传输数据到指定的存储区;

(4)配置通用ADC为独立模式;

(5)设置ADC为12位分辨率,启动扫描,连续转换,不需要外部触发;

(6)设置ADC转换通道顺序及采样时间;

(7)使能DMA请求,DMA在AD转换完自动传输数据到指定的存储区;

(8)启动ADC模块;

(9)软件使能触发ADC转换。

这里需要注意的是,在使用ADC+DMA功能时,如果在启动ADC转换之后使能DMA,ADC采样数据可能会出现异常。因此建议先配置ADC及DMA相关参数,最后启动ADC转换。

代码实现

受篇幅限制,这里只介绍核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本课程配套的例程。相关核心代码实现如下:

(1)ADC宏定义

#defineTEMP_NOFCHANEL3
/*=====================通道1IO======================*/
//PB0ADCIO宏定义,可用杜邦线接3V3或者GND来实验
#defineTEMP_ADC_GPIO_PORT1GPIOB
#defineTEMP_ADC_GPIO_PIN1GPIO_Pin_0
#defineTEMP_ADC_GPIO_CLK1RCC_AHB1Periph_GPIOB
#defineTEMP_ADC_CHANNEL1ADC_Channel_8
/*=====================通道2IO======================*/
//PB1ADCIO宏定义,可用杜邦线接3V3或者GND来实验
#defineTEMP_ADC_GPIO_PORT2GPIOB
#defineTEMP_ADC_GPIO_PIN2GPIO_Pin_1
#defineTEMP_ADC_GPIO_CLK2RCC_AHB1Periph_GPIOB
#defineTEMP_ADC_CHANNEL2ADC_Channel_9
/*=====================通道3IO======================*/
//PA6ADCIO宏定义,可用杜邦线接3V3或者GND来实验
#defineTEMP_ADC_GPIO_PORT3GPIOA
#defineTEMP_ADC_GPIO_PIN3GPIO_Pin_6
#defineTEMP_ADC_GPIO_CLK3RCC_AHB1Periph_GPIOA
#defineTEMP_ADC_CHANNEL3ADC_Channel_6
//ADC序号宏定义
#defineTEMP_ADCADC1
#defineTEMP_ADC_CLKRCC_APB2Periph_ADC1
//ADCDR寄存器宏定义,ADC转换后的数字值则存放在这里
#defineTEMP_ADC_DR_ADDR((u32)ADC1+0x4c)
//ADCDMA通道宏定义,使用DMA传输
#defineTEMP_ADC_DMA_CLKRCC_AHB1Periph_DMA2
#defineTEMP_ADC_DMA_CHANNELDMA_Channel_0
#defineTEMP_ADC_DMA_STREAMDMA2_Stream0

定义多个通道进行多通道ADC实验,并且定义DMA相关配置。

(2)ADC GPIO初始化

staticvoidTemp_ADC_GPIO_Config(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
/*=====================通道1======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK1,ENABLE);//使能GPIO时钟
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN1;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT1, GPIO_InitStructure);
/*=====================通道2======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK2,ENABLE);//使能GPIO时钟
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN2;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT2, GPIO_InitStructure);
/*=====================通道3=======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK3,ENABLE);//使能GPIO时钟
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN3;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT3, GPIO_InitStructure);
}

使用到GPIO时候都必须开启对应的GPIO时钟,GPIO用于AD转换功能必须配置为模拟输入模式。

(3)配置ADC工作模式

staticvoidTemp_ADC_Mode_Config(void)
{
DMA_InitTypeDefDMA_InitStructure;
ADC_InitTypeDefADC_InitStructure;
ADC_CommonInitTypeDefADC_CommonInitStructure;
//--------------DMAInit结构体参数初始化-------------
//ADC1使用DMA2,数据流0,通道0,
RCC_AHB1PeriphClockCmd(TEMP_ADC_DMA_CLK,ENABLE);//开启DMA时钟
DMA_InitStructure.DMA_PeripheralBaseAddr=TEMP_ADC_DR_ADDR;//外设基址为:ADC数据寄存器地址
DMA_InitStructure.DMA_Memory0BaseAddr=(u32)ADC_ConvertedValue;//AD值存储地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//数据传输方向为外设到存储器
DMA_InitStructure.DMA_BufferSize=TEMP_NOFCHANEL;//缓冲区大小,指一次传输的数据量
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_High;//DMA传输通道优先级为高
DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//禁止DMAFIFO,使用直连模式
DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_HalfFull;//FIFO大小,FIFO禁止时不用配置
DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Channel=TEMP_ADC_DMA_CHANNEL;//选择DMA通道,通道存在于流中
DMA_Init(TEMP_ADC_DMA_STREAM, DMA_InitStructure);//初始化DMA流,
DMA_Cmd(TEMP_ADC_DMA_STREAM,ENABLE);//使能DMA流

RCC_APB2PeriphClockCmd(TEMP_ADC_CLK,ENABLE);//开启ADC时钟
//-------------ADCCommon结构体参数初始化----------------
ADC_CommonInitStructure.ADC_Mode=ADC_Mode_Independent;//独立ADC模式
ADC_CommonInitStructure.ADC_Prescaler=ADC_Prescaler_Div4;//时钟为fpclkx分频
ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;//禁止DMA直接访问模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_20Cycles;//采样时间间隔
ADC_CommonInit( ADC_CommonInitStructure);
//-------------------ADCInit结构体参数初始化--------------------------
ADC_StructInit( ADC_InitStructure);
ADC_InitStructure.ADC_Resolution=ADC_Resolution_12b;//ADC分辨率
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=TEMP_NOFCHANEL;//转换通道3个
ADC_Init(TEMP_ADC, ADC_InitStructure);


//配置ADC通道转换顺序和采样时间周期
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL1,1,ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL2,2,ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL3,3,ADC_SampleTime_3Cycles);

ADC_DMARequestAfterLastTransferCmd(TEMP_ADC,ENABLE);//使能DMA请求
ADC_DMACmd(TEMP_ADC,ENABLE);//使能ADCDMA
ADC_Cmd(TEMP_ADC,ENABLE);//使能ADC
ADC_SoftwareStartConv(TEMP_ADC);//开始ADC转换,软件触发
}

首先,使用DMA_InitTypeDef定义了DMA初始化类型变量,另外使用ADC_InitTypeDef和ADC_CommonInitTypeDef结构体分别定义一个ADC初始化和ADC通用类型变量。

调用RCC_APB2PeriphClockCmd()开启ADC时钟以及RCC_AHB1PeriphClockCmd()开启DMA时钟。

对DMA进行必要的配置。首先设置外设基地址就是ADC的规则数据寄存器地址;存储器的地址就是指定的数据存储区空间,ADC_ConvertedValue是我们定义的一个全局数组名,它是一个无符号16位含有3个元素的整数数组;ADC规则转换对应只有一个数据寄存器,所以地址不能递增,而定义的存储区是专门用来存放不同通道数据的,所以需要自动地址递增。ADC的规则数据寄存器只有低16位有效,实际存放的数据只有12位而已,所以设置数据大小为半字大小。ADC配置为连续转换模式,DMA也设置为循环传输模式。设置好DMA相关参数后就使能DMA的ADC通道。

接下来使用ADC_CommonInitTypeDef结构体变量ADC_CommonInitStructure来配置ADC为独立模式、分频系数4、20个周期的采样延迟,并调用ADC_CommonInit函数完成ADC通用工作环境配置。

使用ADC_InitTypeDef结构体变量ADC_InitStructure来配置ADC1为12位分辨率、使能扫描模式、启动连续转换、使用内部软件触发无需外部触发事件、使用右对齐数据格式、转换通道为3,并调用ADC_Init函数完成ADC1工作环境配置。

ADC_RegularChannelConfifig函数用来绑定ADC通道转换顺序和采样时间。分别绑定3个ADC通道引脚并设置相应的转换顺序。

ADC_DMARequestAfterLastTransferCmd函数控制是否使能ADC的DMA请求,如果使能请求,并调用ADC_DMACmd函数使能DMA,则在ADC转换完成后就请求DMA实现数据传输。ADC_Cmd函数控制ADC转换启动和停止。

最后使用软件触发调用ADC_SoftwareStartConvCmd函数进行使能配置。

(4)Main程序

/**主函数*/
intmain(void)
{
Debug_USART_Config();
Temp_Init();
while(1)
{
ADC_ConvertedValueLocal[0]=(float)ADC_ConvertedValue[0]/4096*(float)3.3;
ADC_ConvertedValueLocal[1]=(float)ADC_ConvertedValue[1]/4096*(float)3.3;
ADC_ConvertedValueLocal[2]=(float)ADC_ConvertedValue[2]/4096*(float)3.3;
printf("rnPB0value=%fVrn",ADC_ConvertedValueLocal[0]);
printf("rnPB1value=%fVrn",ADC_ConvertedValueLocal[1]);
printf("rnPA6value=%fVrn",ADC_ConvertedValueLocal[2]);
Delay(0xffffff);
}
}

主函数先调用Debug_USART_Config函数配置调试串口相关参数,接下来调用Temp_Init函数进行ADC初始化配置并启动ADC。配置了DMA数据传输,它会自动把ADC转换完成后数据保存到数组ADC_ConvertedValue内,我们只要使用数组就可以了。经过简单地计算就可以得到每个通道对应的实际电压。

来源:中科芯MCU

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

    关注

    38

    文章

    7151

    浏览量

    162005
  • adc
    adc
    +关注

    关注

    95

    文章

    5653

    浏览量

    539509
  • dma
    dma
    +关注

    关注

    3

    文章

    536

    浏览量

    99070
  • 电压采集
    +关注

    关注

    2

    文章

    18

    浏览量

    13907
收藏 人收藏

    评论

    相关推荐

    MCU微课堂|CKS32F4xx系列产品时钟配置

    作为MCU运行的基础,时钟是单片机各个模块工作时序的最小时间单位,推动单片机的各指令执行,是MCU选型的一个重要指标。CKS32F4xx系列产品具有众多的外设,但并非所有的外设均需要系统时钟的高频率
    发表于 12-12 10:17 568次阅读

    CKS32F4xx系列ETH通信详解

    CKS32F4xx系列芯片自带以太网模块,该模块包括带专用DMA控制器的MAC 802.3(介质访问控制)控制器
    的头像 发表于 11-10 11:13 620次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>ETH通信详解

    CKS32F4xx系列DSP功能介绍

    CKS32F4xx系列使用高性能的32位内核,支持浮点运算单元(FPU),同时还支持DSP指令以及存储保护(MPU)用来加强应用的安全性。
    的头像 发表于 03-04 13:43 886次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>DSP功能介绍

    CKS32F4xx系列I2S功能介绍

    CKS32F4xx系列使用高性能的32位内核,支持浮点运算单元(FPU),同时还支持DSP指令以及存储保护(MPU)用来加强应用的安全性。
    的头像 发表于 03-17 09:40 503次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>I2S功能介绍

    CKS32F4xx系列mcu的GPIO口配置方法

    GPIO(General-purpose input/output)是通用输入输出端口的简称,CKS32F4xx系列产品通过GPIO引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。
    发表于 12-26 11:32 940次阅读

    CKS32F4xx系列产品串口DMA传输

    在上一讲,我们讲过CKS32F4xx系列的6个串口都支持DMA传输。因此本节我们对CKS32F4xx系列
    的头像 发表于 04-10 11:18 707次阅读

    CKS32F4xx系列RNG功能设置

      MCU 微课堂 CKS32F4xx 系 列RNG功能 随机数发生器简介     CKS32F4xx系列自带了硬件随机数发生器(RNG),RNG处理器是一个以连续模拟噪声为基础的随机数发生器
    的头像 发表于 09-08 10:01 344次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>RNG功能设置

    CKS32F4xx系列DAC功能

    CKS32F4xx系列DAC功能
    的头像 发表于 11-06 16:56 601次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>DAC功能

    CKS32F4xx系列ADC通道电压采集

    CKS32F4xx系列ADC通道电压采集
    的头像 发表于 11-06 16:54 572次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b><b class='flag-5'>ADC</b>单<b class='flag-5'>通道</b><b class='flag-5'>电压</b><b class='flag-5'>采集</b>

    CKS32F4xx系列低功耗模式STANDBY模式

    CKS32F4xx系列低功耗模式STANDBY模式
    的头像 发表于 11-06 16:57 245次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式STANDBY模式

    CKS32F4xx系列低功耗模式SLEEP模式

    CKS32F4xx系列低功耗模式SLEEP模式
    的头像 发表于 11-06 16:59 443次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式SLEEP模式

    CKS32F4xx系列低功耗模式STOP模式

    CKS32F4xx系列低功耗模式STOP模式
    的头像 发表于 11-06 17:08 363次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式STOP模式

    MCU微课堂 | CKS32F4xx系列产品SPI通信

    MCU微课堂 | CKS32F4xx系列产品SPI通信
    的头像 发表于 10-24 17:12 423次阅读
    MCU微课堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>产品SPI通信

    MCU微课堂 | CKS32F4xx系列产品GPIO口配置

    MCU微课堂 | CKS32F4xx系列产品GPIO口配置
    的头像 发表于 10-24 15:14 483次阅读
    MCU微课堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>产品GPIO口配置

    CKS32F4xx系列FSMC功能简介

    本课讲为大家讲解CKS32F4xx系列产品的FSMC应用实例,FSMC全称是Flexible Static Memory Controller,读作灵活的静态存储控制器,顾名思义,MCU可以通过FSMC扩展静态内存
    的头像 发表于 04-14 15:06 268次阅读
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>FSMC功能简介