You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F7 Discovery开发板ADC3多通道中断读取问题求助

解决STM32F7 Discovery ADC3多通道中断读取问题

Hey there! Let's work through how to read multiple ADC3 channels using interrupts on your STM32F7 Discovery board—no DMA needed, just like you want.

核心思路

When you configure ADC in scan mode, it converts channels in the order you set up. By enabling single-conversion EOC interrupts, each channel's conversion will trigger an interrupt callback. We'll track which channel we're on, store each result in an array, and cycle through the channels as conversions complete.

Step 1: Define Variables to Track Results & Channel Index

First, set up storage for your ADC readings and a variable to keep track of the current channel being converted:

#define ADC_NUM_CHANNELS 3  // Adjust this to match your number of channels
uint16_t adc_channel_results[ADC_NUM_CHANNELS];  // Stores results for each channel
static uint8_t current_adc_channel = 0;          // Tracks the current channel index

Step 2: Configure ADC3 Correctly

Make sure your ADC init enables scan mode, single-conversion EOC triggers, and disables DMA. Here's a sample HAL config:

ADC_HandleTypeDef hadc3;

void MX_ADC3_Init(void)
{
  hadc3.Instance = ADC3;
  hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc3.Init.Resolution = ADC_RESOLUTION_12B;
  hadc3.Init.ScanConvMode = ENABLE;  // Critical: enables multi-channel scanning
  hadc3.Init.ContinuousConvMode = ENABLE;  // Keep scanning channels non-stop
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;  // Software trigger
  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc3.Init.NbrOfConversion = ADC_NUM_CHANNELS;  // Match your channel count
  hadc3.Init.DMAContinuousRequests = DISABLE;  // We're not using DMA
  hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;  // Trigger EOC after each channel
  if (HAL_ADC_Init(&hadc3) != HAL_OK)
  {
    Error_Handler();
  }

  // Configure your channels in order (Rank 1 = first converted, Rank 2 = second, etc.)
  ADC_ChannelConfTypeDef sConfig = {0};
  
  // Example: Channel 0, Rank 1
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  // Example: Channel 1, Rank 2
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  // Example: Channel 2, Rank 3
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

Step 3: Enable NVIC & Start ADC Interrupt Conversion

Don't forget to enable the ADC interrupt in NVIC and start the ADC in interrupt mode:

// In your main function or init code
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);  // Adjust priority as needed
HAL_NVIC_EnableIRQ(ADC_IRQn);

HAL_ADC_Start_IT(&hadc3);  // Start ADC conversion with interrupts

Step 4: Implement the ADC Interrupt Callback

This is where you'll read each channel's result and store it. The callback triggers every time a single channel conversion finishes:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance == ADC3)
  {
    // Read the current channel's conversion result
    adc_channel_results[current_adc_channel] = HAL_ADC_GetValue(hadc);
    
    // Move to the next channel (loop back to start when all are done)
    current_adc_channel++;
    if(current_adc_channel >= ADC_NUM_CHANNELS)
    {
      current_adc_channel = 0;
      // Optional: Add code here to run when all channels are converted
      // Like printing results or processing data:
      // printf("Ch0: %d | Ch1: %d | Ch2: %d\r\n", adc_channel_results[0], adc_channel_results[1], adc_channel_results[2]);
    }

    // If you disabled ContinuousConvMode, uncomment this to restart the sequence:
    // HAL_ADC_Start_IT(&hadc3);
  }
}

Step 5: Add the ADC IRQ Handler

Make sure the hardware IRQ handler calls HAL's helper function:

void ADC_IRQHandler(void)
{
  HAL_ADC_IRQHandler(&hadc3);
}

Key Notes to Remember

  • EOC Selection: Setting EOCSelection = ADC_EOC_SINGLE_CONV is crucial—it ensures each channel triggers an interrupt, not just the end of the entire sequence. If you use ADC_EOC_SEQ_CONV, you'll only get the last channel's data.
  • Channel Order: The Rank parameter in channel config determines the conversion order. Rank 1 is first, so it maps to adc_channel_results[0], Rank 2 to [1], etc. Keep these aligned!
  • Continuous vs Single Mode: If you don't want non-stop scanning, disable ContinuousConvMode and add HAL_ADC_Start_IT(&hadc3) at the end of the callback to restart the sequence manually.

内容的提问来源于stack exchange,提问作者vera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:31:03