ISR(ADC_vect)
, we will use millis()
to implement non-blocking LED blinking so the system can handle interrupts and blink simultaneously.
// Pin Definitions
#define LED_PIN 13 // LED connected to pin 13
#define POT_PIN A0 // Potentiometer connected to analog pin A0
// Variables
volatile unsigned long blinkInterval = 1000; // Blink interval (ms), default 1000ms
volatile unsigned long lastBlinkTime = 0; // Last time the LED was toggled
volatile bool ledState = LOW; // Current LED state
volatile unsigned int adcValue = 0; // Stores the latest ADC value
void setup() {
// Configure LED pin as output
pinMode(LED_PIN, OUTPUT);
// Configure ADC for potentiometer reading
ADMUX = (1 << REFS0); // Set reference voltage to AVcc (5V)
ADMUX |= POT_PIN; // Select A0 (POT_PIN) as ADC input channel
ADCSRA = (1 << ADEN) // Enable ADC
| (1 << ADIE) // Enable ADC interrupt
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128
ADCSRA |= (1 << ADSC); // Start the first conversion
// Enable global interrupts
sei();
}
void loop() {
while (true) {
//In this loop Microcontroller is busy in monitoring and performing important tasks constantly.
}
}
// ADC Interrupt Service Routine
ISR(ADC_vect) {
unsigned long currentTime = millis();
// Read ADC value and map it to blink interval (100ms to 5000ms)
unsigned int adcValue = analogRead(A0);
blinkInterval = map(adcValue, 0, 1023, 100, 5000);
// Check if enough time has passed to toggle LED
if (currentTime - lastBlinkTime >= blinkInterval) {
lastBlinkTime = currentTime;
ledState = !ledState; // Toggle LED state
digitalWrite(LED_PIN, ledState);
}
// Start next ADC conversion
ADCSRA |= (1 << ADSC);
}
The code flows as follows
currentTime - lastBlinkTime >= blinkInterval
→ yes: toggle LEDMapping ADC Values:
map(adcValue, 0, 1023, 100, 5000)
: Maps the ADC value (0–1023) to a range of 100ms to 5000ms for the blink interval.Starts the ADC conversion:
ADCSRA |= (1 << ADSC);
ADC setup:
ADMUX = (1 << REFS0);
AVcc (5V)
by setting the REFS0
bit in the ADMUX register.ADMUX |= POT_PIN;
A0
) by setting the MUX3:0
bits in ADMUX.POT_PIN
defines the channel (e.g., 0 for A0)
.ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADEN
), enables ADC interrupts (ADIE
), and sets the ADC prescaler to 128 for a stable clock.ADCSRA |= (1 << ADSC);
ADSC
bit. The result will be available in the ADC
register after conversion.What is happening in the setup?