How to Use ADC with Interrupt in Embedded C
To use
ADC with interrupt in embedded C, configure the ADC module and enable its interrupt, then write an ISR (Interrupt Service Routine) to handle the conversion complete event. This allows the CPU to do other tasks while the ADC conversion runs and processes the result only when ready.Syntax
The basic steps to use ADC with interrupt are:
- Initialize ADC hardware and configure input channel.
- Enable ADC interrupt in the interrupt controller.
- Start ADC conversion.
- Write an ISR to handle the ADC conversion complete event.
Each part ensures the ADC runs and signals the CPU when data is ready.
c
void ADC_Init(void) { // Configure ADC input channel and settings ADC_CONTROL_REGISTER = ADC_ENABLE | ADC_INTERRUPT_ENABLE; } void ADC_StartConversion(void) { ADC_CONTROL_REGISTER |= ADC_START_CONVERSION; } void ADC_IRQHandler(void) { if (ADC_INTERRUPT_FLAG) { int result = ADC_DATA_REGISTER; // Read ADC result ADC_INTERRUPT_FLAG = 0; // Clear interrupt flag // Process result here } }
Example
This example shows how to initialize the ADC, enable its interrupt, start a conversion, and handle the result in the ISR.
c
#include <stdint.h> #include <stdbool.h> #define ADC_ENABLE (1 << 0) #define ADC_INTERRUPT_ENABLE (1 << 1) #define ADC_START_CONVERSION (1 << 2) #define ADC_INTERRUPT_FLAG (1 << 0) volatile uint16_t ADC_DATA_REGISTER = 0; volatile uint8_t ADC_CONTROL_REGISTER = 0; volatile uint8_t ADC_STATUS_REGISTER = 0; volatile bool adc_conversion_done = false; volatile uint16_t adc_result = 0; void ADC_Init(void) { // Enable ADC and its interrupt ADC_CONTROL_REGISTER = ADC_ENABLE | ADC_INTERRUPT_ENABLE; } void ADC_StartConversion(void) { // Start ADC conversion ADC_CONTROL_REGISTER |= ADC_START_CONVERSION; } // Simulated ISR called when ADC conversion completes void ADC_IRQHandler(void) { if (ADC_STATUS_REGISTER & ADC_INTERRUPT_FLAG) { adc_result = ADC_DATA_REGISTER; // Read ADC result ADC_STATUS_REGISTER &= ~ADC_INTERRUPT_FLAG; // Clear interrupt flag adc_conversion_done = true; } } int main(void) { ADC_Init(); ADC_StartConversion(); // Wait for ADC conversion to complete while (!adc_conversion_done) { // CPU can do other tasks here } // Use adc_result as needed // For demonstration, just loop here while (1) {} return 0; }
Output
No console output; adc_result holds the ADC value after interrupt
Common Pitfalls
- Forgetting to enable the ADC interrupt in both ADC and interrupt controller.
- Not clearing the ADC interrupt flag inside the ISR, causing repeated interrupts.
- Starting a new ADC conversion before the previous one finishes.
- Accessing ADC result outside the ISR without synchronization, leading to inconsistent data.
c
/* Wrong: Not clearing interrupt flag */ void ADC_IRQHandler(void) { int result = ADC_DATA_REGISTER; // Missing: ADC_INTERRUPT_FLAG = 0; leads to repeated interrupts } /* Correct: Clear interrupt flag */ void ADC_IRQHandler(void) { int result = ADC_DATA_REGISTER; ADC_INTERRUPT_FLAG = 0; // Clear flag to stop interrupt }
Quick Reference
| Step | Description |
|---|---|
| Initialize ADC | Set ADC input channel and enable ADC module |
| Enable Interrupt | Turn on ADC interrupt in ADC and NVIC/interrupt controller |
| Start Conversion | Trigger ADC to start converting analog signal |
| ISR Handling | Write ISR to read ADC result and clear interrupt flag |
| Use Result | Process ADC data safely after interrupt signals completion |
Key Takeaways
Enable ADC and its interrupt before starting conversion to get interrupt-driven results.
Always clear the ADC interrupt flag inside the ISR to avoid repeated interrupts.
Use the ISR to read ADC data and signal main code when conversion is done.
Do not start a new ADC conversion until the previous one finishes and ISR runs.
Keep main code responsive by handling ADC results only when interrupt signals completion.