Our project uses two
types of interrupts: a pin-change interrupt and a
UART “data received”
interrupt. The pin-change
interrupt is driven by the
demonstrates the use of an
interrupt where urgency is
important. The UART interrupt is triggered when data is
received over the UART, and demonstrates how interrupts
can simplify your projects.
July 2015 31
Figure 6: Pin-change interrupts: Pin groupings and interrupt registers.
You may remember that the 24 PCINT pins are
grouped into three banks of eight pins (although you may
notice that PCINT15 doesn’t exist): PCINT0-7, PCINT8-15,
and PCTINT16-23. Figure 6 shows the relationship
between the physical pins, the PCINT designations, the
groupings into “banks,” and then finally how these are
dealt with in the registers.
Listing 1 shows a number of excerpts from the
project. I’ve cut out large parts of code between the areas
we need to focus on here (signified by the “= = = = CUT =
To decode all of this, let’s look at what we need to do
to enable the interrupt on pin PD6. From Figure 6, you’ll
see that PD6 falls into “bank” 2. To enable interrupts on
bank 2, we set bit 2 of the PCICR register:
= = =” inserts).
In most cases, configuring an interrupt is a simple
case of setting some sort of “Interrupt Enable” bit in a
relevant register. Each type of interrupt does have its own
slight peculiarities though, so we’ll deal with the details of
the ones we’re using here.
PCICR |= (1<<PCIE2);
Configuring the PCINT Interrupt
By now, you’ll probably be (reluctantly) comfortable
with the fact that the ATmega328P datasheet is your go-to
when you need to work with new functionality on the
Okay, we’ve enabled interrupts on bank 0 — but
which of the eight pins (PCINT16-23) will actually fire? For
this, we use the PCMSKx register. There are three of these
registers — one for each bank — but, of course, we only
need to manage bank 2. Setting a “1” for a specific pin
allows that pin to trigger an interrupt. So, the code we
MCU. Open it up and head over to section 13. 2 — the part
of the datasheet describing the registers needed for
managing external interrupts. Here, you’ll find details of the:
PCMSK2 |= (1<<PCINT22);
PCICR (Pin Change Interrupt Control Register),
which allows the enabling and disabling of interrupts
when the PCINT pins toggle.
PCIFR (Pin Change Interrupt Flag Register), which
indicates whether an interrupt on a PCINT pin has been
That’s all it takes to configure the pin-change interrupt.
Now whenever the logic level on pin PD6 changes, the
interrupt will fire. For a button, this means that the
interrupt will trigger on both the press and the release, as
well as if the button bounces. We work around this in the
ISR as we only want the first press of the button to trigger
an interrupt in this game.
PCMSKx (Pin Change Mask Registers), enabling you
to set which individual PCINT pins trigger an interrupt.
Configuring the UART Rx Interrupt
From Listing 1, you’ll see that configuring an interrupt
to fire whenever a byte is received on the UART is really
straightforward — set one bit in the USART Control and
Status Register B, and away you go:
UCSR0B |= (1<<RXCIE0);
The projects are based on the build from "Beyond Arduino #1" in the
March 2015 edition of Nuts & Volts. The following additional
components are needed for the "Finger on the Buzzer" project:
D1 Green LED 20 mA
D2 Red LED 20 mA
R1,R3 330 ohm Resistors, 0.25W
SW1 Momentary Pushbutton Switch
If you are working on a project that expects to receive
a large volume of continuous data over the UART, then
using an interrupt like this is probably best for receiving
the first character only — and then handing it off to a
routine that will receive the rest of the data. Of course,
this depends on the complexity, clock speed, and
processing requirements of the rest of your project. I’d
suggest you experiment with both methods to see what
works best for that specific application.