Bits and Droids logo
Mail icon

Back to basics: LED

by Bits and Droids | 21-03-2023

In the last two posts, we've been mainly focussing on inputs. Pushbuttons to send a command to the game and rotary encoders to twist up those frequencies like there is no tomorrow. Like humanlike relationships, it's important to receive something from time to time instead of constantly sending data. Perhaps LEDs sound dull, stupid, and simple, and you might be true. But when speaking for myself, I know that I've burnt the LED or two, overvolted a 7 segment display (which are basically separate LEDs), and installed them backward. I always used to follow tutorials that told me which resistor to use. But not anymore! Do you recognize yourself in these previous statements, don't worry. We'll take a deep dive into LEDs' working and how we could use them to display several statuses.

Cathodes and anodes

Default LEDs have an anode and a cathode side. The best way to visually spot the difference is to check the length of the legs. The anode side (the longer leg usually represents the + side). It would help if you also spotted the anode side with a smaller lead inside the LED while the cathode (the ground side) has a larger lead. This last part will become more important for RGB LEDs which we'll discuss later.

A term you might have heard of is common anode or common anode. This term is often used for LED panels, 7 segment displays, and even RGB LEDs. But what does it exactly tell us? A common anode device tells us that multiple LEDs use a shared anode (+/power) lead. They usually share their anode while having their own individual cathode leg. We could flip the logic for common cathode devices where they share a common cathode line (ground). Each LED will be powered by their individual anode inputs (power) and ditch their current over the same cathode (ground) leg. With this knowledge, we're able to take a look at RGB LEDs.

RGB LEDs

RGB LEDs have multiple leads that let you control their color. RGB refers to Red, Green, and Blue. These primary colors can be combined to create a large variety of mixed colors. I've bought several RGB LEDs over time, and they all were common cathode lights. According to sources, there are also common anode RGB LEDs available. The common cathode/anode line can be found by looking for the longest leg on the LED. To determine if it's a common cathode LED, you to look inside the LED itself to see if the longest leg also has the largest lead. If this is the case, we know for sure that we are dealing with a common cathode RGB LED (Which will be the most common).

(KEEP READING BEFORE YOU PLUG ANYTHING IN)
By using a simple digital signal we could display the primary colors by connecting 1 of the anode legs to our 5v line and the common cathode line to ground. Just swapping the anode leg around would cycle between all three colors.

RGB light, Green -> Red -> Green + RED

Resistors

Now if you have not been paying attention to my warning there is a chance you've already blown through your first LED. Most LEDs will suffer a horible death when hooked up directly to your power source. Even if the LED would hold on for its life the light emmited will probably be too bright to comfortably look at.

In order to prolong the lifespan of our LED we make use of resistors. Resistors reduce the limit flow. How much they reduce the flow depends on the ohmage (the value of resistance).We could calculate the minimum resistor power we need with the following formula:

R = (Vs - VLed) / Iled

  • R is the resistance expressed in ohms.
  • Vs (source voltage)
  • Vled (the voltage drop from the LED in volts)
  • Iled (the current through the LED in mA)

Most of these values can be found on the spec sheet of the LED you've bought. For this example I've taken the following product info from Amazon:

The first thing that stands out is that there is a difference depending on the color used. White, Green and blue have a forward voltage of ~3V while red and Yellow have a forward voltage of ~2V. If we throw these values(for a blue LED) in our formula we would get:

R = (5000 - 2000) / 20 = 150Ohm

Now there are various sites out there that offer free calculators for this purpose. But in reality, most hobbyists don't really have to pinpoint the exact minimum ohmage. Even though there is some variance between various LEDs, the resistance used will usually become a matter of taste. Don't forget that his calculation will give you the MINIMUM value required. In most cases, this LED will still be too bright (at least for my personal taste). If this is the case, you're always able to increase the ohmage.

The image above shows 4 similar LEDs but with different resistors. The first one is a 1k resistor (1k = 1000 Ohm), followed by a 500r (500r = 500Ohm), 274R, and 5k. The 5k is barely turning on, while the 274R is way too bright. Getting the desired result will come down to you testing and fooling around with variable resistance values.

Like I've mentioned earlier, color can also influence brightness. In the picture above, we're able to tell that the green/blue lights seem brighter than the yellow/red while they all use the same Ohmage.

How to code with LEDs

Let's take a look at how to code up our LEDs. Everything I've mentioned above can be achieved with only a 5V power line and a ground line. If a lit LED would be all we wanted to achieve we might as well hook them up directly to a battery and leave out the Arduino. So it's about time we take back some control.

In the first paragraph, I already gave away that we were going to work with outputs. This is important for our Arduino to understand that it can send signals to the LED. With this, we can differentiate digital and analog write.

The schematic used in my examples

Digital signal

Digital write is the simplest solution. It will either set a signal to HIGH or LOW. There is no brightness scale, and the brightness could only be controlled by increasing/decreasing the resistance. The code would look like this:

#include <BitsAndDroidsFlightConnector.h>
BitsAndDroidsFlightConnector connector(false);

//const tells us the pin value changes
//Since we won't be moving the cable we declare the pin as a constant
const byte ledPin = 3;

void setup() {
  Serial.begin(115200);

  //the led pin will send a signal out but will never receive a signal
  pinMode(ledPin, OUTPUT);
}

void loop() {
  //TURN THE LED ON
 digitalWrite(ledPin, HIGH);
 delay(1000);
 //TURN THE LED OFF
 digitalWrite(ledPin, LOW);
 delay(1000);
}

I've already included the flight connector library, which we are going to use down the road. This sketch might look familiar since most Arduino tutorials will start with a similar sketch. It will turn the LED on -> wait 1-sec -> turn the LED off -> wait 1 sec .... until we unplug the device. The HIGH will turn the LED fully on while the LOW will turn it completely off.

Analog write

Ever noticed the squigly lines in front some of the pins?

These indicate that the pin can be used to send a PWM signal. A PWM (pulse width modulation) signal creates a signal wave at variable rates making the led appear brighter or dimmer. The name ANALOG write might seem confusing since A: you can't use the Analog pins on your board to analogWrite. And B: PWM isn't really analog. It only creates an "analog" looking effect. It basically switches the led on and off at precise rates to make them appear dimmer / brighter.

#include <BitsAndDroidsFlightConnector.h>
BitsAndDroidsFlightConnector connector(false);

//const tells us the pin value changes
//Since we won't be moving the cable we declare the pin as a constant
const byte ledPin = 3;

void setup() {
  Serial.begin(115200);
  //the led pin will send a signal out but will never receive a signal
  pinMode(ledPin, OUTPUT);
}

void loop() {
  //TURN THE LED FULLY ON
 analogWrite(ledPin, 255);
 delay(1000);
 //TURN THE LED DIMMER ON
 analogWrite(ledPin, 100);
 delay(1000);
}

The analogWrite function takes a value between 0 and 255. 0 will turn the signal off while 255 will turn it fully on.

Important note about 10uf capacitor (mega, uno, nano)

If you use a different Arduino than a Leonardo or Pro-micro (Atmega 32u4 chip-based Arduinos) this section may apply to you (i.e. the Uno, mega, or nano). it’s necessary to place a 10uf capacitor between the ground and reset button if you use these boards to retrieve data from the game. This ensures that the Arduino doesn’t reset every time it receives data. When uploading a new sketch it’s important to remove the capacitor from the board.

This doesn’t apply to boards from other brands like the STM32 or Teensy.

Game states

LEDs are perfect for displaying certain states in Microsoft flight simulator. Is the autopilot on, is the gear down, are my landing lights on, etc.? Basically, all questions can be answered with a yes or no. For this, we're going to make use of booleans and if statements. The parameter for an if statement actually is just a boolean. if(1 == 3){ } will become if(false) so the code block wont be executed (an if statement only runs if the statement returns true). Now there are a whole bunch of boolean states ready to be used in the connector (go see the documentation). I've listed just a few down below as an example.

Taxi lights.getLightTaxiOn()boolean false = off, true = on
Strobe lights.getLightStrobeOn()boolean false = off, true = on
Panel lights.getLightPanelOn()boolean false = off, true = on

Now turning a light on or off could become something like this:

#include <BitsAndDroidsFlightConnector.h>
BitsAndDroidsFlightConnector connector(false);

//const tells us the pin value changes
//Since we won't be moving the cable we declare the pin as a constant
const byte ledPin = 3;

void setup() {
  //the led pin will send a signal out but will never receive a signal
  Serial.begin(115200);
  Serial.setTimeout(15);
  pinMode(ledPin, OUTPUT);
}

void loop() {
 //This ensures the Arduino keeps listening for game updates comming from the connector
  connector.dataHandling();
 // if the landing lights return true
 if(connector.getLightLandingOn()){
    digitalWrite(ledPin, HIGH);
    delay(1000);
 } 
 //The exclamation mark tells us the statement has to be false 
 else if(!connector.getLightLandingOn()){
   digitalWrite(ledPin, LOW);
  delay(1000);
 }
}

When we use the connector to receive data, it's important to include the connector.dataHandling(). It's also important to select the data to be received before hitting start. This ensures that we don't overload our Arduino with values we'll never use.

Select the desired outputs in the connector.

1's and 0's

If we follow the mantra that everything in the world of computers is either 1's or 0's, we could even shorten our code significantly. HIGH is just another front for a 1. True also is a front for a 1. The same goes for LOW being a front for 0 and false being a front for 0. Let's see how we can manipulate this information into simple code:

#include <BitsAndDroidsFlightConnector.h>
BitsAndDroidsFlightConnector connector(false);

//const tells us the pin value changes
//Since we won't be moving the cable we declare the pin as a constant
const byte ledPin = 3;

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(15);
  //the led pin will send a signal out but will never receive a signal
  pinMode(ledPin, OUTPUT);
}

void loop() {
  connector.dataHandling();
  digitalWrite(ledPin, connector.getLightLandingOn());
}

Here we combined the if on or off statement into a clean one-liner.

Instead of using off-the-shelve booleans, we could also make our own statements.

#include <BitsAndDroidsFlightConnector.h>
BitsAndDroidsFlightConnector connector(false);

//const tells us the pin value changes
//Since we won't be moving the cable we declare the pin as a constant
const byte ledPin = 3;

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(15);
  //the led pin will send a signal out but will never receive a signal
  pinMode(ledPin, OUTPUT);
}

void loop() {
  connector.dataHandling();
  byte landingGearPercentage = connector.getGearTotalPct().toInt();
  //One-line for if(landingGearPercentage >= 99){}
  digitalWrite(ledPin, landingGearPercentage >= 99);
}

Go fly!

I could probably go on about this subject, but I believe we've covered most of the basics required for you to get started. After making it this far, you can proudly call yourself master of the LEDs. As always, if you have any questions, leave them in the comments down below, and have fun!