这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » NUCLEO-U083RC学习历程29-连续模式读取ADC数值

共5条 1/1 1 跳转至

NUCLEO-U083RC学习历程29-连续模式读取ADC数值

助工
2025-02-16 13:54:11     打赏

今天分享一下STM32读取ADC数据时使用连续模式,介绍几种方案和注意事项;

    STM32微控制器的ADC(模数转换器)模块支持多种转换模式,其中连续转换模式是常用的一种。在该模式下,ADC会自动连续进行转换,无需每次手动触发。以下是对STM32 ADC连续转换功能的详细讲解:

一. ADC连续转换模式概述:

连续转换模式:在该模式下,ADC会不断进行转换,一旦完成一次转换,立即开始下一次转换,无需外部触发。我们在软件上处理时候,只需要清除 ADC_FLAG_EOC的标志位即可。

适用场景:适用于需要持续采集模拟信号的场景,如实时监控电压、温度等。

二:STM32cube MX的软件配置:

0216-3.png

如上图所示:需要在图形化配置软件中,将连续采集模式打开。

三:具体和大家分享一下STM32 ADC的连续采集模式下的基本步骤和软件编写方法:

3.1 启动ADC的时钟

我们需要确定当前使用的ADC通道,例如:本次使用,使用ADC1我们通过RCC寄存器启动相对应的时钟

    /* Peripheral clock enable */
    __HAL_RCC_ADC_CLK_ENABLE();

3.2  配置所使用的ADC的引脚功能

这里我们使用的是PA4引脚:这里需要注意下,将ADC使用的引脚设置为输入模式,否则无法正常读取到ADC的数值

    /**ADC1 GPIO Configuration
    PA4     ------> ADC1_IN8
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

3.3 初始化ADC的一些参数:

例如配置ADC的工作模式:包括分辨率、数据对齐方式、扫描模式、触发模式、ADC外设时钟等等;

  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_79CYCLES_5;
  hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
  hadc1.Init.OversamplingMode = DISABLE;
  hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

3.4 配置ADC通道

这里需要将外部引脚和ADC通道对应好

  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

3.5 启动连续转换模式:

    if (HAL_ADC_PollForConversion(&hadc1, 10) != HAL_OK)
    {
      /* End Of Conversion flag not set on time */
      Error_Handler();
    }

3.6 读取转换的结果

在连续转换模式下,ADC会不断更新数据寄存器,我们可以通过以下读取转换的结果

uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
{
  /* Check the parameters */
  assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));

  /* Note: EOC flag is not cleared here by software because automatically     */
  /*       cleared by hardware when reading register DR.                      */

  /* Return ADC converted value */
  return hadc->Instance->DR;
}

几个重要代码如下:

使能ADC1自动校准功能、开启ADC自动转化模式、等待ADC的连续开启模式

  /* Perform ADC calibration */
  if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
  {
    /* Calibration Error */
    Error_Handler();
  }
    /* Start ADC group regular conversion */
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
      /* ADC conversion start error */
      Error_Handler();
    }
    /* Wait for ADC conversion completed */
    if (HAL_ADC_PollForConversion(&hadc1, 10) != HAL_OK)
    {
      /* End Of Conversion flag not set on time */
      Error_Handler();
    }

主代码程序如下:

    /* Retrieve ADC conversion data */
    uhADCxConvertedData = HAL_ADC_GetValue(&hadc1);

    /* Computation of ADC conversions raw data to physical values             */
    /* using helper macro.                                                    */
    uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B);

    /* Toggle LED at each ADC conversion data retrieved */
    BSP_LED_On(LED4);
    HAL_Delay(LED_BLINK_SLOW);
    BSP_LED_Off(LED4);
    HAL_Delay(LED_BLINK_SLOW);

    /* For this example purpose, check that conversion data has been updated
       using flag ADC group regular end of unitary conversion */
    if(__HAL_ADC_GET_FLAG(&hadc1, ADC_FLAG_EOC) == 0)
    {
      Error_Handler();
    }
    __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC);

主程序执行过程如下:从主程序执行开始,ADC 软件启动执行一次,ADC 组定期自动、无限期地连续执行所选通道的转换。软件会轮询第一次转化完成,然后随意检索(在本例中为每秒一次)转化数据。

程序仿真效果如下:

0216-4.png

实物如下:

0216-5.png

四:其他方案读取ADC数值

中断:可以启用ADC转换完成中断,在每次转换完成后触发中断处理。

DMA:在连续转换模式下,结合DMA可以自动将转换结果传输到指定内存区域,减少CPU负担。

4.1 中断配置

启用ADC转换完成中断

ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);  // 启用转换完成中断
NVIC_EnableIRQ(ADC1_IRQn);  // 启用ADC中断

在中断服务程序中读取数据

void ADC1_IRQHandler(void) {
    if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) {
        uint16_t adc_value = ADC_GetConversionValue(ADC1);
        // 处理ADC数据
        ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);  // 清除中断标志
    }
}

4.2 DMA配置如下:

启动DMA自动传输数据,为CPU减轻负担

DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&adc_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  // 循环模式
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);  // 启用ADC DMA请求

在编写ADC通道时,需要注意以下几个方面:

采样时间:根据信号特性选择合适的采样时间,避免信号失真。

参考电压:确保参考电压稳定,以获得准确的转换结果。

噪声抑制:在高速连续转换时,注意电源和信号噪声的影响。

通过上述几种,不同的配置,STM32的ADC可以在连续模式下工作,满足用户实时读取采集数据的需求。





关键词: NUCLEO-U083RC     连续模式     自动转换数据    

专家
2025-02-16 19:59:22     打赏
2楼

感谢分享


专家
2025-02-16 20:02:07     打赏
3楼

感谢分享


专家
2025-02-16 20:07:24     打赏
4楼

感谢分享


专家
2025-02-18 09:05:33     打赏
5楼

感谢分享


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]