this command will look familiar. Remember that this just
enables global interrupts. You’ll need to have already
configured your interrupt source (e.g., the ADC/external
interrupt/timer interrupt).
sleep_mode(); This final function (well, macro actually)
really does three things:
• Sets the Sleep Enable bit: SMCR |= (1<<SE);
• Puts the microcontroller to sleep: __sleep();
• Clears the Sleep Enable bit; this will happen when
the MCU wakes up: SMCR &= ~(1<<SE);
That’s it! We’ve successfully put the microcontroller to
sleep. So, what happens when it wakes up?
When the Microcontroller
Wakes Up
We’ve configured one (or more) interrupts to wake
the MCU from its sleep mode. Now what? When the
interrupt triggers, the microcontroller wakes up (taking at
least 10 clock cycles to get up to full steam) and enters
the Interrupt Service Routine (ISR). When the code in the
ISR has completed, execution returns to the statement
immediately after the sleep instruction that initially put the
microcontroller to sleep. As we usually try to keep code in
the ISR as short as possible, it’s likely that we’d want to
use the ISR to set a flag that then gets processed back in
the main while(1) loop.
Once we’ve finished executing the code that we
woke up to run, we simply put the microcontroller back to
sleep. I usually put the sleep commands in the main
while(1) loop so the MCU goes back to sleep on each
iteration of the loop.
Yep. That is all there is to sleep modes. I’m sure you’re
chomping at the bit to see this all in action, so let’s dive
into our first project.
The First Project: Sleep
I’ve lined up two projects this month. The first is a
simple one that visually shows us the workings of sleep
mode. The second one I’m going to leave to you to play
with — with a bit of guidance, of course. Let’s get cracking!
The first project has two LEDs attached via current-limiting resistors to PB0 and PB1. Listing 1 shows the bulk
of the code and Figures 5 and 6 show the layout. The first
LED (I call it LED_BLINK in the code) is blinked by an
interrupt on Timer2. Last month, we worked with Timer1,
but Timer1 isn’t able to wake a microcontroller from sleep.
So, we need to use Timer2 for this project. We use it in
the same way, although the control registers are slightly
different.
Also, it is an eight-bit timer, so the most we can count
up to is 255. This means that the LED will flash pretty
quickly! To combat that, I’ve used the Timer’s ISR to
increment a variable (delayCounter) on each interrupt;
when delayCounter reaches 10, I toggle the LED. You
could also use a slower crystal. If you’re currently using a
16 MHz one, the lowest you can go without reconfiguring
the fuse bytes is an 8 MHz crystal.
The second LED (LED_SLEEP) is there to prove to you
that the microcontroller is actually going into sleep mode.
I needed it to prove the same to me! This LED is toggled
before the sleep command is executed. If the sleep
command succeeds, then execution of the program will
halt until the timer interrupt wakes it; this delay causes the
LED to blink (very fast). If the microcontroller doesn’t go
to sleep, then execution will continue and the LED will be
toggled a few lines of code later, causing the LED to glow
constantly (although dimly). Test this functionality by
commenting out the sleep_mode(); command and
watching how the LED behaves.
The rest of the code is pretty straightforward and
should consolidate what we’ve discussed earlier in this
article. The problem with this project is that it doesn’t
really demonstrate how the sleep mode is reducing the
power consumption of the project. It’s for that reason we
January 2016 59
Figure 6: Project 1 using a Toadstool.
Figure 5: Project 1 on a breadboard.