Arduino Timer Interrupt Ultimate Secrets: Learn How to make effective use of Timer Interrupts for Reliably Generating Exact Time Periods. An Easy Step-by-Step Tutorial.

  • Exact steps to get your Timer1 interrupts working.

  • Simple Step-by-Step Interrupt procedure.

  • Create Exact Period-Repeatable Interrupts using Timer1.

  • Find out why there are both Overflow and Compare Match interrupts.

  • Why your code won't Set or Read the 16-bit registers correctly for Timer1!

  • Why your output has the Wrong Period from start up.

  • Find out why the micros() function has a resolution of 4us.

  • Apply these steps to get any Interrupts to Work.
This Arduino Timer Interrupt Tutorial shows you exactly how to get Timer1 interrupts working. If you need to get your Arduino to repeatedly do an action at a specific time interval then you need to know how to setup timer interrupts for exact period timing.

You can also use this information for figuring out how to use any other obscure interrupt that is not explicitly supported by the Arduino software. It is - if you like - a template for what you need to do to get an interrupt going in your code.


Note: This tutorial is a template for figuring out how to use any internal interrupt.

Using interrupts for measuring and controlling specific time periods is very different to using delay() or millis() functions ( its more accurate ) - you can setup an interval using these functions however they can not reliably setup an accurate repeatable interval because they depend on the action of other code in your program. For instance you might have some code that is waiting for a key press blocking the rest of the code from operating.

TIP: Find out how to create repeatable, reliable time periods with interrupts.

Timer interrupts operate in the background over you main code allowing accurate repeatable timed actions.

It involves a bit more coding than the usual Arduino code and this tutorial will allow you to understand how to control the underlying hardware to setup a correctly operating timer interrupt.

For a high level look at what interrupts actually are, and how they work this hardware interrupt page gives you an introduction.

This page is about internal timer interrupts. If you are looking for information on external interrupts that use attachInterrupts() and detachInterrupts() functions, then this Arduino hardware interrupt page has that information.

The fact is, that using internal interrupts that have not been "setup" for you by Arduino software is slightly more difficult (not too much!) and you have to delve a bit more deeply into the architecture of the chip in use. In this case for the Arduino Uno it is the ATmega328P chip. You will need to look at the datasheet of other chips if you are using a different microcontroller chip. However, the principles for using interrupts are exactly the same for other microcontrollers.

Timer interrupts are not directly supported by the Arduino software so here we'll be looking at the more fundamental operation and control using the AVR ecosystem.

Fortunately the Arduino code does use the same AVR ecosystem to operate (under the hood) so it is just a matter of determining the correct AVR functions that are already available and using them in your standard Arduino environment.

Warning: Timer0 is used to implement functions delay() and millis().
Since Timer0 is used to time delays for functions delay() and millis() you probably want to keep that functionality so here you will experiment with Timer1. You can also use Timer2. However if you use more than 2 PWM signals then Timer1 and Timer2 will be in conflict with this code (depending on how many PWM signals you setup).

Warning: Timer1 and Timer2 are used in Arduino to implement PWM.

General Interrupt Process

  1. Understand the hardware (read the datasheet),
  2. Find out the relevant interrupt vectors,
  3. Find the relevant hardware module control registers and setup the hardware,
  4. Create the Interrupt Service Routine (ISR) - this is your action part of the code,
  5. Set the interrupt mask to allow your specific ISR to trigger,
  6. Run the program.
  7. Swear loudly when it all goes wrong (or does nothing): Return to step 1.

Arduino Timer Interrupt Vectors

The first thing to do is find out the information on what interrupt vectors are available and how to implement them using the AVR GCC manual.

This is the page on interrupts:

    AVR GCC interrupts for AVR chipset.

Arduino Timer Interrupt: Find the Header File name

If you look at the top of the page you will see that the include file needed is:

    <avr/interrupt.h>

...which you write into the top of your file as...

    #include <avr/interrupt.h>

The angle brackets indicate to the compiler that the file is a standard internal compiler header file and not a user defined header file i.e. look somewhere else for the header!

For a "normal" compiler you need these headers but in the Arduino environment they are automatically included. Its up to you whether or not to use them. Personally I think it shows you are doing something unusual i.e. indicates an "danger" interrupt-in-use indicator in your code.

Arduino Timer Interrupt: Find the Interrupt Vector

The interrupt vector is the vector address associated with a hardware action .e.g you can find the 'ADC reading complete' vector address labeled as 'ADC_vect'. These labels are merely numbers corresponding to the address in the hardware that will be used in the event that an interrupt is triggered.

When you create a function associated with this vector, the address of the function is placed at the vector address (Section12.4 in the datasheet "Interrupt Vectors in ATmega328"). When the interrupt triggers, this address is placed into the program counter i.e. it jumps to your function. There is a bit more involved as the interrupt jump has to know how to return to the main function and also store registers before, and restore registers after the interrupt has finished.

Now do a search for Timer1 in that page. The first item you will see is:

    TIMER1_CAPT2_vect

This is an Arduino timer interrupt that fires when a Timer1 capture event occurs. As you can see there are many interrupt vectors and you should look at the datasheet to see what they are used for in each hardware module.

Scroll down and you get to the two more useful (for this discussion) vectors:

    TIMER1_OVF_vect             which is     Timer/Counter1 Overflow,

and...

    TIMER1_COMPA_vect        which is    Timer/Counter1 Compare Match A

There are a few registers that allow you to compare the value in the Timer to the value stored in the register - here you are only using one of these registers (Compare Match A register).

Using this register allows you to define a specific time that the Arduino timer interrupt will occur since the timer counts up from reset (zero). However remember that the Timer hardware has a prescaler, and selectable clock source, so you need to control the clock that the Timer uses, to obtain the correct time period for Timer1.

Arduino Timer Interrupt: Setup the Hardware

To generate an Arduino Timer Interrupt you need to activate the hardware - in this case, start Timer1. In general all hardware modules default to inactive to save power. To start it up you have to consult the datasheet.

There is a register summary in Section 36 (Register Summary p621) of the datasheet so if you have some idea of the register name this will allow you to see related register names and which main page they are on.

Arduino Timer Interrupt: Timer1 Registers

Registers have fairly cryptic names but expanded text makes sense. There are a lot of registers but they are necessary for controlling the multiple modes for PWM operation.

TCCR1A – Timer/Counter1 Control Register A.
    Function: Compare output and waveform generation mode.

TCCR1B – Timer/Counter1 Control Register B
    Function: Input capture noise canceller, waveform generation mode, Clock Select.

TCCR1C – Timer/Counter1 Control Register C
    Function: Force output compare for channel A & B

TCNT1H and TCNT1L – Timer/Counter1
    Function: I/O address for high and low bytes.

OCR1AH and OCR1AL – Output Compare Register 1 A

OCR1BH and OCR1BL – Output Compare Register 1 B

ICR1H and ICR1L – Input Capture Register 1

TIMSK1 – Timer/Counter1 Interrupt Mask Register
    Function: The Interrupt Mask Register that lets an interrupt trigger.

TIFR1 – Timer/Counter1 Interrupt Flag Register
    Function: The Interrupt Flag shows which interrupt fired (could be overflow or compare match etc.). This is used to figure out which interrupt (or multiple interrupts) triggered ISR. It can be useful when you poll the register instead of using interrupts.

The registers that you need now are show below:

TCCR1A - Control register A
TCCR1A bit names

TCCR1B - Control register B
TCCR1B bit names
Here CS1[2..0] are the clock select bits. For a value of CS1[2..0] equal to zero the clock is stopped, so for 16MHz operation set the value to 1. The others are Input Capture Noise Canceller, and Waveform Generation Mode.

TIMSK1 - Interrupt Enable Controls (Mask)
TIMSK1  bit names
Here TOIE1 is the Timer1 overflow Interrupt Enable. The others are Input Capture and Output Compare Match.

TIFR1 - Interrupt Flags
TIFR1 bit names
Here TOV1 is the Timer1 overflow flag. The others are Input Capture and Output Capture.

Arduino Timer Interrupt: Timer1 Prescaler

The prescaler lets you use a different clock to the main system clock and uses a simple divider to provide different output frequency clocks to Timer1 (and Timer0).

For a different timer clock you can also use a separate external clock fed into a Timer1 input pin but note that this external clock cannot be prescaled. Also the external clock is put through two d-types linked to the system clock for signal stabilisation.

Note: Timer1 can also use an external clock attached to pin: T1.

The prescaler is shared between Timer0 and Timer1 - this just means each Timer can select a different output from the prescaler, so they are effectively independent from each other.

Arduino Timer Interrupt: Timer1 frequency and prescaler Table

Clock mode CS1[2..0]
1
2
3
4
5
The prescaler outputs divided from the system clock are:

fCLK_I/O fCLK_I/O/8 fCLK_I/O/64  fCLK_I/O/256 fCLK_I/O/1024

So that means for the Arduino, with a system clock of 16MHz, you can have the following frequencies input to the timer/counter:

16MHz 2MHz 250kHz 62500Hz 15625Hz

For these frequencies each count of the timer will be equivalent to a period of:

62.5ns 0.5us 4us 16us 64us

Maximum time count on overflow (16 bit Timer/Counter) [ pow(2,16)*period ]:

4.096ms
32.768ms
262.144ms
1.0478576s
4.194304s

Knowing the timer clock period allows you to figure out how many timer periods are needed to reach a specific time period i.e. this is the timer compare register value you need to use. The timer clock period also defines the resolution of the timer.

TIP: You can increase the timer count by increasing a global variable in the ISR.

Arduino Timer Interrupt: Timer1 Clock Select

The prescaler clock is selected by setting bits CS1[2..0]:

  • CS12,
  • CS11,
  • CS10.

 These bit controls are located in register TCCR1B bits 2..0;

They are used as a binary value to program the required clock source:

CS1[2..0]
Clock Source
Clock Frequency
0 No clock source 0Hz
1
clkI/O/1 16MHz
2
clkI/O/8 2MHz
3
clkI/O/64 250kHz
4
clkI/O/256 62500Hz
5
clkI/O/1024 15625Hz
6
External clock on T1 falling edge.
Less than 6.4MHz [1]
7
External clock on T1 rising edge. Less than 6.4MHz [1]

[1] - There are two d-types that perform external clock synchronisation - this removes meta stability problems but means the interaction with the synchronsing system clock makes it important to use a clock input that is stable relative to the system clock. The datasheet requires an input clock at a frequency less than half the system clock. For extra stability margin the datasheet also recommends that the input clock is less than fclk_I/O/2.5. Seed datasheet Section 17.3 "External Clock Source"

Note: Timer2 has an asynchronous input with no synchroniser at the input to the timer, meaning you can put high speed digital signals into it!

Lets say you want to use a 62.5kHz clock [clkI/O/256 - period 16us] then you can set it up as follows:

#if !defined(setbit)
    #define setbit(val,b) (  (val) |= (1<<(b)) )
    #define clrbit(val,b) (  (val) &=~(1<<(b)) )
    #define tstbit(val,b) ( ((val) &(1<<(b-8)))!=0 )
#endif  

    setbit(TCCR1B, CS12); // 1 
    clrbit(TCCR1B, CS11);  // 0
    clrbit(TCCR1B, CS10);  // 0


The clock select bits are also the clock enable since their default value is zero meaning turn off the clock.

Arduino Timer Interrupt: Timer Overflow Interrupt Mask


Looking at the Interrupt mask register definition, the overflow enable in TIMSK1 is bit zero (Section 16.11.8):

    TOIE1 - Timer Overflow Interrupt Enable for Timer1 at bit 0.

So the following code will allow the overflow interrupt for Timer1 to trigger:

    setbit(TIMSK1, TOIE1);// Enable Overflow Interrupt.

Arduino Timer Interrupt: Using the Overflow Registers.

Timer1 overflow is a event that triggers when the timer is full and since this is a 16 bit timer the value for full is 0xFFFF. When it passes this value the overflow interrupt is triggered.

Since you can manipulate the prescaler and/or the clock source you can precisely define the time at which the timer will overflow and therefore create a predictable repeatable time period. The only problem is that it gives you only a fairly crude control over the time period - all you can really do is change the prescaler value, because the main clock is fixed at 16MHz, and then see what time period you get!

For the 16bit Timer1 clock you have overflows of:

    4.096ms, 32.77ms, 262.14ms, 1.048s, 4.19s.

For an 8 bit clock you have overflows of:

    16us, 128us, 1.024ms, 4.10ms, 16.38m.

This can be useful if you are not too fussed about the exact value of the time period but just want a repeatable period i.e. if you need an approximate 20ms (or smaller!) trigger to refresh a display (POV see MAX7219 operation and LED Matrix display). You could also use the 8bit timer (Timer0 and Timer2) instead for a faster repeat rate or lower maximum overflow time (also it gets closer to the 20ms period).

However, if you want a precise period then you need to use the compare match registers. For instance, you might want a precise period for taking measurements from an ADC to define the sample rate.

Arduino Timer Interrupt: Sketch testing Timer1 Overflow

// Arduino timer Interrupt: Test Timer1 overflow interrupt.
//
// This Arduino Timer Interrupt code shows you how to setup
// Timer1 in the right way for use with overflow interrupts.
//
// Copyright (C) John Main - Free for non commercial use. //
#include <avr/interrupt.h> #if !defined(setbit) #define setbit(val,b) ( (val) |= (1<<(b)) ) #define clrbit(val,b) ( (val) &=~(1<<(b)) ) #define tstbit(val,b) ( ((val) &(1<<(b-8)))!=0 ) #endif #define DEBUG_PIN 5 #define LED_PIN LED_BUILTIN static byte val_debug_pin = 0; void setup_T1(void) { TCCR1A = 0; // Initialise registers TCCR1B = 0; // Initialise registers TCCR1C = 0; // Initialise registers OCR1AH = 0; OCR1AL = 0; OCR1BH = 0; OCR1BL = 0; // Set Clock mode. setbit(TCCR1B,CS12); // Clock mode 4. clrbit(TCCR1B,CS11); clrbit(TCCR1B,CS10); setbit(TIMSK1,TOIE1); // Enable T1 Overflow interrupt. } // Interrupt on Timer 1 overflow. ISR(TIMER1_OVF_vect) { // Toggle debug pin. val_debug_pin = !val_debug_pin; if (val_debug_pin) digitalWrite(DEBUG_PIN, HIGH); else digitalWrite(DEBUG_PIN, LOW); } void setup(void) { pinMode(DEBUG_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); setup_T1(); } void loop(void) { delay(100); digitalWrite(LED_PIN,HIGH); delay(100); digitalWrite(LED_PIN,LOW); }

// End of Arduino Timer Interrupt code.


Arduino Timer Interrupt: Timer1 Overflow Output Waveform

This is the output you get with the configuration (set above):

As you can see each high and low period is the predicted 1.048s (the pin is toggled on each Timer1 overflow).

Timer1 overflow Interrupt clock setting divide by 256

Arduino Timer Interrupt: Using the Compare Registers

Timer1 is a complex piece of hardware because it is also used as a PWM generator (Pulse Width Modulation) and it allows many types of PWM signal. To it to do a simple task is a bit more difficult. The simple task you want it to do is generate a signal of defined period and repeat that action after each interrupt.

There are two sets of bit controls that set the Timer1 operation COM (Compare output mode) and WGM (Waveform Generation Mode). COM controls how output is generated i.e. signal inversion but more interestingly, in non-PWM mode it controls whether the output should be set, cleared or toggled on compare match.

The WGM module can be set to clear on compare match (this is not the default action!). This is the mode you need and WGM1[3..0] must be set to either 4 or 12. The value 4 indicates that the reset should occur for matches from OCR1A (output compare) while 12 means that reset should occur for matches from ICR1 (input compare).

Table 16-4 (datasheet) shows the relationship between WGM1[3..0] and the counter/PWM modes. So for setting mode 4 WGM you need the following code:

    clrbit(TCCR1B, WGM13);  // 0
    setbit(TCCR1B, WGM12); // 1 WGM mode 4
    clrbit(TCCR1A, WGM11);  // 0
    clrbit(TCCR1A, WGM10);  // 0

... and control COM - Compare Output Mode - (Table 16-1 datasheet) set to mode:

    clrbit(TCCR1A, COM1A1); // 0
    setbit(TCCR1A, COM1A0); // 1

Mode 1 is toggle OC1A on compare match.

The specific table to use depends on the WGM mode in use!

Table 16-1 (datasheet) for non-PWM mode
Table 16-2 (datasheet) for fast-PWM mode
Table 16-3 (datasheet) for phase-correct and frequency-correct-PWM mode

Warning: Compare output mode changes depending on the WGM mode in use.


Note: The OC signal is only output at the pin if pinMode is set to output.

Gotcha - Wrong value in 16 bit register

This is why your code won't set or read the 16-bit registers correctly for Timer1.

The datasheet indicates that for C code you can write the following to set the value of a 16bit register:

    OCR1A = 19000;

What you get when you do this, is: "undefined" action and that's a bad idea. Especially as a piece of text that is buried with the datasheet says the following:

   " To do a 16-bit write, the high byte must be written before the low byte.
    For a 16-bit read, the low byte must be read before the high byte."

When you write:

    OCR1A = 19000;

..you are assuming that the compiler will do the write in a specific order - but that order could be low or high byte first. The Arduino compiler is writing the low byte first followed by the high byte. In practice the code became unreliable when changing the compare value using the code above. The correct way to control the compiler is to be explicit:

         // 16-bit write must do H then L.
         noInterrupts();
         OCR1AH =  ( (uint16_t)OVFcount >>8) & 0x00ff;            
         OCR1AL = (uint16_t)OVFcount & 0x00ff;
         interrupts();

Warning: For 16 bit writes, write the high byte followed by the low byte.

Gotcha - Wrong frequency at startup

This is why your output has the wrong period from start up.

Since the Arduino ecosystem sets up the output compare registers for use as PWM when they are enabled some of the registers in the "Compare output and waveform generation" have already been set.

If you don't override them you can get seemingly wrong frequency output. The solution us to initialise all registers associated with the PWM.

Note that you you go back to PWM use then you need to restore the values that were originally there. This is the code used to initiaise some of the relevant registers:

   TCCR1A = 0;  // Without output compare outputs 32us instead of 4.1ms.
   TCCR1C = 0;  // Without output compare outputs 32us instead of 4.1ms.
   OCR1AH = 0;
   OCR1AL = 0;
   OCR1BH = 0;
   OCR1BL = 0;

Warning: Initialise registers at start for correct operation.

Arduino Timer Interrupt: Set the desired repeat rate

Lets say you want a repeat rate of exactly 195.7ms.

You would look at the table and see the minimum overflow value that is larger than 195.7ms. Here it is clock mode 3 - 262ms  - (mode 2 has 32ms maximum time period).

The value of the compare output count is calculated using the count resolution for the mode in use = ( 195.7ms / 4us ) = 195.75e-3/4e-6 = 48937.5. Round up to ensure the period is at least as long as required and this is your compare match register value to use.

The actual time calculation is: 48938* 4e-6 = 195.72ms

Arduino Timer Interrupt: Sketch testing Timer1 Compare

// Arduino timer Interrupt: Test Timer1 compare match interrupt
//
// This Arduino Timer Interrupt code shows you how to setup
// Timer1 in the right way for use with compare match interrupts.
//
// Copyright (C) John Main - Free for non commercial use. //
#include <avr/interrupt.h> #if !defined(setbit) #define setbit(val,b) ( (val) |= (1<<(b)) ) #define clrbit(val,b) ( (val) &=~(1<<(b)) ) #define tstbit(val,b) ( ((val) &(1<<(b-8)))!=0 ) #endif #define DEBUG_PIN 5 #define LED_PIN LED_BUILTIN static byte val_debug_pin = 0; void setup_T1(void) { TCCR1A = 0; // Without reset COM mode outputs 32us instead of 4.1m. TCCR1B = 0; // Without reset COM mode outputs 32us instead of 4.1m. TCCR1C = 0; // Without reset COM mode outputs 32us instead of 4.1m. OCR1AH = 0; OCR1AL = 0; OCR1BH = 0; OCR1BL = 0; // Set WGM mode - non pwm. clrbit(TCCR1B, WGM13); // 0 setbit(TCCR1B, WGM12); // 1 WGM mode 4. clrbit(TCCR1A, WGM11); // 0 clrbit(TCCR1A, WGM10); // 0 // Set Compare Output mode non-pwm clrbit(TCCR1A, COM1A1); // 0 setbit(TCCR1A, COM1A0); // 1 // Set Clock mode. clrbit(TCCR1B,CS12); // Clock mode 3 setbit(TCCR1B,CS11); setbit(TCCR1B,CS10); // 16-bit write must do H then L. 48938 * 4us = 195.75ms noInterrupts(); OCR1AH = ( (uint16_t)48938 >>8) & 0x00ff; OCR1AL = (uint16_t)48938 & 0x00ff; interrupts(); setbit(TIMSK1, OCIE1A); // Enable Compare Output A interrupt. } // Interrupt on Timer 1 Compare Match register A ISR(TIMER1_COMPA_vect) { // Toggle debug pin. val_debug_pin = !val_debug_pin; if (val_debug_pin) digitalWrite(DEBUG_PIN, HIGH); else digitalWrite(DEBUG_PIN, LOW); } void setup(void) { pinMode(DEBUG_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); setup_T1(); } void loop(void) { delay(100); digitalWrite(LED_PIN,HIGH); delay(100); digitalWrite(LED_PIN,LOW); }
// End of Arduino Timer Interrupt code.

Arduino Timer Interrupt: Timer1 Compare Match Waveforms

Here's the a screenshot of the Output Compare repeat period at 195.72ms. Note that the pin is toggled at every compare match so the period of the high or low part of the waveform gives the interrupt repeat period.

Timer1 compare match 195.72ms clock select 3 div by 64

As another example lets choose a 20ms repeat rate:

The maximum clock needed is in mode 2 - max period 32ms - (mode 2 has period 0.5us and 32.768kHz requency). Then the calculation is: 20e-3/0.5e-6 = 40000.

Here's the a screenshot of the Output Compare repeat period at 20ms:

Timer1 compare match 20ms div cs 4 div 256

You can increase the measured time period by using counters within the ISR code.

Note: You can increase the maximum time period by using counters in the ISR.

Arduino Timer Interrupt: Why use Overflow instead of Compare?

The question is really why does the overflow interrupt exist when you can choose to use an exact time period. If you can get an exact time period then why bother with overflows?

Its true you could do away with the overflow interrupt. However Timers are a limited resource and you may want to keep a timer continuously going without altering it, but at the same time you want a defined time period interrupt. This is a way of using one timer for different jobs.

A very good example of this is the Arduino millisecond timer and PWM operation. Timer0 is used for both the millisecond timer and the PWM output at the same time. It gets round the fact that the ms timer is slow by 24ms by using a special algorithm to correct the actual time every so often. So a single timer is used for two tasks, leaving the other timers for anything else.

For this example it is important that the clock is not reset at random times (which the Output Compare Logic can do - if set to do so i.e. it can reset the counter on a compare match event). So the clock continuously counts up and the PWM generator can operate correctly. In this case the ms clock is not always accurate but over time is corrected and is therefore "accurate enough". The reason is that it is not critical.

In a commercial system - if it is important enough - you could choose the main crystal clock to give an exact millisecond output and then you would have an exact clock time and a useful period generator.

Timer0 frequency and prescaler Table


Clock mode CS1[2..0]
1
2
3
4
5
The prescaler outputs divided from the system clock are:

fCLK_I/O fCLK_I/O/8 fCLK_I/O/64 fCLK_I/O/256 fCLK_I/O/1024

So that means for the Arduino, with a system clock of 16MHz, you can have the following frequencies input to the timer/counter:

16MHz 2MHz 250kHz 62500Hz 15625Hz

For these frequencies each count of the timer will be equivalent to a period of:

62.5ns 0.5us 4us 16us 64us

TIMER 0

Maximum time count on overflow (8 bit Timer/Counter) [ pow(2,8)*period ]:

16us
128us
1.024ms
4.096ms
16.384ms

Arduino Timer Interrupt: How is Timer0 used?

For Timer0 you can see that a clock divider of 64 gives a 1.024ms overflow period and that the resolution of that timer is 4us. This is where the approximate 1ms clock for millis() and delay() functions is derived (The clock is corrected to 1ms by a special algorithm).

This clock is also used for PWM ( 1/1024e-6 = 976.5625kHz ), and in the micros() function and that is why the resolution of the microsecond functions is 4us. This is effectively the error bound on measuring microseconds.

You can see that by using a different divider you could reduce this to 62.5ns! but you would need to change Arduino code or use a separate timer if you wanted original code to work. Also, if you did change it then the processor would be calling the ISR a lot and that could affect the operation of main code. It is a trade off.

End of Arduino Timer Interrupts page. If you need information on external interrupts then the link has that information.


Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.



Privacy Policy | Contact | About Me

Site Map | Terms of Use