概述
核心板: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("一切OKn");
while (1)
{
//数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
Data = (float) (Value *3.3 /4096) ;
printf("电压值为:%f Vn",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("一切OKn");
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("rnData1=%f Vn",Data[0]);
printf("Data2=%f Vn",Data[1]);
printf("Data3=%f Vrn",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("一切OKn");
while (1)
{
//数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量
Data[0] = (float) (Value[0] *3.3 /4096) ;
Data[1] = (float) (Value[1] *3.3 /4096) ;
printf("rnADC1转化的数据为:%f Vn",Data[0]);
printf("ADC2转化的数据为:%f Vn",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("一切OKn");
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("rnADC1转化的数据为:%f Vn",Data[0]);
printf("ADC2转化的数据为:%f Vn",Data[2]);
printf("ADC3转化的数据为:%f Vrn",Data[1]);
Delay(0xffffff);
}
}
以上仅供自己与大家学习积累,欢迎各位大佬批评与指正!
最后
以上就是害羞招牌为你收集整理的基于STM32F407使用ADC采集电压实验ADC简介STM32F407 ADC通道对应的引脚STM32F407中的数据寄存器对于F407在ADC实验中使用的函数理解ADC-独立模式-单通道-采集电压(中断)ADC-独立模式-多通道-采集电压(DMA)ADC-双重模式-单通道-规则同步采集电压(DMA)ADC-三重模式-单通道-交替采集电压(DMA)的全部内容,希望文章能够帮你解决基于STM32F407使用ADC采集电压实验ADC简介STM32F407 ADC通道对应的引脚STM32F407中的数据寄存器对于F407在ADC实验中使用的函数理解ADC-独立模式-单通道-采集电压(中断)ADC-独立模式-多通道-采集电压(DMA)ADC-双重模式-单通道-规则同步采集电压(DMA)ADC-三重模式-单通道-交替采集电压(DMA)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复