One of the oldest tricks in the book when it comes to embedded microcontroller based designs is to incorporate a “heartbeat” LED. A heartbeat, indicator, general purpose (or the name of your choice) LED is simply an LED powered by one of the microcontroller's extra pins, either directly through a current limiting resistor or with the help of a transistor if the microcontroller's native voltage / current capability is not enough to drive the LED directly. The heartbeat LED can come in extremely handy as a cheap and simple indicator and diagnostic tool. For extremely cost sensitive designs it can always be removed for production, but I wouldn't recommend laying out a PCB without (at least) one.
A common use of the heartbeat LED is simply to inform the user / operator (or whoever needs to know) that the software is running. This is typically accomplished by blinking the LED slowly (kind of like a heartbeat), usually once or twice a second. The idea is that it doesn't blink so fast as to simply look like a blur or too slow to make the user have to wait around for a while to determine if the software is running. The simple reason blinking (as opposed to steady on) operation is used is to help identify lock ups. If the software happens to lock up with the LED lit steady, for example, and that also happens to be your “running” indicator, you may falsely think the software is still running. By blinking the LED, you can be sure that a steady on (or off with the power LED on - it's a good idea to have one of those too!) means your software has locked up or never started running in the first place.
This brings up an important point related to the actual software implementation. It may be tempting to use one of the microcontroller's timer interrupts to periodically toggle the state of the heartbeat LED pin. This may not be good practice, however, as it could very well keep your LED toggling while your software is locked up in a logic loop, giving you a false sense of normal operation. The code that handles the heartbeat should in someway be tied into the rest of the running software. A simple program with a continuous loop can accomplish this easily by processing the heartbeat state once per loop. If the code anywhere in the loop is to lock up, the heartbeat code will not be processed and the LED will stop blinking.
Things can quickly get more complicated in code that doesn't operate in a loop fashion. In this case, the heartbeat processing can be handled much like how a traditional watchdog is handled (another good embedded practice). A flag can be used to monitor software operation. In this case, using a timer interrupt may actually come in handy. A periodic interrupt could check the heartbeat flag/flags as well as any other diagnostic information and update the heartbeat LED state accordingly.
This opens up the possibility of displaying alternate error conditions. Instead of just blinking or not blinking, the LED could blink at different rates to indicate various states. A faster rate may indicate a certain error condition has occurred, a slower rate may indicate that a low power or sleep mode has been activated.
In addition to varying the blinking rate, the LED brightness can be varied with PWM (pulse width-modulation) of the LED power. If a hardware PWM peripheral is not available on the microcontroller, simple PWM functionality can be incorporated through code. Combining varying blink rates with different LED intensities can lead to an incredibly vast array of message possibilities. To save power, for example, low power modes may chose to use lower intensity brightness with a short duration blink that occurs at a slower interval. A high level error may blink at a fast rate and high intensity to grab the user's attention. Blinking by alternating the LED from full brightness to say 10% brightness provides yet another possible display indicator.
A continuous and gradual variance in the brightness level can also help communicate progress of specific events. Much like a progress bar displays progress in a graphical way, an LED can achieve a similar effect by gradually getting brighter (or dimmer) to communicate a time consuming process. For processes that take a considerable amount of time, it may be worthwhile to repeat this gradual dimming effect at a constant rate until the process has been completed to avoid too slow of a gradual transition from looking like a steady light (which wouldn't be very communicative).
The LED can also come in handy as a crude debugging tool during software development. It can act as a “do we ever get here?” indicator that communicates whether or not you reach a certain point in the firmware. The LED can also be used to indicate various events to give insight into the firmware, such as when a button press has been detected, when a communication signal is being received or transmitted, when an interrupt is active, etc.
One more common use of the LED during initial software development is as a time indicator. If you need to know how long a particular section of code takes to run, simply turn the LED on at the start of the code and off after processing is complete. If the code is too fast to see, loop through it 100 times, or 1,000, or whatever need be, and divide the total processing time as needed. Sometimes a precise time may not be necessary. If you have a continuous running loop, you may just be interested in how large a percentage of the loop time a certain portion of the code uses. With fast loops (too fast to see the LED turning on and off) the brightness of the LED can give you a rough estimate of the processing time. If the LED looks like it is nearly full on, it may be taking up a large percentage of the loop time, nearly off means it probably isn't taking up much time at all. Sometimes a rough idea is all that is required.
The heartbeat LED can be an engineers best friend, providing a vast array of potential information and the reassuring knowledge of always being there, even when other superior tools such as debuggers, oscilloscopes and multimeters are not. It may be easy to look over during design time, but don't forget it. The first time you do will be the time you need it most! Also, don't limit your use of the heartbeat LED to some boring on/off scheme, it offers a tremendous amount of information conveying potential.