STM32ADC多通道DMA读取

程序给出了3种ADC读取方式,单通道,DMA单通道和DMA多通道,下面是ADC.h文件:
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "delay.h"

//-------------单通道 ADC读取----------------
void Adc_Init(void);
u16 get_ADC_Values(u8 ch,u8 rank);
u16 get_ADC_Average(u8 ch,u8 rank,u8 count);

//-------------单通道 ADC DMA读取----------------
void ADC_DMA_Init(void);
u16 get_ADC_DMA_Average(u8 count);

//-------------多通道 ADC DMA读取----------------
void ADC_DMA_Multichannel_Init(u32 ADC_Buff); 

#endif


ADC.c实现上面定义的函数:
#include "adc.h"
//单通道 DMA adc数据
volatile u16 adc_values;

//-------------单通道 ADC读取----------------
void Adc_Init() {
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6 = 12MHz
    //ADC1通道11的转换时间为T=(239.5+12.5) x 1/12=21us。

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);



    ADC_DeInit(ADC1);//复位ADC1
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC 独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;//单次扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次转换模式
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;//ADC1 和ADC2 工作在同步规则模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1 ;//进行规则转换的ADC通道数量
    ADC_Init(ADC1, &ADC_InitStructure);//初始化ADC1


    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);//开启复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准成功
    ADC_StartCalibration(ADC1);//开始校验ADC1
    while(ADC_GetCalibrationStatus(ADC1));//等待校验成功

}

u16 get_ADC_Values(u8 ch, u8 rank) {

    //设置指定ADC规则通道,设置转换时间
    ADC_RegularChannelConfig(ADC1, ch, rank, ADC_SampleTime_239Cycles5);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //开启软件转换
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待转换结束
    return 	ADC_GetConversionValue(ADC1);
}


//返回ADC平均值
u16 get_ADC_Average(u8 ch, u8 rank, u8 count) {
    u32 temp_val = 0;
    u8 i;

    for(i = 0; i < count; i++) {
        temp_val += get_ADC_Values(ch, rank);
        delay_ms(5);
    }
    return temp_val / count;

}


//-------------单通道 ADC DMA读取----------------
void ADC_DMA_Init() {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
	
    //使能DMA1时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);      
  
		//初始化IO 
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;        
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;  
    GPIO_Init(GPIOA,&GPIO_InitStructure);  

    //复位DMA1 通道1 ADC
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//ADC内存基地址
    DMA_InitStructure.DMA_MemoryBaseAddr  = (u32)&adc_values;//变量基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设到内存
    DMA_InitStructure.DMA_BufferSize = 1;//数据宽度
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设内存地址不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//变量内存地址不变
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//16字节 12位ADC
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//16字节
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//关闭内存到内存传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA1 通道1
    DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA 通道1

    ADC_DeInit(ADC1);//复位ADC1
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //关闭扫描
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换 触发一次 持续转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发转换
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 1;//转换一个通道
    ADC_Init(ADC1, &ADC_InitStructure);//初始化ADC
		//ADC时钟 不能大于14MHz
		RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6 = 12MHz 
		//设置指定ADC规则通道,设置转换时间
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
    //使能ADC DMA
		ADC_DMACmd(ADC1, ENABLE);
		//使能ADC
    ADC_Cmd(ADC1, ENABLE);
		
		ADC_ResetCalibration(ADC1);//复位校准寄存器  
    while(ADC_GetResetCalibrationStatus(ADC1));//等待校准寄存器复位完成  
  
    ADC_StartCalibration(ADC1);//ADC校准  
    while(ADC_GetCalibrationStatus(ADC1));//等待校准完成  
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//由于没有采用外部触发,所以使用软件触发ADC转换 
		
}
//返回ADC平均值
u16 get_ADC_DMA_Average(u8 count) {
    u32 temp_val = 0;
    u8 i;

    for(i = 0; i < count; i++) {
        temp_val += adc_values;
        delay_ms(5);
    }
    return temp_val / count;

}
//-------------多通道 ADC DMA读取----------------
void ADC_DMA_Multichannel_Init(u32 ADC_Buff) {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
	
    //使能DMA1时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);      
  
		//初始化IO 
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;        
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;  
    GPIO_Init(GPIOA,&GPIO_InitStructure);  

    //复位DMA1 通道1 ADC
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//ADC内存基地址
    DMA_InitStructure.DMA_MemoryBaseAddr  = ADC_Buff;//变量基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设到内存
    DMA_InitStructure.DMA_BufferSize = 3;//数据宽度
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设内存地址不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//变量内存地址增长
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//16字节 12位ADC
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//16字节
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//关闭内存到内存传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA1 通道1
    DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA 通道1

    ADC_DeInit(ADC1);//复位ADC1
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE; //开启扫描 多通道读取 
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换 触发一次 持续转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发转换
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 3;//转换3个通道
    ADC_Init(ADC1, &ADC_InitStructure);//初始化ADC
		
		//ADC时钟 不能大于14MHz
		RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6 = 12MHz 
		//设置指定ADC规则通道,设置转换时间
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
		ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_239Cycles5);
		ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_239Cycles5);
    //使能ADC DMA
		ADC_DMACmd(ADC1, ENABLE);
		//使能ADC
    ADC_Cmd(ADC1, ENABLE);
		
		ADC_ResetCalibration(ADC1);//复位校准寄存器  
    while(ADC_GetResetCalibrationStatus(ADC1));//等待校准寄存器复位完成  
  
    ADC_StartCalibration(ADC1);//ADC校准  
    while(ADC_GetCalibrationStatus(ADC1));//等待校准完成  
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//由于没有采用外部触发,所以使用软件触发ADC转换 
		
}


主函数调用:

#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "string.h"
#include "usart.h"
#include "adc.h"




//3个通道ADC值
u16 ADC_BUFF[3];

int main(void)
{
    u16 tep_val;
    float adc_v;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    delay_init();
    //初始化串口IO
    uart_init(115200);
		//单通道ADC DMA初始化
//      ADC_DMA_Init(); 
	//-------------多通道 ADC DMA读取----------------
    ADC_DMA_Multichannel_Init((u32)ADC_BUFF);
    while(1)
    {
				//-------------单通道 ADC DMA读取----------------
			//ADC通道1 获取10次取平均值
//				tep_val = get_ADC_DMA_Average(10);
//        adc_v	= (float)tep_val * (3.3 / 4096);
//        printf("\r\nADC1 PA1 = %d\r\n", tep_val);
//        printf("ADC1 PA1 = %fV\r\n", adc_v);
				//-------------多通道 ADC DMA读取----------------
        tep_val = ADC_BUFF[0];//ADC 通道1
        adc_v	= (float)tep_val * (3.3 / 4096);
        printf("\r\nADC1 PA1 = %d\r\n", tep_val);
        printf("ADC1 PA1 = %fV\r\n", adc_v);

        tep_val = ADC_BUFF[1];//ADC 通道2
        adc_v	= (float)tep_val * (3.3 / 4096);
        printf("\r\nADC1 PA2 = %d\r\n", tep_val);
        printf("ADC1 PA2 = %fV\r\n", adc_v);


        tep_val = ADC_BUFF[2];//ADC 通道3
        adc_v	= (float)tep_val * (3.3 / 4096);
        printf("\r\nADC1 PA3 = %d\r\n", tep_val);
        printf("ADC1 PA3 = %fV\r\n", adc_v);

       delay_ms(500);

    }
}





### 回答1: STM32系列微控制器具有多通道ADC(模数转换器)和DMA(直接内存访问)功能。ADC是用于将模拟信号转换成数字信号的模块,而DMA是用于高效地在外设和内存之间传输数据的模块。 多通道ADC意味着STM32微控制器可以同时接收多个模拟信号并进行转换。例如,一款具有8个通道的STM32微控制器可以同时处理8个不同的模拟信号。每个通道都有一个独立的ADC转换器,因此可以同时对多个信号进行采样和转换。 为了提高效率和性能,STM32微控制器还配备了DMA功能。DMA可以在处理ADC数据转换时,直接将转换数据传输到内存中,而无需CPU的干预。这样可以减少CPU处理数据的负担,提高系统的响应能力。 使用DMA进行ADC转换时,需要配置DMA通道和相关的内存地址。然后,当ADC完成一次数据转换后,DMA将自动激活并将转换结果传输到指定的内存地址。这样,CPU可以继续执行其他任务,而不需等待ADC转换完成和数据传输。 因此,STM32多通道ADCDMA功能可以帮助我们实现高效的模拟信号采集和数据处理。无论是工业控制、传感器应用还是数据采集,都可以利用这些功能实现高性能和快速的数据转换与传输。同时通过合理的配置和使用,可以更好地提高系统效率和响应能力,为我们的应用带来更多的便利。 ### 回答2: STM32系列MCU的ADC模块具有多通道DMA功能。ADC多通道DMA是一种可以同时采集多个模拟信号并通过DMA传输到内存的方法。 首先,STM32ADC模块支持多通道采集。它有多个ADC通道,每个通道可以独立地采集一个模拟信号。多通道ADC可以在单次转换模式下按照所选择的通道顺序依次进行转换,也可以在扫描模式下连续转换多个通道,这样就可以同时采集多个信号。 其次,STM32DMA模块可用于提高ADC转换结果的传输效率。DMA即直接内存访问,它可以在不经过CPU干预的情况下,直接将ADC转换结果传输到指定的目的地,比如内存。通过使用DMA,可以减少CPU的负担,提高系统的效率。 在ADC多通道DMA的应用中,首先需要配置ADC多通道转换模式和DMA的相关参数。可以选择单次转换模式或连续转换模式,并设置多个通道的转换顺序。然后配置DMA通道,指定源地址为ADC的数据寄存器,目的地址为内存的指定位置,并设置数据长度和传输方向。最后,启动ADC转换和DMA传输,ADC会按照设定的通道顺序逐一进行转换,转换结果会通过DMA直接传输到指定的内存地址。 通过使用ADC多通道DMA,可以方便地同时采集多个模拟信号,并高效地将转换结果传输到内存,从而提高了系统的性能和效率。 ### 回答3: STM32系列的MCU具备多通道ADC功能,并且可以利用DMA(直接内存访问)来实现高效率的数据传输。 首先,ADC(模数转换器)是一种用于将模拟信号转换为数字信号的电子设备。STM32ADC模块支持多通道,这意味着可以同时对多个模拟输入信号进行转换。 而DMA是一种无需CPU干预的数据传输方式,利用DMA可以实现高速、高效的数据传输。在STM32的MCU中,DMA可以与ADC模块配合使用,实现从ADC转换结果缓冲区自动传输到指定的内存区域,无需CPU的介入。 具体实现方法如下: 1. 配置ADC模块的多通道扫描模式:通过设置ADC模块的控制寄存器,选择需要转换的通道数量,并设置扫描顺序。扫描模式可以使ADC连续地转换多个通道的模拟输入信号。 2. 配置DMA传输:通过设置DMA控制器的寄存器,配置DMA通道和传输方向(从ADC读取数据到内存)。同时设置DMA的数据宽度、传输大小和传输完成后的中断等参数。 3. 启动ADCDMA:通过设置ADCDMA的控制位,启动ADC模块和DMA传输。ADC开始按照设置的通道顺序进行连续转换,转换结果会自动传输到DMA的缓冲区。 4. 等待转换完成:可以通过DMA的传输完成中断来判断数据传输是否完成。一旦传输完成,可以读取DMA缓冲区内的数据,即为ADC转换的结果。 通过以上步骤,可以实现STM32 MCU的多通道ADC模块与DMA的协同工作。这种方式可以大大提高数据传输效率和系统性能。在实际应用中,可以根据需求进行相应的配置和优化,以满足具体的应用要求。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值