Understanding Arduino Interrupts | Hardware, Pin Change & Timer Interrupts
Introduction to Arduino Interrupts
Overview of Workshop
- The workshop focuses on using interrupts with the Arduino, specifically hardware pin change and timer interrupts.
- Although the session is based on the Arduino Uno, concepts are applicable to other Arduinos and microcontrollers.
- Previous discussions on interrupts were held four years ago, particularly regarding speed sensors in robot car kits.
Structure of Today's Session
- Unlike previous videos that start with an animated explainer, this session will begin directly at the workbench.
- The first demonstration involves connecting an Arduino Uno to components and writing a sketch without interrupts.
Setting Up Components
Wiring Instructions
- Required components include an Arduino Uno, a momentary contact push button switch, an LED (any color), and a dropping resistor (220 ohm recommended).
- Connections: Digital output pin 13 connects to one side of the dropping resistor; the other side connects to the LED's anode. The cathode goes to ground.
- Digital pin 2 connects to one side of the push button switch; the other side connects to ground.
Initial Sketch Without Interrupts
Code Explanation
- The initial sketch toggles an LED using a push button: pressing turns it on, releasing turns it off.
- A function named
checkSwitchreads the button status; if pressed (low), it debounces before changing toggle state.
Setup Functionality
- In
setup, pin modes for both LED (output) and button (input pull-up using internal resistors) are defined.
- The loop continuously runs
checkSwitchto monitor button status and control LED accordingly.
Testing Basic Toggle Functionality
Observations from Initial Test
- After loading code onto the board, pressing the switch successfully toggles the LED on/off as intended.
Modifying Sketch for Serial Monitor Output
Changes Made
- A modified version of the sketch includes starting a serial monitor for additional feedback during operation.
New Loop Functionality
Understanding Delays and Interrupts in Arduino Programming
Issues with Delay in Loop
- The modified code includes a delay at the end of the loop, causing the toggle switch to become non-functional during this period.
- The toggle switch only works intermittently, primarily when pressed between the start and end of the delay, indicating that delays disrupt normal operations.
- Long delays are not typical in practical applications; however, certain sensors (like DHT22) require waiting periods for readings, which can introduce unavoidable delays.
Inefficiency of Constant Checking
- Continuously checking if a switch has been pressed is inefficient, akin to a child repeatedly asking "Are we there yet?" during a long trip.
- This method leads to missed inputs as the program spends most of its time checking without effectively responding to user interactions.
Importance of Interrupt Handling
- The discussion shifts to how interruptions can be beneficial; some interruptions (e.g., emergencies) warrant immediate attention and should override ongoing tasks.
- Microcontrollers can handle interrupts by saving current processes and addressing urgent tasks without losing data or context.
Implementing Hardware Interrupts
- To improve functionality, hardware interrupts allow the microcontroller to respond immediately when an event occurs (like pressing a button).
- In an Arduino sketch, variables are declared first, followed by setting pin modes and running one-time setup code before entering an infinite loop.
Flow of Execution with Interrupt Service Routines (ISRs)
- Within the loop, commands run sequentially. If a delay is active while checking for switches, any button presses are ignored until after the delay ends.
- A better approach involves placing check switch functionality within its own interrupt service routine (ISR), allowing it to execute independently from other tasks like delays.
Understanding Interrupt Service Routines in Arduino
What is an Interrupt Service Routine (ISR)?
- An ISR is a function that executes when an interrupt is received, pausing the main program execution until the ISR completes.
- ISRs must be quick; certain commands like
delay,serial, andmilliscannot be used within them to avoid delays in processing.
- Variables used in ISRs should be defined globally or declared as volatile to prevent compiler optimization issues that could lead to errors.
Experimenting with Interrupts on Arduino Uno
- The Arduino Uno has two hardware interrupts: pin 2 (interrupt vector 0) and pin 3 (interrupt vector 1), while other boards may have more.
- The
attachInterruptfunction links an interrupt to its corresponding ISR, requiring parameters such as the interrupt vector number, the ISR name, and the mode of triggering.
Modes of Triggering Interrupts
- The mode parameter can trigger interrupts based on input changes:
- Rising: Triggered when input goes from low to high.
- Falling: Triggered when input goes from high to low.
- Low: Triggered when input remains low.
- Change: Triggered on any change in state.
Understanding Interrupt Vectors
- Determining the correct interrupt vector can be confusing since it does not match pin numbers; use
digitalPinToInterrupt()for clarity.
- This method simplifies coding by allowing you to specify actual pins instead of internal numbers.
Modifying Code for Hardware Interrupt Usage
- Only one ISR runs at a time due to priority systems; multiple interrupts are executed sequentially based on their priority level.
- A revised sketch using interrupts aims to resolve timing issues caused by delays. Constants for LED and button states are defined, including a boolean toggle state marked as volatile.
Implementing Debouncing in ISRs
- The check switch function checks if a button is pressed without delay for debouncing since it's now part of the ISR.
- Removing delays helps ensure that pressing the button triggers immediate responses without lagging due to debounce handling.
Setting Up Attach Interrupt Functionality
- In setup, attach the interrupt using
attachInterrupt(), specifying which pin will trigger it and linking it with the check switch function as its ISR.
- The push button uses an internal pull-up resistor, remaining high until pressed, which triggers a falling pulse interrupt.
Final Notes on Loop Functionality
Understanding Interrupts in Arduino
The Role of Interrupts During Delays
- An issue with toggling during a delay is addressed by loading code with interrupts, allowing the Arduino to run while in a delay period.
- Pressing the switch successfully toggles the state on and off, demonstrating that interrupts can effectively manage input even when delays are present.
- Hardware interrupts provide a superior method for connecting switches to an Arduino compared to traditional methods.
Types of Interrupts on Arduino Uno
- The Arduino Uno has only two hardware interrupt-capable pins; however, there are ways to utilize more pins for interrupts.
- Pin change interrupts allow every I/O pin on the Arduino Uno, including analog pins, to function as interrupt pins but are less versatile than hardware interrupts.
Understanding Pin Change Interrupts
- The ATmega328 processor supports 24 pin change interrupt pins; 20 of these are available on the Arduino Uno.
- Pin change interrupts activate upon any change of state (low to high or high to low), and they are grouped into ports (Port B, Port C, Port D).
Configuring Pin Change Interrupts
- To use pin change interrupts, you must enable or disable the desired port using the Pin Change Interrupt Control Register (PCICR).
- After selecting a port with PCICR, you modify the pin change mask for specific pins within that port.
Implementing and Managing Interrupt Service Routines
- Define an interrupt service routine corresponding to your selected port; for example,
ISR PCINT0_vectis used for Port B.
- Be aware of the Pin Change Interrupt Flag Register (PCIFR), which activates upon changes within a pin group and must be reset after being triggered.
Precautions When Using Pin Change Interrupts
- Remember that pin change interrupts only detect changes in state; they do not differentiate between rising or falling edges.
Wiring and Programming Pin Change Interrupts in Arduino
Wiring Setup for LEDs and Push Buttons
- The circuit involves connecting a dropping resistor to the LED's anode, with the cathode grounded.
- Pin 13 connects to another dropping resistor leading to a second LED's anode, also grounded at the cathode.
- Pin 2 is wired to one push button switch, while pin 7 connects to another switch, both grounded on their opposite sides.
Introduction to Code for Pin Change Interrupts
- The initial sketch will demonstrate reading from one LED and switch setup.
- Define the LED on pin 13 and the push button on pin 7; a volatile boolean
toggleStateindicates input state.
- Set up interrupt control by modifying the PCI Control Register (PCI CR), enabling bit number three for port D where switches are located.
Configuring Interrupt Service Routine
- Modify the pin change mask for port D to respond only to changes on pin D7 (bit number seven).
- The interrupt service routine (ISR) is predetermined; it inverts
toggleStateand updates the LED based on this state.
Demonstration of Button Press Behavior
- When pressing or releasing the button, two state changes occur: from high to low when pressed, and low back to high when released due to internal pull-up resistors.
- Acknowledges potential bounce issues that may cause unexpected behavior but generally operates reliably.
Expanding Functionality with Multiple Inputs
- Next demonstration incorporates both switches and LEDs; switches are connected at pins D2 and D7 which share interrupts.
- This sketch aims to differentiate between inputs from pins D2 or D7 using defined connections for each switch/LED pair.
Setting Up Multiple Interrupt Handling
- Define input/output connections for both switches/LED pairs while maintaining volatile booleans for their states.
- Configure interrupts similarly as before by writing bit three in PCI CR for monitoring port D.
Finalizing Configuration of Pins
- Enable both pins D2 and D7 in the pin change mask by setting bits two and seven high.
Toggle Control with Pin Change Interrupts
Implementing Button Controls for LEDs
- The speaker discusses using button pin number one on port D2 to check its state. If the button is pressed (low), it toggles a boolean state and writes that state to LED number one.
- Similarly, button pin number two on D7 is monitored, inverting its state and controlling LED pin 2 (pin 13). This setup allows independent control of each LED via their respective buttons.
- A demonstration shows both buttons functioning correctly; pressing either button toggles the corresponding LED on or off, illustrating effective use of interrupts despite sharing the same port.
- The speaker notes occasional issues with debouncing but finds the system relatively stable, highlighting that different pin change interrupts can be differentiated even when connected to the same port.
Utilizing Libraries for Simplified Interrupt Handling
- To ease working with pin change interrupts, the speaker recommends using libraries. While many are outdated, a valid library by Nico Hood can be found in the Arduino IDE's library manager.
- After installing this library, an example sketch called "pin change interrupt led" is explored. It sets up an input port (pin 7 for a push button) and uses built-in LED (pin 13).
- The sketch includes a function that ensures functionality by turning the LED on and off briefly during setup. It attaches a custom function to handle pin change interrupts instead of default behavior.
Demonstrating Library Functionality
- The blink function within the library toggles the LED's state based on input changes from the push button. This method simplifies managing input without needing extensive code in the loop section.
- A demonstration shows that pressing down on the red push button activates its corresponding red LED while releasing it turns off again—confirming stable operation through pin change interrupts.
Exploring Timer Interrupts
- The discussion shifts to timer interrupts, which trigger after set time intervals—useful for periodic readings or outputs. Users may have unknowingly used these through PWM or servo libraries previously.
- Caution is advised when using timer interrupts as they may conflict with other processes utilizing timers already in use within Arduino applications.
Understanding Timer Mechanics
- The ATmega328 chip has three internal timers: Timer 0 and Timer 2 are 8-bit; Timer 1 is 16-bit. These timers operate based on a 16 MHz clock oscillator where each tick equals approximately 62.5 nanoseconds.
- An internal prescaler divides this clock frequency down to lower rates like 15.625 kHz (64 microseconds), allowing more manageable timing operations across various applications involving Arduino Uno.
Understanding Timer Functionality in Microcontrollers
Prescaler and Timer Configuration
- The CS02, CS01, and CS00 bits determine the prescaler value for timers. It can also be set to no clock source, halting the timers or using an external clock source.
- Timer 1 operates similarly to Timer 0 but utilizes the CS12, CS11, and CS10 bits. Timer 2 has limited prescaler options and cannot use an external clock source.
- Interrupts are generated when a timer reaches a specific count in compare match mode; this value is stored in the compare match register.
- The formula for setting timer frequency involves both the prescaler and compare match register values. The addition of one accounts for the zero-based index of the compare match register.
- To achieve a one hertz output with a prescaler of 1024, a compare match register value of 15624 is calculated.
Interrupt Service Routines (ISRs)
- Predefined names exist for interrupt service routines related to timer interrupts; these include modes for both comparison and overflow.
- In this experiment, Timer 1 will control an LED on pin 13 without additional hardware since Arduino Uno has a built-in LED on that pin.
- An integer variable is defined as the compare match register value which sets output frequency alongside the prescaler.
- The ISR will reset the timer with its preloaded value upon triggering and toggle the LED state using digital read/write methods for efficiency.
- This method allows rapid toggling of LED states within an ISR context, crucial for maintaining performance during interrupts.
Setting Up Timers
- During setup, LEDs are configured as outputs while all interrupts are disabled to prevent interference during initialization.
- Timer 1 is initialized by setting two registers to zero before determining its compare match variable based on previously discussed formulas.
- For a prescaler value of 256, a calculated compare match value of 31249 results in an output frequency of 2 Hz (LED blinking every half second).
- After preloading the timer with this value, appropriate bits are set in configuration registers to enable operation in comparison mode.
- All interrupts are re-enabled post setup; notably, no code runs within the main loop as functionality relies entirely on timer-driven ISRs.
Demonstration Outcomes
- A demonstration shows successful LED blinking driven solely by timer interrupts without any active code in the loop section of Arduino programming.
Understanding Timer Interrupts and Community Engagement
Timer Interrupts in Sensor Sampling
- The DHT22 sensor requires sampling every two seconds, which can be efficiently managed using timer interrupts.
- Timer interrupts are highlighted as an ideal method for achieving precise timing in sensor data collection.
- The discussion concludes with encouragement to implement interrupts in personal coding projects.
Additional Resources and Community Interaction
- Viewers are directed to the DroneBot Workshop website for further information on interrupts and access to accompanying code.
- A newsletter sign-up is encouraged, providing updates about the workshop's activities at no cost.
- The DroneBot Workshop forums are recommended for discussions on electronics, allowing users to connect with like-minded individuals.
Subscription Encouragement