Skip to content

Instantly share code, notes, and snippets.

@victorbnl
Last active August 26, 2021 16:13
Show Gist options
  • Save victorbnl/8b37fdbd3f080b618fc8ea6c8b760d0a to your computer and use it in GitHub Desktop.
Save victorbnl/8b37fdbd3f080b618fc8ea6c8b760d0a to your computer and use it in GitHub Desktop.
Arduino: How to control LED strip from Bluetooth

Arduino: How to control LED strip from Bluetooth

Introduction

A few days ago my brother bought a LED strip and then realized it wasn't what he was looking for, so I thought I could do something with it. In this tutorial I'll show you how I turned a classic LED strip into a Bluetooth controlled one.

Requirements

The LED strip I have as four pins :

  • 12V power (check if your LED strip requires the same power voltage)
  • Red
  • Green
  • Blue

Unfortunately we can't control LEDs independantly but if you want to take one that supports it, don't hesitate, you'll be able to do awesome things. A friend recommended me the WS2812b, but I haven't tested it.

I have a Arduino Uno but I guess it would work with another model, but if you need to control LED intensity, the Arduino must have at least 3 PWM pins, these are the pins with the "~" next to them.

You'll also need power supplies to power the Arduino and the strip. If the strip comes with a power supply with, for example, a pin for the power and three other for the colors, then you can use the power pin to deliver power, and connect the colors to the ground as the Arduino will manage it. If your power supply is between 7 and 12 volts, you could try to power the Arduino connecting the power in the VIN and the ground of the power supply in a ground on the Arduino, but when I do that I have problems with the BT Serial, so as you want, I'll update this tutorial if I find a solution.

Setup the LED strip

Step 1: Setup the power sources

Now you have to give power to the arduino. You can use the Jack port of the Arduino or the COM port. Or, if you want to use the power supply for both LED strip and Arduino, you can give 12V to the VIN pin like this :

Step 2: turn on colors with a transistor

Now that you have power, let's setup the LED strip

We don't want the 3 colors to be on all the time, so how could we make them be turned on only sometimes?

Hmm... Maybe a switch? But we don't want to control them by hand... Here comes the transistor! See the transistor like a switch, but it's not your finger that presses it, it's the Arduino!

Here you have two solutions : 3 transistors or a transistor array. I didn't used 3 transistors because I don't have them (or maybe I didn't find them, hmmm)

So what I used is the transistor array! It's 7 transisor, in one component. Here's what it looks like :

Don't have a transistor array? I'm sure you have one, check your kit, there is often this component :

Yes, you can remove the ULN2003, use your nails and a flathead screwdriver, but do it gently!

Okay, now I'll show you how a transistor array works.

Here we have the black cable we need to connect to the Arduino's ground (if you followed the schemes I made, just connect it to the - of the breadboard as we connected it to the Arduino's ground)

And the white cable which gives the power, I'll send 12V here because my LED strip takes 12V per color, but again, check your LED strip voltage requirement.

Now if I send power in the upper part, the power given in the + will be sent in the corresponding pin of the lower part, for example :

I'm not sure this is 100% correct, please comment if you think it's wrong

Now that you know how a transistor works, let's apply this to the colors

Here I put the strip pins on the board (the 4 cables), connected the 12V to the + of the breadboard so the strip receives power and connected the colors to 3 pins of the transistor, then the same 3 pins in the upper part

Step 3: Let's start to code !

We made all the necessary connections, so now we can start to code.

Open your Arduino IDE and put these 3 lines at the beginning to define which pin is what

#define REDPIN 5
#define GREENPIN 6
#define BLUEPIN 3

Now we need to tell the Arduino we'll send signals through these pins (and not receive), so add this in the setup :

void setup() {
    pinMode(REDPIN, output);
    pinMode(GREENPIN, output);
    pinMode(BLUEPIN, output);
}

Here's the instruction we need to use to turn on a color :

digitalWrite(REDPIN, HIGH);

This will send about 3V in the 5th pin. Try, add this in the loop! Does the LED strip turn red? Congratulations, you can continue. Doesn't it? Check if all is aligned correctly on the breadboard, if it is, send me a mail, it must be on my GitHub.

Bluetooth communication

Step 1: Install something you'll send commands with

First you'll need something to communicate with the Bluetooth module, here's an app to install on your smartphone.

If you take this app, it automatically send line-endings at the end of each command, this can result in weird characters at the end of your text. Go in settings > Send > Newline > None to disable it.

Step 2: Connect the Bluetooth module to the Arduino

For this part you need... A Bluetooth module, of course, because Arduino doesn't support Bluetooth itself, you need to use a Bluetooth adapter. Often you have a HC-05 or a HC-06, I have a HC-05 and I don't think HC-06 is very different, but if you have an other one, I can't help you with it.

So you need to connect it to the Arduino, here's the table

HC-05 pin Arduino pin
EN n/a
VCC 5V
GND GND (surprisingly)
TXD Any classic pin you want (let's use 4)
RXD Any classi... (2)
STATE n/a

- And what about the EN and STATE pins?
Don't connect them, we don't need them.

Step 3: Let's start to code! (again)

Now you have the Bluetooth module connected to the Arduino but your code need to interact with it.

We'll use the Bluetooth as a serial monitor, to do this we need a library, software serial. Don't worry you don't have to install it, it's already in the Arduino default libraries, you just need to import it!

Put the following at the very beginning of your code :

#include <SoftwareSerial.h>

Then define the TXD and RXD pins of the module

#define BTTXPIN 4
#define BTRXPIN 2

Here I named the variables BTTXDPIN and BTRXDPIN but you can give them whatever name you want

You also need to define the module serial

SoftwareSerial HC05(BTTXPIN, BTRXPIN);

Again here it's named HC05 but give it what name you want.

Now we need to start the monitor, with 9600 bauds (the rate of the monitor), go in setup() and put :

HC05.begin(9600);

Step 4: Try some commands

At this moment, the Arduino should receive the commands from the Bluetooth module, but do nothing with it and do not answer. She's a bit rude at the beginning so you must educate your Arduino before she can answer to people.

Let's write something that answers what people sent. Go in the loop function and write :

// The variable in which we store the message
String cmd = "";
char c;

// Does the serial have unread messages?
while (HC05.available()) { 
    // We mustn't go faster than the Bluetooth module!
    delay(1); 
    // Now we read the message character by character
    c = HC05.read();
    cmd += c;
}

// Print the message in the Bluetooth Serial (will be displayed on your phone)
HC05.println(cmd);

Send the command. Does the Arduino answer you? If so, she's now well-mannered.

Let's make a command to turn on/off the blue color from your smartphone. Let's say that if you send "B", it turns on blue, and if you send "b", it turns it off

Keep the code above but you can remove

// Print the message in the Bluetooth Serial (will be displayed on your phone)
HC05.println(cmd);

if you want.

Now add a if which will check the command, then turn on/off the blue.

if (cmd == "B") {
    digitalWrite(BLUEPIN, HIGH);
} else if (cmd == "b") {
    digitalWrite(BLUEPIN, LOW);
}

Now send a "B" with your smartphone, does it turn blue?

Try to adapt this code for other colors

Let's play with PWM

Introduction

PWM are special pins on Arduino that can blink very quickly so that you can control LED intensity. Not believing me, not thinking it can work? Try yourself, you can do that with normal pins as well :

void loop() {
    digitalWrite(BLUEPIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(BLUEPIN, LOW);
    delayMicroseconds(90)
}

The LED should be turned on at a lower intensity (ok in truth it blinks and you can't see it, but shh)

Why I should use PWM?

- I can do that with normal pins!

Yes, but if you do that, your Arduino will not be able to do that with the other colors, and to do anything else! Because it'll be monopolized for it.

So, how do I use PWM ?

Step 1: Set the frequency

By default, the frequency is at the minimum (the maximum divided by 1024) so it doesn't affect too much the internal timer, but with this frequency we can see the LED blinking, and because you don't want to have a headache everytime you use your LED strip, we'll change it!

To be honest it's complicated to change the frequency because it requires to understand the PWM at a low-level, so I just copy/paste this function at the end of my program :

/*
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/0#4
*/
void setPwmFrequency(int pin, int divisor) {
   byte mode;
   if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
      switch(divisor) {
         case 1: mode = 0x01; break;
         case 8: mode = 0x02; break;
         case 64: mode = 0x03; break;
         case 256: mode = 0x04; break;
         case 1024: mode = 0x05; break;
         default: return;
      }
      if(pin == 5 || pin == 6) {
         TCCR0B = TCCR0B & 0b11111000 | mode;
      } else {
         TCCR1B = TCCR1B & 0b11111000 | mode;
      }
   } else if(pin == 3 || pin == 11) {
      switch(divisor) {
         case 1: mode = 0x01; break;
         case 8: mode = 0x02; break;
         case 32: mode = 0x03; break;
         case 64: mode = 0x04; break;
         case 128: mode = 0x05; break;
         case 256: mode = 0x06; break;
         case 1024: mode = 0x7; break;
         default: return;
      }
      TCCR2B = TCCR2B & 0b11111000 | mode;
   }
}

Then, in the setup

setPwmFrequency(REDPIN, 1);
setPwmFrequency(GREENPIN, 1);
setPwmFrequency(BLUEPIN, 1);

You can use only the following divisors : 1, 8, 32, 64, 128, 256, 1024

I recommend using 1 or 8, 1 being the maximum (so it'll blink very very fast), but if you do that you may have problems with the BT Serial. Try 1 and if you have problems with it, just put 1024 again to see if the problem comes from this.

Step 2: Turn on a LED with specific intensity using PWM

The function is analogWrite(pin, intensity) where pin is the pin (nope, it's not a joke, it's really the pin) and intensity a number between 0 and 255

Try this :

analogWrite(BLUEPIN, 30);
analogWrite(REDPIN, 255);
analogWrite(GREENPIN, 0);

(in the loop)

The blue color should be not very itense, the red must be at the maximum and the green one off.

Step 3: PWM + Bluetooth = ...

Step 3.1: Simplify things updating automatically colors

This part will probably be the most complicated part of this tutorial. We'll see how we can make this command "255,0,0" turn on red.

First go at the beginning of your code (after the #define but before the functions) to create some variables

int red = 0;
int green = 0;
int blue = 0;

Then we create a function which updates the colors

void updateColors() {
    analogWrite(REDPIN, red);
    analogWrite(GREENPIN, green);
    analogWrite(BLUEPIN, blue);
}

And to always update the colors, put

updateColors();

at the end of the loop (and keep it at the end).

Perfect, now all is always updated so if we want to change the intensity of the colors, we just have to change the content of the variables red, green and blue.

Step 3.2: The parser

Here comes the complicated part, we need to make the parser, it the things that'll transform "255,255,255" into

red = 255;
green = 255;
blue = 255;

Go in the loop

Let's define some variables

// This will contain the parsed thing at each step of the parsing
char *token;
// Basically the same thing, we'll write the token to a char array
char value[3];
// The value, but in String instead of a char array
String strval;

Now make the parsing itself

    token = strtok(input, ",");
    for (int i = 0; i < 3; i++) {
      value[i] = token[i];
    }
    strval = value;
    red = strval.toInt();

Then just need to do the same thing but with the other colors, and NULL instead of the input in strtok so it goes forward in the string

    token = strtok(NULL, ",");
    for (int i = 0; i < 3; i++) {
      value[i] = token[i];
    }
    strval = value;
    green = strval.toInt();
    token = strtok(NULL, ",");
    for (int i = 0; i < 3; i++) {
      value[i] = token[i];
    }
    strval = value;
    blue = strval.toInt();

Now you can wonder something legitimately, why do char[3] > String > int instead of char[3] > int directly? Only because it's simpler and I didn't find a way to do the second thing.

If you try to run this code and send a command the LED strip should turn on a bit then off again. It's because we do this all the time, even when no command is sent. To counter this, create a variable in the very beginning of the loop :

bool hcAvail = HC05.available();

then take all the code of the loop except the line where you create hcAvail and put it in a if

if (hcAvail) {
    // ...
}

And update this variable in the while where you read the data :

while (HC05.available()) { 
    hcAvail = HC05.available(); // <---
    delay(1); 
    c = HC05.read();
    cmd += c;
}

The end

Thanks for reading this tutorial completely, even though it was a bit long, if you need help contact me on my e-mail which is on my GitHub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment