📖 Scenario: You are programming a simple embedded system that counts button presses using an interrupt service routine (ISR). The main program reads the count and displays it.
🎯 Goal: Learn how to declare and use a volatile variable to safely share data between the ISR and the main program.
📋 What You'll Learn
Create a global variable button_press_count to store the number of button presses.
Declare button_press_count as volatile.
Write an ISR function button_isr that increments button_press_count.
In the main function, read and print the value of button_press_count.
💡 Why This Matters
🌍 Real World
Embedded systems often use interrupts to respond quickly to hardware events like button presses. Using <code>volatile</code> ensures the main program sees the latest data changed by interrupts.
💼 Career
Understanding <code>volatile</code> and ISR interaction is essential for embedded software engineers working on microcontrollers and real-time systems.
Progress0 / 4 steps
1
Create a global variable for button press count
Create a global variable called button_press_count of type int and initialize it to 0.
Embedded C
Hint
Use the keyword volatile before int to tell the compiler this variable can change unexpectedly.
2
Write the ISR to increment the count
Write a function called button_isr with no parameters and void return type. Inside it, increment the button_press_count variable by 1.
Embedded C
Hint
The ISR function should have void return type and no parameters. Use button_press_count++; to add one.
3
Read the volatile variable in main
Write the main function with int return type and no parameters. Inside it, declare an int variable called count_snapshot and assign it the value of button_press_count.
Embedded C
Hint
In main, create count_snapshot and set it equal to button_press_count.
4
Print the button press count
Add a printf statement inside main to print the text "Button presses: " followed by the value of count_snapshot and a newline.
Embedded C
Hint
Use printf("Button presses: %d\n", count_snapshot); to display the count.
Practice
(1/5)
1. Why should a variable shared between an ISR (Interrupt Service Routine) and the main program be declared volatile?
easy
A. To allocate extra memory for the variable.
B. To tell the compiler the variable can change unexpectedly and prevent optimization errors.
C. To make the variable constant and unchangeable.
D. To speed up the program by caching the variable.
Solution
Step 1: Understand the role of volatile
The volatile keyword tells the compiler that the variable's value can change at any time, outside the normal program flow.
Step 2: Apply to ISR context
Since ISRs can change variables asynchronously, the compiler must always read the variable fresh, not use cached values.
Final Answer:
To tell the compiler the variable can change unexpectedly and prevent optimization errors. -> Option B
Quick Check:
Volatile prevents optimization errors in ISR variables = C [OK]
Hint: Volatile means 'may change anytime' to compiler [OK]
Common Mistakes:
Thinking volatile makes variable constant
Assuming volatile allocates more memory
Believing volatile speeds up code
2. Which of the following is the correct way to declare a variable flag that is modified inside an ISR?
easy
A. const int flag;
B. int flag;
C. volatile int flag;
D. static int flag;
Solution
Step 1: Identify the need for volatile
Since flag is changed inside an ISR, it must be declared volatile to prevent compiler optimizations.
Step 2: Check declaration syntax
The correct syntax is volatile int flag; which tells the compiler to always read the variable fresh.
Final Answer:
volatile int flag; -> Option C
Quick Check:
ISR-modified variable needs volatile keyword = A [OK]
Hint: Use volatile before type for ISR-shared variables [OK]
Common Mistakes:
Forgetting volatile keyword
Using const which prevents changes
Using static without volatile
3. Consider this code snippet:
volatile int flag = 0;
void ISR() {
flag = 1;
}
int main() {
while(flag == 0) {
// wait for flag to change
}
return 0;
}
What will happen if flag was NOT declared volatile?
medium
A. The program will immediately exit the loop.
B. The program will crash at runtime.
C. The program will cause a compile-time error.
D. The program may loop forever because the compiler caches flag value.
Solution
Step 1: Understand compiler optimization without volatile
Without volatile, the compiler may assume flag does not change in the loop and cache its value.
Step 2: Effect on the loop
The loop condition flag == 0 may never be rechecked from memory, causing an infinite loop.
Final Answer:
The program may loop forever because the compiler caches flag value. -> Option D
Quick Check:
Missing volatile causes infinite loop due to caching = B [OK]
Hint: No volatile means compiler caches variable, causing infinite loops [OK]
Common Mistakes:
Thinking program crashes without volatile
Assuming compile error occurs
Believing loop exits immediately
4. Given this code, what is the main problem?
int flag = 0;
void ISR() {
flag = 1;
}
int main() {
while(flag == 0) {
// wait
}
return 0;
}
medium
A. flag should be declared volatile to avoid optimization issues.
B. ISR function must return a value.
C. flag should be declared as const.
D. main() should not have a while loop.
Solution
Step 1: Identify variable shared with ISR
The variable flag is modified inside the ISR and read in main.
Step 2: Check declaration for optimization safety
Since flag is shared, it must be declared volatile to prevent the compiler from caching its value.
Final Answer:
flag should be declared volatile to avoid optimization issues. -> Option A
Quick Check:
Shared ISR variable needs volatile keyword = D [OK]
5. You have a variable counter incremented inside an ISR and read in the main loop. Which of these is the best way to safely read counter in main without race conditions?
hard
A. Declare volatile int counter and disable interrupts briefly while reading it in main.
B. Declare volatile int counter and read it directly in main.
C. Declare int counter without volatile and read it directly.
D. Declare const int counter and read it in main.
Solution
Step 1: Understand volatile role
Declaring counter volatile ensures main reads fresh value, but does not prevent partial updates during read.
Step 2: Prevent race conditions
Disabling interrupts briefly while reading counter prevents ISR from changing it mid-read, avoiding inconsistent values.
Final Answer:
Declare volatile int counter and disable interrupts briefly while reading it in main. -> Option A