STM32F407ADC电压采集DMA传输

文章目录

  • ADC电压采集DMA传输
  • ADC相关知识
    • 1.ADC引脚与相关的通道的关系
  • DMA相关知识
    • 1.DMA外设通道
  • 代码
    • 1.GPIO初始化配置
    • 2.ADC初始化配置
    • 3.DMA初始化配置
    • 4.配置信息整理,ADC转换
  • 总结

一、ADC相关知识

ADC引脚与相关的通道的关系,16个外部资源对应表。这里只列出了外部资源表具体ADC相关的知识可以去看ADC详细资料,这里当中对ADC通道有比较重要

通道号ADC1ADC2ADC3
通道0PA0PA0PA0
通道1PA1PA1PA1
通道2PA2PA2PA2
通道3PA3PA3PA3
通道4PA4PA4PF6
通道5PA5PA5PF7
通道6PA6PA6PF8
通道7PA7PA7PF9
通道8PB0PB0PF10
通道9PB1PB1PF3
通道10PC0PC0PC0
通道11PC1PC1PC1
通道12PC2PC2PC2
通道13PC13PC13PC13
通道14PC4PC4PF4

二、DMA相关知识

外设通道的选择主要目的是决定哪一个外设作为该数据流的源地址或者目标地址。这个也是DMA这个功能的精髓之一。这也是这里的重点。

三、代码

        1.GPIO初始化配置

//ADC GPIO初始化
void my_ADC_GPIO_Init(void)
{  
    my_gpio_init(GPIO_PA0_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA1_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA2_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA3_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA4_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA5_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA6_VOLTAGE_RUN);
    my_gpio_init(GPIO_PA7_VOLTAGE_RUN);
    
}


这里大家可能会不太理解,怎么这样可以配置,因为我把配置封装了一遍,大家可以能会不太理解,大家可以以平常配置GPIO的方式去配置就可以了。以下只是举一个栗子。

void my_GPIO_Init
{
 GPIO_InitTypeDef GPIO_InitStructure;

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能 GPIOA 时钟

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PA5 通道 5
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

}

        2.ADC初始化配置

void my_ADC_Init(void)
{ 
    ADC_InitTypeDef ADC_InitStruct;
    ADC_CommonInitTypeDef ADC_CommonInitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    
    
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1 复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //复位结束
    
    ADC_TempSensorVrefintCmd(ENABLE);//使能内部温度传感器
    
    ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;    //独立模式
    ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //MDA 禁止直接访问 
    ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div4;  //预分频4分频    //ADCCLK=PCLK2/4=84/4=21Mhz,ADC 时钟最好不要超过 36Mhz
    ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //两个采样阶段之间的延迟5个时钟
    ADC_CommonInit(&ADC_CommonInitStruct);
 
    ADC_StructInit(&ADC_InitStruct);
    ADC_InitStruct.ADC_ScanConvMode = ENABLE;                                //扫描模式, 多通道采集
    ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;                          //连续转换
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;                      //右对齐
    ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止触发检测,使用软件触发.
    ADC_InitStruct.ADC_NbrOfConversion =  ADC_Channel_MAX;                                 //转换通道 3 个
    ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;                      //12位模式
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;       //软件触发.
    ADC_Init(ADC1, &ADC_InitStruct);
    
    ADC_Cmd(ADC1,ENABLE);
    
}

        3.DMA初始化配置

void my_DMA_Init(void)
{
    
    DMA_InitTypeDef DMA_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
    
    DMA_InitStruct.DMA_Channel = DMA_Channel_0;              //通道0
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;     //外设到寄存器
    DMA_InitStruct.DMA_Memory0BaseAddr = (u32)Run_Voltage;   //存储到的外部内存  
    DMA_InitStruct.DMA_PeripheralBaseAddr = ADC_Voltage;     //ADC1内存地址
    DMA_InitStruct.DMA_BufferSize = ADC_Channel_MAX;                       //一次传输的数据量为3
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;         //优先级高
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据大小也为半字,跟外设数据大小相同
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   // 外设数据大小为半字,即两个字节    
    DMA_InitStruct.DMA_MemoryInc =  DMA_MemoryInc_Enable;           //存储器地址固定
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   //外设地址只有一个,地址不用递增.   
    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;                    //循环传输
    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;             //是否开启FIFO模式
    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;  //选择FIFO阈值
    DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;            //存储器突发传输
    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;    //外设突发传输配置
    DMA_Init(DMA2_Stream0, &DMA_InitStruct);
    
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC|DMA_IT_TE, ENABLE);
    
    DMA_Cmd(DMA2_Stream0,ENABLE);
    
    NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;    
    NVIC_Init(&NVIC_InitStruct); 
    
}

这里要多提一句的是ADC1的偏移地址,大家可以参考中文数据手册,里面有详细写了每一个外设的偏移地址,ADC1的偏移地址是0X4C。

还有一个就是存放数据的内存地址了,static u16 Run_Voltage[ADC_Channel_MAX];

#ifndef __RUN_VOLTAGE__H_
#define __RUN_VOLTAGE__H_
#include "common.h"
#include "Mygpio.h"
#include "Tasking.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_adc.h"

#define ADC_Voltage     ((u32)ADC1+0x4C)


typedef enum
{
    PA0_ADC_Voltage,     //引脚PA0
    PA1_ADC_Voltage,     //引脚PA1
    PA2_ADC_Voltage,     //引脚PA2
    PA3_ADC_Voltage,     //引脚PA3
    PA4_ADC_Voltage,     //引脚PA4
    PA5_ADC_Voltage,     //引脚PA5
    PA6_ADC_Voltage,     //引脚PA6
    PA7_ADC_Voltage,     //引脚PA7
    
    CPU_ADC_Voltage,     //CPU温度
    ADC_Channel_MAX,
}task_ADC;




void my_ADC_GPIO_Init(void);
void my_DMA_Init(void);
void my_ADC_Init(void);
void Task_Voltage(void);

void Voltage_Process(void);   //电压采集处理
#endif

4.配置信息整理,ADC转换

void Task_Voltage(void)
{
    task_ADC Comply = (task_ADC)0;
    my_ADC_GPIO_Init();
    my_DMA_Init();
    my_ADC_Init();    
    for(Comply = (task_ADC)0; Comply< ADC_Channel_MAX; Comply++)
    {
         ADC_RegularChannelConfig(ADC1, Adc_Channel_ID[Comply], Comply+1 ,ADC_SampleTime_480Cycles);        
    }   
    //在最后一次传输后启用或禁用 ADC DMA 请求(单 ADC 模式)
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);   
    ADC_DMACmd(ADC1, ENABLE);          //使能ADC DMA  
    ADC_Cmd(ADC1, ENABLE);
    ADC_SoftwareStartConv(ADC1);       //开始传输
    
    My_Add_task(LY_VOLTAGE_Run,Voltage_Process, 200, 8);        //设置执行系统运行ADC采集任务
}






void DMA2_Stream0_IRQHandler(void)
{
    u8 temp = 0, j = 0;
    if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) == ENABLE)
    {
        for(temp = 0 ;temp < ADC_Channel_MAX; temp++)
        {
            for(j = 0; j < ADC_Channel_MAX; j++)
            {
                ADC_Converter[temp][j]=Run_Voltage[temp];               
            }           
        }
    }  
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
}


总结

配置成功的话,ADC1每一次转换都会到DMA2中断当中,中断当中把传输到自己的内存当中在取出来,在做后面的操作处理。至于要怎么处理这份数据,就看项目的要求了。

大家有什么疑问的话,可以评论区留言哦。

### 回答1: STM32F407ADC DMA FFT是一种基于STM32F407芯片的数字信号处理技术,主要用于实现高速数据采集、处理和分析。其中,ADC代表模拟数字转换器,DMA代表直接存储器访问,FFT代表快速傅里叶变换。通过将这些技术结合起来,可以实现高效的数据采集和处理,从而满足各种应用场景的需求。 ### 回答2: STM32F407ADCDMA模块是这一系列微控制器中最先进的部分之一。ADC是用于从模拟输入信号中读取数据的模块,而DMA则是一种用于高速数据传输的技术。对于实现实时信号处理的应用程序来说,有一个FFT(快速傅里叶变换)模块非常有用。FFT可以将模拟信号转换为其在频域内的表示,这是许多应用程序所必需的。 在STM32F407中,ADCDMA可以结合使用,以实现高速的数据读取和传输。通过使用DMA,可以让CPU完成其他任务,而ADCDMA模块则将数据直接传输到内存中,从而免去了CPU的干预。这可以极大地提高系统的效率。 当然,FFT模块也可以与ADCDMA结合使用使用FFT算法可以对模拟信号进行处理,以提取其在不同频率上的成分。但是,FFT的计算需要大量的计算能力和内存空间。因此,对于STM32F407这样的嵌入式系统来说,需要使用高效的FFT库和优化的算法。 总之,STM32F407ADCDMA和FFT模块可以协同工作,以实现高速数据采集传输和处理。这使得这种微控制器非常适合于实现实时信号处理的应用程序。同时,需要注意的是,这一系列模块的使用需要仔细的设计和实现,以保证系统的稳定性和可靠性。 ### 回答3: STM32F407是一款基于ARM Cortex-M4内核的微控制器,具有丰富的外设和高性能。其中包括ADC(模拟-数字转换器)和DMA(直接存储器访问)模块。 ADC模块可以将模拟信号转换为数字信号,用于数据采集DMA模块可以直接将采集到的数据存储到内存中,减少了CPU的负担。FFT(快速傅立叶变换)是一种数字信号处理算法,用于将时域信号转换为频域信号,常用于音频处理、图像处理、通信等领域。 在STM32F407上,通过ADCDMA和FFT模块结合使用,可以实现实时的数据采集和处理。首先,ADC模块将模拟信号转换为数字信号,DMA模块将采集到的数据存储到内存中,FFT模块对存储的数据进行处理,获得频域信息。这些信息可以用于进行频谱分析、滤波、信噪比评估等。 在具体的应用中,可以使用不同的采样率、精度、采样通道数等参数进行调节,以满足不同的需求。此外,STM32F407的灵活性和可编程性,使得开发者可以自定义算法、优化代码,进一步提高系统的性能和效率。 总之,STM32F407ADC DMA FFT的组合,为实时信号采集和处理提供了高效、可靠的解决方案。通过合理地配置参数和算法,可以应用于各种领域,为我们的生产和生活带来便利和效益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

留不住王哪跑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值