使用STM32F407开发ADC采集电压的实验研究

核心板:STM32F407

实验目的:使用ADC采集电压值将其打印在串口助手上


目录

ADC简介

STM32F407 ADC通道对应的引脚

STM32F407中的数据寄存器

ADC 规则数据寄存器 (ADC_DR)

ADC 注入数据寄存器 x (ADC_JDRx) (x= 1..4) 

适用于双重和三重模式的 ADC 通用规则数据寄存器(ADC_CDR)

对于F407在ADC实验中使用的函数理解

非DMA的相关函数

ADC_RegularChannelConfig()

ADC_Cmd()与ADC_SoftwareStartConv()

有关DMA的相关函数

ADC_DMARequestAfterLastTransferCmd()与ADC_DMACmd()

ADC_MultiModeDMARequestAfterLastTransferCmd()与ADC_CommonInitTypeDef中的成员ADC_DMAAccessMode

ADC-独立模式-单通道-采集电压(中断)

ADC-独立模式-多通道-采集电压(DMA)

ADC-双重模式-单通道-规则同步采集电压(DMA)

ADC-三重模式-单通道-交替采集电压(DMA)



ADC简介

        ADC就是一种数模转换器。在以下介绍的实验中,都是ADC对电压的采集,而ADC的输入电压为0-3.3v,如果ADC我们设置为12位,那么3.3v对应这2的12次方即4096,那么单位数字量对应的模拟量则为3.3/4096。而ADC的功能可以帮助我们获取数字量X,那么我们读取ADC获取的数字量X再乘以3.3/4096,就是电压值。

STM32F407 ADC通道对应的引脚

STM32F407中的数据寄存器

        在STM32F407中有三个数据寄存器,他们对应着不同的模式下数据存放的地方,在使用DMA时注意不要吧外设地址设置错误。

ADC 规则数据寄存器 (ADC_DR)

        ADC规则数据寄存器是一个32位只适用于独立模式的寄存器,但是只有低16位有效来存储数据,ADC最大精度为12位,所以我们在ADC在存放数据时我们需要设置左对齐还是右对齐来存储数据。

ADC 注入数据寄存器 x (ADC_JDRx) (x= 1..4) 

        ADC注入数据寄存器有四个,对应四个注入通道,所以不会存在向规则数据寄存器那样数据被覆盖的问题。

适用于双重和三重模式的 ADC 通用规则数据寄存器(ADC_CDR)

        ADC_DR仅适用于独立模式,而ADC_CDR适用于多重ADC即多个ADC使用的情况。 

对于F407在ADC实验中使用的函数理解

        在刚开始写这个实验的时候,在配置时某个函数该什么时候用什么时候不用,在哪用,就比较懵,其实就是多读读手册就好了,这里给大家小小的总结以下。

非DMA的相关函数

ADC_RegularChannelConfig()

 其参数为(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)

哪个ADC(ADCx),哪个通道(ADC_Channel),在这个ADC的转换顺序为第几(Rank),其采样周期为多少(ADC_SampleTime)。

ADC_Cmd()与ADC_SoftwareStartConv()

        这两函数操作的寄存器均为ADC_CR2,前者操作的为ADC_CR2中的ADON,后者为ADC_CR2中的SWSTART。

 

        所以我们在不是用外部触发时,我们应该如下写这两句代码(颠倒顺序我也不知道OK不)。

有关DMA的相关函数

ADC_DMARequestAfterLastTransferCmd()与ADC_DMACmd()

        其操作的分别为ADC_CR2中的DDS与DMA。

        所以这两个函数是针对只使用一个ADC时启用DMA该调用的函数。 

ADC_MultiModeDMARequestAfterLastTransferCmd()与ADC_CommonInitTypeDef中的成员ADC_DMAAccessMode

        其操作的分别为ADC_CCR中的DMA和DDS。

          所以这两个函数是针对只使用多个ADC时启用DMA该调用的函数。 

        初学的应该懂得为什么上面禁止DMA下面又使能DMA了吧!


        下面开始写实验,这里我只写ADC相关的配置和主程序,串口就交给大家了。

ADC-独立模式-单通道-采集电压(中断)

        实验内容:使用ADC1将PB0引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。

        bsp_adc.h

#ifndef _BSP__ADC_H
#define _BSP__ADC_H

#include "stm32f4xx.h"

/* ADC1 */

#define ADC_CLK 											RCC_APB2Periph_ADC1
#define ADC_CHANNEL											ADC_Channel_8

/* 电压输入引脚 (ADC1 通道8 引脚 ——PB0) */
#define ADC_PIN  											GPIO_Pin_0
#define ADC_GPIO_PORT										GPIOB
#define ADC_GPIO_CLK									    RCC_AHB1Periph_GPIOB

extern uint16_t Value;//数字量

void ADC_Config(void);


#endif

         bsp_adc.c

#include "bsp_adc.h"

uint16_t Value;//数字量

static void ADC_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	/* 配置ADC1为中断源 */
	NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	
	NVIC_Init(&NVIC_InitStructure);
}


void ADC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
	RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
	RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE);
	
	/* GPIO相关配置 */
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉  无下拉
	GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
	
	GPIO_Init (ADC_GPIO_PORT,&GPIO_InitStructure);
	
	
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式
	//ADC 外部触发选择(本实验用软件触发,随便配置)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要	
		
	ADC_Init(ADC1, &ADC_InitStructure);
	
	
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//禁止DMA直接访问模式	
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔	
	
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	ADC_NVIC_Config();
	
	//配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期
	ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
	
	ADC_ITConfig(ADC1,ADC_IT_EOC, ENABLE);//开启转换结束中断 
	
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	
	ADC_SoftwareStartConv(ADC1);//开始adc转换
}

        中断服务函数 

void ADC_IRQHandler(void)
{
	if(ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET)
	{
		Value = ADC_GetConversionValue(ADC1);//读取采集到的数字量
		
		ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
	}
	
}

        main.c(写一个)

void Delay(__IO u32 nCount); 

float Data;//最终的电压值

int main(void)
{
	USART_Config();
	
	ADC_Config();
	
	printf("一切OK\n");

	while (1)
	{
        //数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
		Data = (float) (Value *3.3 /4096) ;
		
		printf("电压值为:%f V\n",Data);
		
		Delay(0xffffff);
	}
}

void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}

 实验结果(PB0连接着滑动变阻器)

ADC-独立模式-多通道-采集电压(DMA)

       实验内容:使用ADC1将PB0、PB1、PA6引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。

         bsp_adc.h

#ifndef _BSP__ADC_H
#define _BSP__ADC_H

#include "stm32f4xx.h"

/* 电压输入引脚 (ADC 通道8 引脚 ——PB0) */
#define ADC_PIN1  												GPIO_Pin_0
#define ADC_GPIO_PORT1										    GPIOB
#define ADC_GPIO_CLK1										    RCC_AHB1Periph_GPIOB

/* 光敏电阻 (ADC 通道9 引脚 ——PB1)*/
#define ADC_PIN2  												GPIO_Pin_1
#define ADC_GPIO_PORT2										    GPIOB
#define ADC_GPIO_CLK2									      	RCC_AHB1Periph_GPIOB

/* 悬空 用杜邦线连接GND或VCC(ADC 通道6 引脚 ——PA6) */
#define ADC_PIN3  												GPIO_Pin_6
#define ADC_GPIO_PORT3										    GPIOA
#define ADC_GPIO_CLK3								  		    RCC_AHB1Periph_GPIOA

/* ADC1 */
#define ADC_CLK 												RCC_APB2Periph_ADC1
#define ADC_CHANNEL1											ADC_Channel_8
#define ADC_CHANNEL2											ADC_Channel_9
#define ADC_CHANNEL3											ADC_Channel_6
#define ADC1_DR_BASE											((uint32_t)ADC1+0x4c)

/* DMA */
#define ADC_DMA_CLK 											RCC_AHB1Periph_DMA2
#define ADC_DMA_CHANNEL  									    DMA_Channel_0
#define ADC_DMA_STREAM   									    DMA2_Stream0

extern uint16_t Value[3];

void ADC_Config(void);


#endif

        bsp_adc.c

#include "bsp_adc.h"

uint16_t Value[3];

static void ADC_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE);
	
		/* 配置DMA */
	DMA_InitStructure.DMA_BufferSize = 3;//一次性传输3个数据
	DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据宽度:半字16位
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_BASE;//外设地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度:半字16位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级
	/* FIFO不用随便配置 */
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	
	DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure);
	
	DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA
}	

void ADC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
	/* 开启时钟 */
	RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1|ADC_GPIO_CLK2|ADC_GPIO_CLK3,ENABLE);
	RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE);
	
	/* GPIO相关配置 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉  无下拉
	GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN1;
	GPIO_Init (ADC_GPIO_PORT1,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN2;
	GPIO_Init (ADC_GPIO_PORT2,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN3;
	GPIO_Init (ADC_GPIO_PORT3,&GPIO_InitStructure);
	
	
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式
	//ADC 外部触发选择(本实验用软件触发,随便配置)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_NbrOfConversion = 3;//转换通道数目
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;// 开启扫描模式,多通道采集需要	
		
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//禁止直接存储器访问模式(对于多个 ADC 模式)
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔	
	
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	ADC_DMA_Config();
	
	//配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期
	ADC_RegularChannelConfig(ADC1, ADC_CHANNEL1, 1, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC1, ADC_CHANNEL2, 2, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC1, ADC_CHANNEL3, 3, ADC_SampleTime_56Cycles);
	
	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求
	
	ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式)
	
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	//再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启
	ADC_SoftwareStartConv(ADC1);//开始转换规则通道
}

        main.c 

void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}


float Data[3];//最终的电压值

int main(void)
{
	USART_Config();
	
	ADC_Config();
	
	printf("一切OK\n");

	while (1)
	{
		//数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
		Data[0] = (float) (Value[0] *3.3 /4096) ;
		Data[1] = (float) (Value[1] *3.3 /4096) ;
		Data[2] = (float) (Value[2] *3.3 /4096) ;
		
		printf("\r\nData1=%f V\n",Data[0]);
		printf("Data2=%f V\n",Data[1]);
		printf("Data3=%f V\r\n",Data[2]);
		
		Delay(0xffffff);
	}
}

ADC-双重模式-单通道-规则同步采集电压(DMA)

        实验内容:使用ADC1将PB0引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。

        为了演示DMA模式1与2,这里我们使用模式1,下一个使用模式2。 

        模式1DMA应设置传输数据大小为16位,模式2DMA应设置传输数据大小为32位。

 

        bsp_adc.h

#ifndef _BSP__ADC_H
#define _BSP__ADC_H

#include "stm32f4xx.h"

/* 滑动变阻器(ADC1 通道8 引脚 ——PB0) */
#define ADC_PIN1  												GPIO_Pin_0
#define ADC_GPIO_PORT1										    GPIOB
#define ADC_GPIO_CLK1								  		    RCC_AHB1Periph_GPIOB

/* 滑动变阻器(ADC2 通道9 引脚 ——PB1) */
#define ADC_PIN2  												GPIO_Pin_1
#define ADC_GPIO_PORT2										    GPIOB
#define ADC_GPIO_CLK2								  		    RCC_AHB1Periph_GPIOB

/* ADC1 */
#define ADC1_CLK 												RCC_APB2Periph_ADC1
#define ADC2_CLK 												RCC_APB2Periph_ADC2

#define ADC1_CHANNEL											ADC_Channel_8
#define ADC2_CHANNEL											ADC_Channel_9

#define ADC1_CDR_ADDR											((uint32_t)ADC1+0x300+0x08)//多重ADC数据寄存器地址

/* DMA */
#define ADC_DMA_CLK 											RCC_AHB1Periph_DMA2
#define ADC_DMA_CHANNEL  									    DMA_Channel_0
#define ADC_DMA_STREAM   									    DMA2_Stream0
//多重模式下,ADC1还是主,所以只需要配置ADC1的DMA通道

extern uint16_t Value[2];

void ADC_Config(void);


#endif

        bsp_adc.c

#include "bsp_adc.h"

uint16_t Value[2];

static void ADC_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE);
	
		/* 配置DMA */
	DMA_InitStructure.DMA_BufferSize = 2;//一次性传输2个数据
	DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据宽度:半字16位
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_CDR_ADDR;//外设地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度:半字16位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级
	/* FIFO不用随便配置 */
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	
	DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure);
	
	DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA
}	

void ADC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
	/* 开启时钟 */
	RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1 | ADC_GPIO_CLK2,ENABLE);
	RCC_APB2PeriphClockCmd(ADC1_CLK | ADC2_CLK, ENABLE);
	
	/* GPIO相关配置 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉  无下拉
	GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN1;
	GPIO_Init (ADC_GPIO_PORT1,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN2;
	GPIO_Init (ADC_GPIO_PORT2,&GPIO_InitStructure);
	
	
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式
	//ADC 外部触发选择(本实验用软件触发,随便配置)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要(对于两个ADC只有一个通道)
		
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_Init(ADC2, &ADC_InitStructure);
	
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;//允许直接存储器访问模式(对于多个 ADC 模式)
	ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;// 二重模式规则同步采集
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔	
	
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	ADC_DMA_Config();
	
	//配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期
	ADC_RegularChannelConfig(ADC1, ADC1_CHANNEL, 1, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC2, ADC2_CHANNEL, 1, ADC_SampleTime_56Cycles);
	
//	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求(单通道)

	//对于多通道不用使能
//	ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式)
	
  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);//只要发生数据转换就会发生DMA请求(多通道)
	
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	ADC_Cmd(ADC2,ENABLE);
	
	//再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启
	ADC_SoftwareStartConv(ADC1);//开始转换规则通道(主ADC触发了,从ADC也会触发)
}

         main.c

void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}


float Data[2];//最终的电压值

int main(void)
{
	USART_Config();
	
	ADC_Config();
	
	printf("一切OK\n");

	while (1)
	{
		//数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
		Data[0] = (float) (Value[0] *3.3 /4096) ;
		Data[1] = (float) (Value[1] *3.3 /4096) ;
		
		printf("\r\nADC1转化的数据为:%f V\n",Data[0]);
		printf("ADC2转化的数据为:%f V\n",Data[1]);
		
		Delay(0xffffff);
	}
}

ADC-三重模式-单通道-交替采集电压(DMA)

        实验内容:使用ADC1、ADC2、ADC3将PC2引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。

       

 

         我们使用DMA模式2。

        bsp_adc.h

#ifndef _BSP__ADC_H
#define _BSP__ADC_H

#include "stm32f4xx.h"

/* 悬空 用杜邦线连接GND或VCC(ADC 通道12 引脚 ——PC2) */
#define ADC_PIN  												GPIO_Pin_2
#define ADC_GPIO_PORT											GPIOC
#define ADC_GPIO_CLK								  		    RCC_AHB1Periph_GPIOC

/* ADC1 */
#define ADC1_CLK 												RCC_APB2Periph_ADC1
#define ADC2_CLK 												RCC_APB2Periph_ADC2
#define ADC3_CLK 												RCC_APB2Periph_ADC3

#define ADC_CHANNEL												ADC_Channel_12

#define ADC1_CDR_ADDR											((uint32_t )ADC1+0x300+0x08 )

/* DMA */
#define ADC_DMA_CLK 											RCC_AHB1Periph_DMA2
#define ADC_DMA_CHANNEL  									    DMA_Channel_0
#define ADC_DMA_STREAM   									    DMA2_Stream0
//多重模式下,ADC1还是主,所以只需要配置ADC1的DMA通道

extern uint32_t Value[3];

void ADC_Config(void);


#endif

         bsp_adc.c

#include "bsp_adc.h"

uint32_t Value[3];

static void ADC_DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE);
	
		/* 配置DMA */
	DMA_InitStructure.DMA_BufferSize = 3;//一次性传输3个数据
	DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据宽度:字32位
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_CDR_ADDR;//外设地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据宽度:字32位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级
	/* FIFO不用随便配置 */
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	
	DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure);
	
	DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA
}	

void ADC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	
	/* 开启时钟 */
	RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
	RCC_APB2PeriphClockCmd(ADC1_CLK | ADC2_CLK | ADC3_CLK, ENABLE);
	
	/* GPIO相关配置 */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉  无下拉
	GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速
	
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_Init (ADC_GPIO_PORT,&GPIO_InitStructure);
	
	
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式
	//ADC 外部触发选择(本实验用软件触发,随便配置)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要	
		
	ADC_Init(ADC1, &ADC_InitStructure);//通道相同只需要初始化ADC1就好
//	ADC_Init(ADC2, &ADC_InitStructure);
//	ADC_Init(ADC3, &ADC_InitStructure);
	
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;//允许直接存储器访问模式(对于多个 ADC 模式)
	ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;// 三重模式交替采集
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔	
	
	ADC_CommonInit(&ADC_CommonInitStructure);
	
	ADC_DMA_Config();
	
	//配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期
	ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC2, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
	ADC_RegularChannelConfig(ADC3, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
	
//	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求(单通道)

	//对于多通道不用使能
//	ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式)
	
  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);//只要发生数据转换就会发生DMA请求(多通道)
	
	ADC_Cmd(ADC1,ENABLE);//使能ADC
	ADC_Cmd(ADC2,ENABLE);
	ADC_Cmd(ADC3,ENABLE);
	
	//再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启
	ADC_SoftwareStartConv(ADC1);//开始转换规则通道(主ADC触发了,从ADC也会触发)
}

        main.c

void Delay(__IO uint32_t nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
}


float Data[3];//最终的电压值

int main(void)
{
	USART_Config();
	
	ADC_Config();
	
	printf("一切OK\n");

	while (1)
	{
		//数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
		Data[0] = (float) ((uint16_t)Value[0] *3.3 /4096) ;
		Data[1] = (float) ((uint16_t)Value[1] *3.3 /4096) ;
		Data[2] = (float) ((uint16_t)Value[2] *3.3 /4096) ;
		
		printf("\r\nADC1转化的数据为:%f V\n",Data[0]);
		printf("ADC2转化的数据为:%f V\n",Data[2]);
		printf("ADC3转化的数据为:%f V\r\n",Data[1]);
		
		Delay(0xffffff);
	}
}

        以上仅供自己与大家学习积累,欢迎各位大佬批评与指正!

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32F407开发ADC采集电压的实验研究

发表评论