5 Ways to Blink an LED with Arduino
Learn about the internals of the Arduino Uno microcontroller by looking at 5 different approaches for a seemingly simple task: blinking an LED!
Blinking an LED is the “Hello World” program of hardware. It is also one of the most popular Arduino program, and I bet electronics enthusiast has run it at least once in their life.
In this blog post, I am going to show you 5 different ways of blinking an LED on Arduino: blinking an LED by turning it on/off roughly once a second.
visit goodarduinocode.com to have access to many interesting Arduino projects, as well to subscribe for weekly curated Arduino projects.
We’ll start with the Blink example that comes with the Arduino IDE:
Below is the code for blinking an LED with standard built-in example:
This is pretty straightforward: LED_BUILTIN
is a constant that contains the number of the pin connected to the on-board LED, pin 13 in Arduino Uno. We set this pin to output in the setup()
function, and then repeat the following code:
- Set the pin to
HIGH
(5V), this will turn the LED on. - Wait for 1000 milliseconds, or one second.
- Set the pin to
LOW
(0V), cutting the power to the LED and turning it off. - Wait for another second, and then repeat everything again.
You can try it yourself on the free online Arduino blink code simulator playground.
Can we achieve the same with less code?
The Two-Liner
We can easily cut the loop()
code down to two lines by toggling the value of the pin:
Here’s the trick: digitalRead()
returns the current output value of the pin: 1
if the pin is high and the LED is on, 0
otherwise. We use the !
(not) operator to invert that value, and thus toggle the state of the LED. So basically the code above could be read as:
- Toggle the state of the LED.
- Wait one second, repeat.
The One-Liner
This one is my favorite, which was first presented to me by my friend avi ostfeld. By using a clever trick, we no longer need to call delay()
in our code:
We take advantage of Arduino’s millis()
function, which returns the number of milliseconds since the program has started running. We then divide this value by 1000, so we get the number of seconds passed so far. Finally, we take the number of seconds and calculate the remainder of dividing it by two, using the modulus (%
) operator. This calculation returns 0
for even numbers and 1
for odd numbers:
In other words, we repeatedly take the number of seconds passed since the program started running, and set the value of the LED based on that: ON if the number if currently odd, OFF if it is currently even. This is how we achieve the desired blink.
This method has a big advantage over the previous approaches: we can perform additional tasks inside our loop, as it is no longer blocking on the delay()
function. For example, you can blink three LEDs in different intervals: one every second, one every 1.26 seconds, and one every 380 milliseconds. Can you write the code for that?
A similar, but more verbose approach can also be found in Arduino’s documentation. You can also tinker with this code in the online Arduino simulator: blinking three LEDs without delay() playground .
Blinking with Timers ⌚
Our solutions so far relied on Arduino’s built-in functions, so they would virtually work on any board supported by the Arduino environment. However, if we focus just on the Uno board, we can start taking advantage of its specific hardware features — namely, timers and interrupts.
Hardware timers are simply counters that go up every predetermined interval. This interval is usually tied to the clock speed of the microcontroller. Uno boards use the ATmega328 microcontroller, and run it with a clock speed of 16MHZ, or 16 million times per second.
The following code sets up one of Arduino’s hardware timers and uses it to toggle the LED roughly every second:
You probably noticed a few weird things here. First of all, our loop()
function is empty, is the Uno doing nothing? Second, what are all these strange acronyms: OVF, ISR, TCCR1A, etc.?
For starters, here is some more background about the Uno timers. It has 3 timers, numbered 0 to 2. Timer0
and Timer2
are 8-bit timers, so they count from 0 to 255, Timer1
, on the other hand, is a 16-bit timer, so it counts from 0 to 65535.
But how fast do these timers count? What do they do when they reach their maximum value? This is exactly what we define in lines 2–5. Each of the timers is controlled by special CPU variables called “registers”. Our code uses Timer1
, and starts by initializing the timer control registers TCCR1A
and TCCR1B
t0 0
(lines 2-3).
In line 4 we set a flag called CS12
in the TCCR1B
register. This flag tells the microcontroller that we want the counter to go up exactly every 256 clock cycles, or 16,000,000 / 256 = 62500 times a second (remember that our clock ticks 16 million times a second).
Where does the “magic” number 256 comes from? You can find it in table 16–5 in page 143 of the ATmega328 Datasheet:
The next line (number 5) tells the CPU to generate a hardware interrupt whenever the timer reaches the maximum number (or overflow). An interrupt is an event generated by the hardware, which calls a predefined routine in our code, an interrupt service routine (ISR or interrupt handler). This is exactly what TIMER1_OVF_vect
is:
a piece of code that runs whenever Timer1
overflows ( OVF
stands for overflow).
To recap, our code sets a timer that goes up 62500 times a second. Whenever the timer reaches its maximum value, 65535, the interrupt service routine runs and toggles the LED (in line 10). The timer is then reset to zero, and starts counting up again. As you can probably tell, this code will blink the LED a bit slower than once a second, rather once every 1.05 seconds (that is 65536 divided by 62500).
But wait, there is another trick up my sleeve!
Hardware Blinking 😉
In the previous program, we made the hardware count for us, and run some code we provided every certain amount of time. But what if the hardware could also take care of toggling the pin for us?
Actually, it can, if we accept some constraints. For the next program, you will need to connect an LED to pin 9 of your Uno board:
And here is the program itself:
As you can see, this time we are setting pin number 9 as an output pin, but there are no digitalWrite()
calls in the code - yet the LED blinks every single second. How does it work then?
The magic lies in lines 5 and 6. First, we set the OCR1A
register to 62500
. This register is the Timer 1 Output Compare A register, and its value is continuously compared with the value of Timer1
. In other words, we tell the microcontroller to do something whenever Timer1
gets to 62500
. But what does it do when there is a match?
This is exactly what line 6 takes care of. Setting the COM1A0
flags tells our chip that we want to toggle a specific pin whenever the timer hits our target value. The timer is then automatically reset to zero, and starts counting up again. We can find this information in the chip's datasheet (page 140):
For me, this was a little confusing, as the datasheet says that the hardware will toggle OC1A
on Compare match. But who is this mysterious OC1A
pin?
Another quick search in the datasheet reveals the answer:
Then, all you need to do is google for “Arduino PB1” and find that it is digital pin number 9 in Arduino.
Bonus: The Serial Port 🔌
After sharing this post in the Arduino Facebook group, some users shared their insights about how they’d blink an LED. This is in turn the 6th way of blinking an LED on Arduino.
My personal favorite was using the Arduino’s serial port. I decided to try try blinking the LED using serial port on Arduino myself, myself, connected a green LED to pin 1 (TX) of the Arduino, and came up with the following code:
byte blink[256];void setup() {
for (byte i = 0; i < 128; i++) {
blink[i] = 0xff;
}
Serial.begin(1200);
}void loop() {
Serial.write(blink, 256);
}
Note that this approach doesn’t truly blink the LED, only toggles it between high brightness and low brightness (due to the start/stop bits in the UART protocol). Creative thinking, nevertheless!
The Takeaways
We have seen five different ways of blinking an LED on Arduino.
- Blinking an LED using standard Arduino Blink example
- Blinking an LED using two lines code using
!
(not) operator - Blinking an LED using one line of code using Arduino’s
millis()
function - Blinking an LED using built in Arduino hardware timers
- Blinking an LED using Timer output on Arduino
I hope this shows you how much room for creativity Arduino has, and how versatile the platform is — even a simple task toggling an LED can be solved in a variety of ways.
You can use the millis()
trick in your project whenever you want to perform more than a single task in your loop()
.
The timers you saw can come handy when have a task that blocks the loop()
(for instance, polling an ultrasonic distance sensor), and you need to accurately time another task, such as blinking an LED or driving a stepper motor. In fact, several Arduino functions use these timers under the hood, e.g. analogWrite() and tone().
Finally, Arduino goes a long way making your life simple, but in order to take advantage of all the capabilities of the Uno, you definitely want to consult the ATmega328 Datasheet. With over 600 pages, the datasheet can be overwhelming at first sight, but it’s a very valuable resource which you can refer to whenever you want to know more about the specifics of this chip.
If you want to learn more about using the Arduino timers, check out this tutorial:
Which method is your favorite one? Can you come up with more creative ways to blink an LED on Arduino Uno?
Interested in many more LED and Arduino projects? I collected some relevant links and posts for you:
Originally published at https://blog.wokwi.com on November 7, 2019.