【STM32】ADC模拟数字转换(规则组多通道)+ DMA数据转运(外设到存储器)

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发

目录

前言

ADC规则组扫描模式+DMA

定义变量

规则组配置 

ADC初始化 

连续模式

 扫描模式

规则组通道个数 

 ADC初始化框架

 DMA初始化

ADC和DMA使能 

 软件触发转运

 代码框架

ADC扫描转换与DMA循环转运

单次扫描+单轮转运


前言

本篇博客会在下面两篇的代码及理解的基础上修改。阅读本篇之前建议先阅读以下两篇博客: 

 【STM32】ADC模拟数字转换-规则组单通道-CSDN博客

【STM32】DMA数据转运(存储器到存储器)-CSDN博客

ADC规则组扫描模式+DMA

  之前学习了ADC规则组单通道,这种方式只能一次触发一个通道的ADC转换,虽然可以通过每次触发前改变序列上的通道号来对通道实现轮询的转换,但每次触发也只能转换一个通道的模拟量,不能一次ADC触发实现多个模数转换,效率较低。

本篇来学习ADC规则组的多通道转换,一次触发ADC转换可以实现转换多个通道,已知ADC规则组数据寄存器只有一个,当配置为多通道转换时,每个序列上的通道会依次把数据存在数据寄存器中。规则组转换完成一次时(标志位EOC为1),最终数据寄存器上的数据是最后一个指定的序列上的通道转换的值。前面通道的数据都会覆盖,因为组内每一个序列上通道转换完成时,没有标志位,无法通过软件实现检查标志位控制CPU来实现转运数据,那该怎么办呢?

可以通过ADC发出DMA请求,每一个序列上的通道转换完成都会发出DMA请求。ADC序列1的通道转换完成发出DMA请求,触发DMA转运,DMA就会把ADC规则组数据寄存器位置上的数据转运到指定地址,序列2的通道转换完成,数据覆盖上一次转化的数据,再次发出DMA请求,DMA转运数据(转运相当于复制了数据再转运,原数据依然在寄存器中)

图片来源于[8-1] DMA直接存储器存取_哔哩哔哩_bilibili

参考手册

DMA请求 因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用 DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。 只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户指定的目的地址。

注: 只有ADC1和ADC3拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的 DMA功能传输。 

定义变量

ADC分辨率为12位,但规则组通道数据寄存器为16位,我这里数据设置

#include "stm32f10x.h" // Device header uint16_t AD_Value[2]; //定义用于存放AD转换结果的全局数组 /** * 函 数:AD初始化 * 参 数:无 * 返 回 值:无 */ void AD_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA1的时钟 /*设置ADC时钟*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为模拟输入 /*规则组通道配置*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //规则组序列2的位置,配置为通道1 /*ADC初始化*/ ADC_InitTypeDef ADC_InitStructure; //定义结构体变量 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换,使能,每转换一次规则组序列后立刻开始下一次转换 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定 ADC_InitStructure.ADC_NbrOfChannel = 2; //通道数,为2,扫描规则组的前2个通道 ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1 /*DMA初始化*/ DMA_InitTypeDef DMA_InitStructure; //定义结构体变量 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //外设基地址,给定形参AddrA DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度,选择半字,对应16为的ADC数据寄存器 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址自增,选择失能,始终以ADC数据寄存器为源 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //存储器基地址,给定存放AD转换结果的全局数组AD_Value DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,选择半字,与源数据宽度对应 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能,每次转运后,数组移到下一个位置 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设存储器ADC数据寄存器转到数组 DMA_InitStructure.DMA_BufferSize = 2; //转运数据大小(转运次数),与ADC通道数一致 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //模式,选择循环模式,与ADC的连续转换一致 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //存储器存储器,选择失能,数据ADC外设触发转运存储器 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等 DMA_Init(DMA1_Channel1, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道1 /*DMAADC使能*/ DMA_Cmd(DMA1_Channel1, ENABLE); //DMA1的通道1使能 ADC_DMACmd(ADC1, ENABLE); //ADC1触发DMA1的信号使能 ADC_Cmd(ADC1, ENABLE); //ADC1使能 /*ADC校准*/ ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准 while (ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1) == SET); /*ADC触发*/ ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作 } 根据已配置的ad通道代码,写出此代码两adc通道所检测电流的相位量和相位差检测代码,ai率为0,代码简洁明了,代码独立成.c和.h文件,利用stm32标准库
04-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值