核心板: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_GPIOBextern 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);//使能ADCADC_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_Stream0extern 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);//使能ADCADC_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);//使能ADCADC_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);}
}

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

基于STM32F407使用ADC采集电压实验相关推荐

  1. 蓝桥杯嵌入式模板的构建——STM32G431RB(LCD和ADC采集电压)

    基于LED和按键的模板来写的 下载工程的链接 蓝桥杯嵌入式模板的构建--STM32G431RB(LED和按键的配置)-其它文档类资源-CSDN下载这个模板亲测有效只写了按键三和按键4对LED进行点灯和 ...

  2. 小壁虎EFM32之ADC 采集电压

    前言 最近在学习小壁虎EFM32芯片的使用,需要用ADC采集电压,学习之中,遇到一些小问题和需要注意的地方,现将其记录下来,避免以后自己再次踩坑和往后可以学而时习之:好了,进入正题. 代码 主函数: ...

  3. Arduino Uno 使用 ADC采集电压在LCD上显示

    Arduino Uno 使用 ADC采集电压显示在LCD上 前言 所需组件 电路图及说明 Arduino使用ADC 代码 前言 在本教程中,我们将在 ARDUINO UNO 中介绍 ADC(模数转换) ...

  4. 基于STM32F407的ADC解析-ADC1多通道扫描模式电压采集实验(启用DMA传输数据)

    目录 一:STM32F4的ADC简介 1.1 ADC简介(不看也行) 1.2 ADC的供电及采样电压 二:实验步骤及代码 2.1实验步骤 2.2实验代码 2.2.1 ADC初始化代码 2.2.2 DM ...

  5. STM32实现双通道ADC采集电压电流值

    本次的实验是通过配置DMA来获取ADC采集到的数据的. 软件实现如下: adc.c文件 #include "adc.h"#define ADC1_DR_Address ((u32) ...

  6. STM32 - ADC采集电压 中断处理

    一.参考电压 VDD接入电压为3.3V ADC供电要求:2.4V到3.6V 注意:STM32的100脚以上(含100脚)有参考电压引脚.在没有参考电压引脚的单片机上,可以把基准电压芯片接入VDDA,但 ...

  7. GD32 ADC采集电压

    文章目录 ADC TIM DMA 其他一些初始化 main 总结 使用芯片为GD32F307 ADC 连续转换模式,可以运行在规则组通道上,一旦相应软件触发或者外部触发产生,ADC就会采样和转换规定的 ...

  8. 单片机 ADC采集电压

    单片机:N76E003 /********************************************* 函数名:Adc_Configuration 功 能:ADC初始化配置 形 参: 返 ...

  9. F28335的ADC采集电压不对(采集的电压值乱飘)

    昨天在调试F28335的ADC采集部分,因为有开发板,所以我就直接把光盘自带的程序给跑了一下,结果发现采集的值和我输入的值不对,我的输入是直接把一个直流电源的正极接到一个采集通道的端口上,直流电源的地 ...

最新文章

  1. Linux 命令之 passwd -- 修改用户账号密码
  2. React开发(208):react代码分割在嵌套组件中更新 Context
  3. 欧盟批准ATT收购时代华纳 或年底前完成交易
  4. 2017android 最强旗舰,2017年世界六大旗舰机,华为第五,第一惊艳全球!
  5. 【janio】janio 官网 翻译 Janino 是一个超小、超快的 Java 编译器
  6. 【Oracle】创建概要文件
  7. 【转】.Net 架构图
  8. ansys通过扫掠(sweep)方法划分网格的方法
  9. C++ 原子操作与无锁编程
  10. win11怎么进安全模式,win11进入安全模式的方法
  11. 清除Zabbix的历史记录
  12. 还没收到win11系统的推送?教你这样可以直接升级win11
  13. system verilog基础知识总结与复习(随机化)
  14. m227fdw恢复出厂设置_HP各种打印机恢复出厂设置的方法
  15. uniapp开发微信小程序生成二维码海报
  16. Catia 滚动轴承设计
  17. 【数据结构】广义表的基本概念
  18. 标幺值下Simulink三相瞬时功率模块输出端加增益2/3的原因
  19. Java精品文章收藏(百度文库)
  20. 邓西百度网盘批量分享工具

热门文章

  1. 初识HTML(五)进阶:CSS盒子模型、页面布局
  2. 基于Java毕业设计在线直播平台源码+系统+mysql+lw文档+部署软件
  3. Android相关简述题
  4. layUI中使用layer.open,在content打开数据表格,获取值并返回
  5. 打印机一页内容总是有空白
  6. 【Scapy】获取流量包【原创】
  7. RocketMq - Springboot2.x整合RocketMQ4.x - 发送消息(七)
  8. eclipse 上传代码到github,我花费了一个月测的。就这样了
  9. 可以发热的“电”羽绒服!60秒升温15度,自带充电宝,脏了还能机洗
  10. 9、验签失败可能的原因有哪些?