Skip to content

Embedded Systems

How to make an LED bar graph with Arduino

An LED bar graph shows a reading as a row of lights that fills up, like the signal bars on a phone. On an Arduino it takes three lines: map the reading to a percent, divide to count how many LEDs to light, then a for loop lights that many and switches the rest off.

Percent, then a count

int reading = analogRead(A0);                  // 0 to 1023
int percent = map(reading, 0, 1023, 0, 100);   // 0 to 100
int lit = percent / 25;                        // 0 to 4 LEDs

Each of four LEDs stands for a quarter. Dividing whole numbers throws away the remainder, so lit counts whole quarters:

LightReadingPercentLEDs lit
Night250240
Lamp-lit room544532
Sunny window937913

Live experiment

How many to light

A light sensor on A0 feeds a bar of four LEDs on pins 9 to 12. Slide the light: the reading becomes a percent, percent / 25 counts the whole quarters, and the loop lights that many. Pip, at the top, needs 100 %. Slide to full sun and see if he gets it.

Try it yourself: free lesson

“A bar of light” is lesson 3 of 6 in Signal Shore, Embedded Systems World 3. Free with an account. Lessons unlock in order, so you’ll do the 16 before it first.

One loop lights the bar

Keep the four pins in an array, wired through 220 Ω resistors to LEDs and GND, and write every one on every pass:

int pins[] = {9, 10, 11, 12};

void setup() {
  for (int i = 0; i < 4; i++) pinMode(pins[i], OUTPUT);
}

void loop() {
  int reading = analogRead(A0);
  int percent = map(reading, 0, 1023, 0, 100);
  int lit = percent / 25;
  for (int i = 0; i < 4; i++) {
    digitalWrite(pins[i], i < lit);    // the first lit are on
  }
}

i < lit is true for the first lit LEDs and false for the rest, so one line lights some and switches off the others. With lit at 0, nothing lights.

Make the bar fill

With percent ÷ 25, the top LED needs exactly 100%, a reading of 1023. A light sensor in a divider never quite gets there: even full sun might read 984, which is 96%. For a bar that can fill, divide the range into five equal steps instead, so 0 to 204 lights none and 820 and up lights all four:

int lit = reading / 205;   // 0 to 4

Stop the edge flickering

When the reading sits right on a boundary, like 615 with a step of 205, noise of a count or two flips the last LED on and off many times a second. Two cures: average a few readings before working out lit, or make an LED switch on a little above its boundary and off a little below it, a gap called hysteresis.

The same bar works for any reading: a volume level, a battery's charge, a temperature, or a knob. Four LEDs at about 12 mA each draw under 50 mA in all, well within what the board can supply.

Free lesson

Now build it yourself

Each lesson comes in three short parts: see the idea, try it on a live board, then build it yourself, with quick checks as you go.

Try it yourself: free lesson

“A bar of light” is lesson 3 of 6 in Signal Shore, Embedded Systems World 3. Free with an account. Lessons unlock in order, so you’ll do the 16 before it first.

Or start from the very first lesson, no account needed

Practice questions

Three quick questions from the lessons. Pick an answer to check it.

  1. Question 1 of 3The bar has four LEDs, one per quarter. At 91 % how many are lit?
    Show the answer

    Answer: 3. 91 ÷ 25 is 3 and a bit, and the board keeps the whole number: 3. The fourth LED needs the full 100 %.

    • Why not “1”? One LED means 25 to 49 %. 91 % is well past that: three whole quarters.
    • Why not “2”? Two LEDs means 50 to 74 %. 91 % has passed the third quarter as well.
    • Why not “4”? The fourth LED needs a full 100 %. 91 ÷ 25 is 3 and a bit, and the bit is thrown away.
  2. Question 2 of 3Full sun reads 984, and map makes that 96 %. How many of the four LEDs light?
    Show the answer

    Answer: 3. 96 / 25 is 3 and a bit, and whole numbers keep the 3. The fourth needs 100 %, a reading of 1023, which the divider never quite reaches.

    • Why not “1”? One LED would mean only 25 to 49 %. 96 % lights three.
    • Why not “2”? Two LEDs would mean 50 to 74 %. At 96 %, three whole quarters have passed.
    • Why not “4”? 96 ÷ 25 is 3.84, and whole-number division keeps only the 3. The fourth LED needs exactly 100 %.
  3. Question 3 of 3In the loop for (int i = 0; i < 4; i++), which write lights only the first lit LEDs?
    Show the answer

    Answer: digitalWrite(pins[i], i < lit);. i < lit is true for the first lit pins and false for the rest, so each LED gets exactly the level it should. The others light everything, light one pin, or write to the wrong pin.

    • Why not “digitalWrite(pins[lit], HIGH);”? pins[lit] is just one pin, the first that should be dark, so it lights a single wrong LED and switches nothing off.
    • Why not “digitalWrite(i, lit);”? i is a place in the list, 0 to 3, not a pin number, so this writes to pins 0 to 3 instead of 9 to 12.
    • Why not “digitalWrite(pins[i], HIGH);”? Writing HIGH every time lights all four LEDs, whatever the reading.
Keep practising: free lesson

“A bar of light” is lesson 3 of 6 in Signal Shore, Embedded Systems World 3. Free with an account. Lessons unlock in order, so you’ll do the 16 before it first.

Questions people ask

How do I make the top LED of the bar light up?

With percent ÷ 25, the top LED needs exactly 100%, a reading of 1023, which a real sensor may never give. Split the range into five equal steps instead, lit = reading ÷ 205, so each LED takes a fifth of the range and the bar can fill.

How many LEDs can a bar graph use?

As many pins as you have: put them all in the array and change the step size. Ten LEDs on separate pins is fine, since each draws about 12 mA through 220 Ω. Beyond that, a shift register or an LED driver chip saves pins.

Can the bar show a dot instead of a filled bar?

Yes: light only the LED where i == lit − 1, and the rest stay dark. A single moving dot is easier to read at a glance for some uses, like a tuning meter.

Every topic