STM32 ADC和DMA

STM32 ADC和DMA简单总结

1.简介

使用野火开发板F429IGT6

ADC框图

image-20220702105713458

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hcRJQP6A-1656898707918)(https://raw.githubusercontent.com/Master-4869/pictures/main/image-20220702105905661.png)]

ADC主要的选项配置有

  • 时钟的分频配置,这个决定了ADC的时钟速度,
  • 采样时钟数量,采样的时间长一点会更准,整个一个采样的周期是采样时间加上转换时间,如果使用12位的就需要加上12个时钟的转换时间,这样3个采样时间加上12个转换时间,整个采样周期就是15个周期
  • 数据对齐的方式为左对齐还是右对齐,因为数据寄存器的宽度是16位的,采样的精度只能12位
  • 扫描模式是同一个ADC开启多个通道,是否要轮流转换每个通道
  • 连续采样是ADC是否要一直采样转换还是触发一次就停止转换
  • EOC是转换结束标志
  • 可以配置ADC的触发是软件触发还是硬件触发
  • rank可以配置各个通道的转换先后顺序
  • ADC可以分为规则转换通道和注入转换通道,一般用的就是规则转换通道

ADC还可以配置为多重采样的模式,一共有3个ADC,可以轮流来采样转换同一个通道,这样在第一个ADC转换的时候第二个可以紧接着采样,可以提升ADC的采样率。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2GFsNAoN-1656898707918)(https://raw.githubusercontent.com/Master-4869/pictures/main/image-20220702111226199.png)]

将3个ADC的相同通道选中,在ADC1的模式中选择三重采样。配置DMA以ADC1为主,其他ADC不需要配置,每个ADC都要打开循环检测模式。

image-20220702111709462

image-20220702111817887

DMA的配置主要有

  • 数据传输的方向,分为存储器到存储器,外设到存储器,存储器到外设
  • 传输的模式是循环传输还是只传输一次
  • 传输数据的宽度
  • 传输时外设寄存器的地址和存储器的地址要不要递增,注意每次递增的地址的大小是和设置的数据宽度相同的

如果使用FIFO的话可以设置突发模式等

2.代码

使用cubemx6.6.0

MDK5.34

2.1多通道DMA

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    adc.c
  * @brief   This file provides code for the configuration
  *          of the ADC instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "adc.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

/* ADC1 init function */
void MX_ADC1_Init(void)
{
   
   

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {
   
   0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 3;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
   
   
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_13;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
   
   
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
   
   
    Error_Handler();
  }

  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
   
   
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
  /* USER CODE END ADC1_Init 2 */

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
   
   

  GPIO_InitTypeDef GPIO_InitStruct = {
   
   0};
  if(adcHandle->Instance==ADC1)
  {
   
   
  /* USER CODE BEGIN ADC1_MspInit 0 */

  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PC3     ------> ADC1_IN13
    PA4     ------> ADC1_IN4
    PA6     ------> ADC1_IN6
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* ADC1 DMA Init */
    /* ADC1 Init */
    hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
   
   
      Error_Handler();
    }

    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);

  /* USER CODE BEGIN ADC1_MspInit 1 */
	
  /* USER CODE END ADC1_MspInit 1 */
  }
}

void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
   
   

  if(adcHandle->Instance==ADC1)
  {
   
   
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();

    /**ADC1 GPIO Configuration
    PC3     ------> ADC1_IN13
    PA4     ------> ADC1_IN4
    PA6     ------> ADC1_IN6
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_3);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_6);

    /* ADC1 DMA DeInit */
    HAL_DMA_DeInit(adcHandle->DMA_Handle);
  /* USER CODE BEGIN ADC1_MspDeInit 1 */

  /* USER CODE END ADC1_MspDeInit 1 */
### STM32 ADCDMA结合使用的教程 #### 初始化ADC 为了使STM32能够利用其内置的模数转换器(ADC),并借助直接存储器访问(DMA)来提高效率,初始化过程至关重要。在此阶段,需指定采样时间、分辨率以及外部触发源等参数[^1]。 ```c // 配置ADC结构体 static void MX_ADC_Init(void) { ADC_ChannelConfTypeDef sConfig = {0}; hadc.Instance = ADC1; // 设置ADC模式其他高级配置选项... } ``` #### 配置DMA 紧接着,在完成ADC的基础设定之后,应着手准备DMA控制器。这一步骤涉及定义数据传输的方向是从外设到内存还是相反方向;同时也要指明缓冲区大小及地址增量模式等内容。 ```c // DMA配置函数片段 hdma_adc.Instance = DMA1_Channel1; hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc.Init.MemInc = DMA_MINC_ENABLE; HAL_DMA_Init(&hdma_adc); __HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc); // 将DMA关联至ADC ``` #### 启动DMA传输 一旦上述准备工作就绪,则可通过调用特定API接口开启一次性的或连续循环式的DMA操作。对于后者而言,每当一轮完整的读取周期结束时,会自动重新装载起始位置从而维持不间断的数据流输入。 ```c if (HAL_ADC_Start_IT(&hadc) != HAL_OK){ Error_Handler(); } if(HAL_DMA_Start (&hdma_adc,(uint32_t)&(ADCx->DR),(uint32_t)aVoltageBuffer,BUFFER_SIZE)!= HAL_OK){ /* Start Transfer error */ Error_Handler (); } ``` #### 中断处理(可选) 虽然并非强制要求,但在某些应用场景下可能希望当每次DMA事务完成后接收到通知以便立即响应新到达的信息。此时便可以通过注册相应的回调机制达成目的。 ```c void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance==ADC1) { // 处理DMA传输完毕后的逻辑 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值