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 achieving the same: blinking an LED by turning it on/off roughly once a second. We'll start with the Blink example that comes with the Arduino IDE:

And the code:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

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:

  1. Set the pin to HIGH (5V), this will turn the LED on.
  2. Wait for 1000 milliseconds, or one second.
  3. Set the pin to LOW (0V), cutting the power to the LED and turning it off.
  4. Wait for another second, and then repeat everything again.

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:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  delay(1000);
}

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:

  1. Toggle the state of the LED.
  2. Wait one second, repeat.

The One-Liner

This is my favorite one, 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:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, (millis() / 1000) % 2);
}

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 solution 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.

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:

void setup() {
  TCCR1A = 0;
  TCCR1B = 0;
  bitSet(TCCR1B, CS12);  // 256 prescaler
  bitSet(TIMSK1, TOIE1); // timer overflow interrupt
  pinMode(LED_BUILTIN, OUTPUT);
}

ISR(TIMER1_OVF_vect) {
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

void loop() {
}

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 is a 8-bit timer, so it counts from 0 to 255, while Timer1 and Timer2 are 16-bit timers, so they count from 0 to 65535:

Timer 0
000
Timer 1
00000
Timer 2
00000

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:

1, 8, 64, 256, or 1024 - the choice is all yours!

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:

This time you need to connect an LED to pin 9. Don't forget to add a resistor!

And here is the program itself:

void setup() {
  TCCR1A = 0;
  TCCR1B = 0;
  bitSet(TCCR1B, CS12);  // 256 prescaler
  OCR1A = 62500;
  bitSet(TCCR1A, COM1A0); // Toggle pin OC1A (9)
  pinMode(9, OUTPUT);
}

void loop() {
}

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):

Setting COM1A0 toggles the OC1A pin whenever the timer reaches the target value

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:

OC1A is actually PB1, or Arduino's pin 9

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. My personal favorite was using the Arduino's serial port. I decided to try it 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. I hope this shows you how much room for creativity Arduino has, and how versatile the platform is - even a simple task 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.

Which method is your favorite one? Can you come up with more creative ways to blink an LED on Arduino Uno?