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_CONVis crucial—it ensures each channel triggers an interrupt, not just the end of the entire sequence. If you useADC_EOC_SEQ_CONV, you'll only get the last channel's data. - Channel Order: The
Rankparameter in channel config determines the conversion order. Rank 1 is first, so it maps toadc_channel_results[0], Rank 2 to[1], etc. Keep these aligned! - Continuous vs Single Mode: If you don't want non-stop scanning, disable
ContinuousConvModeand addHAL_ADC_Start_IT(&hadc3)at the end of the callback to restart the sequence manually.
内容的提问来源于stack exchange,提问作者vera

