STM32 ADC模块+DMA传输

一、ADC的电压采集范围
    ADC 输入范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定。我们在设计原理图的时候一般把 VSSA 和 VREF- 接地,把 VREF+ 和 VDDA 接 3V3,得到 ADC 的输入电压范围为: 0~3.3V

二、输入通道的选择

我们确定好 ADC 输入电压之后,那么电压怎么输入到 ADC?这里我们引入通道的概念, STM32 的ADC 多达 19 个通道,其中外部的 16 个通道就是框图中的 ADCx_IN0、 ADCx_IN1… ADCx_IN5。这 16 个通道对应着不同的 IO 口,具体是哪一个 IO 口可以从手册查询到。

外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16 路,注入通道最多有 4 路。

规则通道
        规则通道:顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通道,或者应该说我们用到的都是这个通道,没有什么特别要注意的可讲。
注入通道
        注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种通道。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。

三、通过ADC采集PC3引脚的电压值,并通过串口发送到串口助手中显示

首先使用到中断函数

ADC初始化代码,我们这里开启转换完成中断,也就是ADC每次转换完成之后,会产生一个中断,在中断里边要及时将转换结果取走,否则下次转换完成时会覆盖本次的转换结果。

    GPIO_InitTypeDef gpio_info;
    ADC_CommonInitTypeDef  adc_common_info;
    ADC_InitTypeDef  adc_init_info;
    NVIC_InitTypeDef  NVIC_InitStructure;
   //初始化 ADC
    //1.初始化引脚 PC3
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
    gpio_info.GPIO_Mode = GPIO_Mode_AN;
    gpio_info.GPIO_OType = GPIO_OType_PP;
    gpio_info.GPIO_Pin = GPIO_Pin_3;
    gpio_info.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio_info.GPIO_Speed = GPIO_High_Speed;
    GPIO_Init(GPIOC,&gpio_info);
    //初始化ADC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    //2.初始化ADC common
    adc_common_info.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;  //不适用DMA
    adc_common_info.ADC_Mode = ADC_Mode_Independent;  //独立模式
    adc_common_info.ADC_Prescaler = ADC_Prescaler_Div6;
    adc_common_info.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;
    ADC_CommonInit(&adc_common_info);

 //3.初始化ADC 
    //使用连续转换模式,MCU会自动进行多次转换
    adc_init_info.ADC_ContinuousConvMode = ENABLE;
    //数据右对齐
    adc_init_info.ADC_DataAlign = ADC_DataAlign_Right;
    //外部触发源
    adc_init_info.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
    //不适用外部触发源
    adc_init_info.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    //只转换PC3一个通道,所以写1
    adc_init_info.ADC_NbrOfConversion = 1;
    adc_init_info.ADC_Resolution = ADC_Resolution_12b;
    //只有一个采集通道,不用扫描
    adc_init_info.ADC_ScanConvMode = DISABLE;
    ADC_Init(ADC1,&adc_init_info);
    //4.配置转换通道
    //PC3引脚对应的是第13通道
    ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_56Cycles);
    //5.开启中断,这样当ADC转换完成之后能立即通知用户
    ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);
    
    //5.1配置中断优先级
    NVIC_InitStructure.NVIC_IRQChannel =  ADC_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    //6.使能ADC
    ADC_Cmd(ADC1,ENABLE);
    //7.开始进行转换
    ADC_SoftwareStartConv(ADC1);

四、下面我们使用定时器触发+DMA传输

1.使用定时器触发ADC采集

设置一个定时器,定时器时间到之后自动触发ADC进行一次采集,配置定时器的时间,就可以精确的控制ADC采集的间隔,ADC的触发源可以有多种,如下图黑色框所示:

这里我们使用定时器3进行触发,配置代码如下:

因为使用的是定时器触发,原来的ADC初始化参数需要修改,修改的内容如下:

adc_init_info.ADC_ContinuousConvMode = DISABLE; //因为使用定时器触发,定时器定时时间到就触发一次,所以不使用连续转换

adc_init_info.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; //外部触发源选择定时器3


ADC_ITConfig(ADC1,ADC_IT_EOC,DISABLE);  //不使用中断
//ADC_SoftwareStartConv(ADC1); //因为使用定时器触发,所以不再使用软件启动转换

2.使用DMA进行数据传输

        2.1DMA(Direct Memory Access, 直接存储区访问) 为实现数据高速在外设寄存器与存储器之间或者存储器与存储器之间传输提供了高效的方法。之所以称之为高效,是因为 DMA 传输实现高速数据移动过程无需任何 CPU 操作控制。从硬件层次上来说,DMA 控制器是独立于 Cortex-M4 内核的,有点类似 GPIO、USART 外设一般,只是 DMA 的功能是可以快速移动内存数据。

       2.2 STM32F4xx 系列资源丰富,具有两个 DMA 控制器,同时外设繁多,为实现正常传输,DMA 需要通道选择控制。每个 DMA 控制器具有 8 个数据流,每个数据流对应 8 个外设请求。在实现 DMA传输之前,DMA 控制器会通过 DMA 数据流 x 配置寄存器 DMA_SxCR(x 为 0~7,对应 8 个 DMA数据流) 的 CHSEL[2:0] 位选择对应的通道作为该数据流的目标外设。

        2.3我们需要将ADC外设的数据搬运到内存中,ADC对应的是DMA2的通道0,我们要分析声音的频率,就要采集一小段连续的声音,所以我们在内存中设置一个长度为1024的数组,让DMA将ADC转换结果搬运到这个数组中。

我们可以使用DMA传输完成中断,当DMA搬运的数据个数达到了设置的长度,会产生一个DMA传输完成中断:

void DMA2_Stream0_IRQHandler()
{
    if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0))
    {
      uint16_t i = 0;
    
      for(i=0;i<1024;i++)
      {
          printf("%d\r\n",adc_value_buf[i]);
      }
      DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
    }
}

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32 ADC DMA例程是一种使用STM32微控制器的模拟到数字转换器(ADC)和直接内存访问(DMA)功能的代码示例。该例程旨在帮助开发人员快速了解如何配置和使用ADCDMA功能来高效地采集模拟信号并将其传输到内存中。 代码示例中通常包括以下步骤: 1. 初始化ADC模块DMA模块:通过配置相关的寄存器,设置ADC通道和采样速率、分辨率等参数,同时配置DMA通道和内存地址。 2. 配置ADC触发源:选择合适的触发源,例如定时器、外部触发或软件触发。设置触发源后,ADC将在触发事件发生时启动转换。 3. 配置DMA传输:设置DMA传输方向和传输大小,选择源和目的地址等。这些设置将确保在ADC转换完成后,数据能够正确地传输到指定的内存地址。 4. 启动ADCDMA:启动ADCDMA模块,使它们开始采集和传输数据。可以通过启动ADC转换和DMA传输来触发整个过程。 5. 处理数据:在DMA传输完成后,可以在中断服务程序中访问采集到的数据。这些数据可以进行进一步的处理和分析,例如滤波、计算统计指标或用于控制其他硬件设备。 通过使用ADCDMA模块,可以实现高效的模拟信号采集,并减少CPU的负载。相比于使用中断方式来处理ADC转换,DMA可以自动将数据传输到内存中,同时允许CPU继续执行其他任务。 总之,STM32 ADC DMA例程提供了一种简单而强大的方法来配置和使用ADCDMA功能,使开发人员能够轻松实现高效的模拟信号采集和数据处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值