Go Down

Topic: Setting Brightness of RGB LED with a remote control (Read 695 times) previous topic - next topic

SchnoppDog

Hello there,

Since I am a rookie in arduino I look for help. I want to control a RGB LED with a remote control. Now I've come to the point where I want to set the brightness of each color individually. Like having color "red" selected and now changing the brightness of "red" with 2 Button on my remote Control (for + and -).

When I want to change the color the brightness should be on the same level as before. For Example for red I want a brightness of 200 the next color should also have a brightness of 200.

I've searched through the internet without finding a solution.

This is how far I came:
Code: [Select]

#include <IRremote.h>

const int recvPin = 5; //IR Input
int redPin = 11;
int greenPin = 10;
int bluePin = 9;



//Initializing the Receiver Pin
IRrecv irrecv(recvPin);
decode_results results; //decoding Decode-Results in variable "results"
unsigned long key_val = 0; //storing code when same button is pressed again



void setup() {
  irrecv.enableIRIn(); //Starting Receiver
  irrecv.blink13(true); //Arduino led blinking when receiving an incoming button-code
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

}
void loop() {
  if(irrecv.decode(&results)){
    if(results.value == 0xFFFFFFFF){
      results.value = key_val; //Storing button hex-code if same button is pressed again
    }
    if(results.value == 0xFFA25D){ //If Remote Control pressed button "1"
      setColor(255, 0, 0); //color red
    }else
    if(results.value == 0xFF629D){ //If Remote Control pressed button "2"
      setColor(0, 255, 0); //color green
    }else
    if(results.value == 0xFFE21D){ //If Remote Control pressed button "3"
      setColor(0, 0, 255); //Color blue
    }
    else { //If any other button is pressed
      setColor(0, 0, 0); //RGB LED Off
    }
   
    key_val = results.value;
    irrecv.resume(); //Clearing button for next incoming button
  }
}

void setColor(int red, int green, int blue){ //Setting the rgb LED to RGB


  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}



I addressed 3 Buttons with red, green and blue. Now I want to change with 2 Buttons the brightness. Is there a way you could help me?


Thank you in advance.

SchnoppDog

#1
Nov 04, 2018, 02:31 pm Last Edit: Nov 04, 2018, 02:44 pm by SchnoppDog
So I've found a Code and remodded it for my Needs. It works with Setting the brightness Level of a Color, but doesn't save it for the next Color. But I do not understand the Code. So it would be of great help if you could tell me what exactly it does (commenting the Code would help)

Here it is:
Code: [Select]

#include <IRremote.h>
 
int RECV_PIN = 5;
int R_PIN = 11;
int G_PIN = 10;
int B_PIN = 9;
 
#define RED               0xFFA25D
#define GREEN             0XFF629D
#define BLUE              0xFFE21D
#define BRIGHTNESS_UP     0xFF18E7
#define BRIGHTNESS_DOWN   0xFF4AB5
#define OFF               0xFF38C7
 
#define INCREMENTO 10
 
unsigned long rgb = 0;
byte r,g,b;
 
IRrecv irrecv(RECV_PIN);
 
decode_results results;
 
 
void setup()
{
  irrecv.enableIRIn(); // Inicializamos el receptor
  Serial.begin(9600);
  pinMode(R_PIN, OUTPUT);   
  pinMode(G_PIN, OUTPUT);   
  pinMode(B_PIN, OUTPUT);   
}
 
 
void variar (byte* color, char valor) {
    if (valor > 0) {
        if ( *color + valor <= 255) {
            *color += valor;
        } else {
            *color = 255;
        }
    } else {
        if (*color + valor >= 0) {
            *color += valor;
        } else {
            *color = 0;
        }
  }
}
 
void RGB(unsigned long valor) {
   r = valor >> 16;
   g = (valor >> 8) & 0xFF;
   b = valor & 0xFF;
}
 
void loop() {
  if (irrecv.decode(&results)) {
    if ( results.value != 0xFFFFFFFF) {
      switch (results.value) {
           case BRIGHTNESS_UP :
               variar (&r, INCREMENTO);
               variar (&g, INCREMENTO);
               variar (&b, INCREMENTO);
               break;
           case BRIGHTNESS_DOWN :
               variar (&r, -INCREMENTO);
               variar (&g, -INCREMENTO);
               variar (&b, -INCREMENTO);
               break;
           case OFF :
               r = g = b = 0;
               break;   
           case RED           : RGB(0x00FF0000); break;
           case GREEN         : RGB(0x0000FF00); break;
           case BLUE          : RGB(0x000000FF); break;
      }
      Serial.println(results.value, HEX);
      Serial.println(r,DEC);
      Serial.println(g, DEC);
      Serial.println(b, DEC);
      analogWrite(R_PIN,r);
      analogWrite(G_PIN,g);
      analogWrite(B_PIN,b);
    }
    irrecv.resume(); // Receive the next value
  }
}




Edit: I looked up some functions on the Arduino reference and I think this Code is too high for me ever to understand.

PaulRB

It's not clear exactly what you want to happen. This is what I think you mean, tell me if I am wrong. You want to be able to select just 3 colours, red, green and blue, with buttons 1, 2, 3 on the remote. You also want to control the brightness, up or down with two more buttons. The brightness level should remain at the set level, when you change colours between red, green blue. Correct?

If so, this is simple, but I wonder if you will want more colours in the future, like yellow, orange and purple? If so, you need to begin to think about that now, because controlling the brightness of other colours is more complex than for the 3 basic red, green, blue.

But for now, what you need to do is make a new variable which holds the current colour. This can be a simple "int" where 1=red, 2=green, 3=blue and 0=off. You also need a variable to hold the current brightness level, perhaps between 0 and 99 or 0 and 255.

When a remote press is received, instead of immediately setting the colour of the led, set the value of the variable which holds the colour, or increase or decrease the value of the variable that holds the current brightness level.

After the remote press had been actioned, you next lines of code can examine the colour variable and brightness variable and send the appropriate values to the setColor() function.

PaulRB

Your second code is much more complicated than it needs to be to achieve what you wanted. It brings complexities of hex codes, bit shifting and other things that will be confusing to a beginner. I think you should go back to your first code and work on that with my suggestions from above.

SchnoppDog

Quote
It's not clear exactly what you want to happen. This is what I think you mean, tell me if I am wrong. You want to be able to select just 3 colours, red, green and blue, with buttons 1, 2, 3 on the remote. You also want to control the brightness, up or down with two more buttons. The brightness level should remain at the set level, when you change colours between red, green blue. Correct?
You are absolutely correct. I want to add more colors in future but i want to focus now on these 3 colors for basic understanding.

Quote
But for now, what you need to do is make a new variable which holds the current colour. This can be a simple "int" where 1=red, 2=green, 3=blue and 0=off. You also need a variable to hold the current brightness level, perhaps between 0 and 99 or 0 and 255.
I some kinda do understand it. But I dont know how to write in the code. Whatever I try I get stuck at setting the brightness Level for those three colors and I dont know how to  do it.

So basically you say I shall make some other variables like:
Code: [Select]

int red_value, green_value, blue_value, brightness;

Then I thought of setting all to 0.
Then writing in the Switch()-Statement for each color something like:
Code: [Select]

case RED:
  red_value = 255;
  setColor(red_value, 0, 0); break;

And repeating that for green and blue.

I am going to send my code. Maybe you can help me.
Code: [Select]

#include <IRremote.h>

const int recvPin = 5; //IR Input
int redPin = 11;
int greenPin = 10;
int bluePin = 9;
int red_value = 0;
int green_value = 0;
int blue_value = 0;
int brightness = 0;
int color = 0;

#define RED         0xFFA25D
#define GREEN       0xFF629D
#define BLUE        0xFFE21D
#define FADE        0xFF6897
#define OFF         0xFF38C7
#define BRIGHT_UP   0xFF18E7
#define BRIGHT_DOWN 0xFF4AB5



//Initializing the Receiver Pin
IRrecv irrecv(recvPin);
decode_results results; //decoding Decode-Results in variable "results"
unsigned long key_val = 0; //storing code when same button is pressed again



void setup() {
  irrecv.enableIRIn(); //Starting Receiver
  irrecv.blink13(true); //Arduino led blinking when receiving an incoming button-code
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);

}
void loop() {
  if(irrecv.decode(&results)){
    if(results.value == 0xFFFFFFFF){
      results.value = key_val; //Storing button hex-code if same button is pressed again
    }
    switch(results.value){
      case RED:
        red_value = 255;    //Setting the red_value to 255 and adding it to the setColor() statement  
        setColor(red_value,0,0); break;
      case GREEN:  
        green_value = 255;  
        setColor(0,green_value,0); break;
      case BLUE:
        blue_value = 255;      
        setColor(0,0,blue_value); break;
      case BRIGHT_DOWN:
      /*
       * Here I confused myself. I wanted to assign variable "color" with the 255 from the "getColor()"-Statement
       * If the value of "color" would have been less or equal than 255 the color should be compared to the color_values
       * I thought like "if I press 1, case RED would be activated storing the red_values 255 and here could the brightness-level set"
       * I know this part is confusing. It confuse me more and more when I think about it
       */
        color = getColor(red_value, green_value, blue_value);
        if(color <= 255){
          if(color == red_value
        }
      case OFF:       setColor(0,0,0); break;
    }
    
    key_val = results.value;
    irrecv.resume(); //Clearing button for next incoming button
  }
}

void setColor(int red, int green, int blue){ //Setting the rgb LED to RGB
  
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}

/*
Here I wanted to get the value, which has the 255 stored in it and return it for setting the brightness
 */
int getColor(int redValue, int greenValue, int blueValue){
  int color;
  if(redValue == 255){
    color = redValue;
  }
  if(greenValue == 255){
    color = greenValue;
  }
  if(blueValue == 255){
    color = blueValue;
  }
  return color;
}


Thank you in advice

SchnoppDog

#5
Nov 15, 2018, 09:03 am Last Edit: Nov 16, 2018, 08:44 am by SchnoppDog
Okay. It's been a while. I did not figure out how to set the brightness yet. But I figured out how this rgb bitshifting works.

If anyone wants to know this I try to explain it:

First we make the variables r,g,b and set it as "byte". Since byte is only a range from 0 to 255 it's representing our brightness needed for one color (0 = low/no light | 255 = High/light on).

Now we're coming to this:
Code: [Select]

      switch(results.value){
        case RED:       RGB(0x00FF0000); break;
        case GREEN:     RGB(0x0000FF00); break;
        case BLUE:      RGB(0x000000FF); break;

Let us just keep the case RED in mind. We hand over the value "0x00FF0000" to the RGB()-Function.

Let's look have a look on the RGB()-Function:
Code: [Select]
void RGB(unsigned long var) {
r = var >> 16;
g = (var >> 8) & 0xFF;
b = var & 0xFF;
}

Now we need an understanding for bitshifting.For getting to know bitshifting use this link: https://www.arduino.cc/reference/en/language/structure/bitwise-operators/bitshiftright/
In this case we need the right bitshifting.

Right-Bitshifting simply put:
Code: [Select]

bitshift_result = shifting_variable >> with bits of x
-> bitshift_rsult = shifting_variable >> 2 //We shift the binary value of "shifting_variable" 2 bits to the right.

Example:
Code: [Select]

bitshift = 5;
shift_result = bitshift >> 2 //Binary Value of 5 = 00000101
//shift_result = 00000001 = 1

Okay now that we know how bitshifting to the right works we can understand this:
Code: [Select]
r = val >> 16
The value of the variable "val" is shifted 16 bits to the right.
We handed the hexadecimal number 0x00FF0000 (=red) over to the RGB()-Function. That means that the variable "val" is now treated as "0x00FF0000".

Since 0x00FF0000 is a hex number, we need to translate it into binary. This would be the outcome:
0000 = First 0 (=4 Bits)
x
0000 = Second 0 (=4 Bits)
0000 = Third 0 (=4 Bits)
1111 = First F (=4 Bits)
1111 = Second F (=4 Bits)
0000 = Fourth 0 (=4 Bits)
0000 = Fifth 0 (=4 Bits)
0000 = Sixth 0 (=4 Bits)
0000 = Seventh 0 (=4 Bits)

Now we want to shift the "FF" 16 bits to the right. Coutning from above it would be like this:
0000 = 0
x       = x
0000 = 0
0000 = 0
0000 = 0
0000 = 0
0000 = 0
0000 = 0
1111 = F
1111 = F

So the variable "r" has the value "0x000000FF" stored.
Now we can ignore the zeros standing in front of the "FF" and we only have the value "0xFF" left which is for decimal = 255. So now we stored the number 255 in variable "r".

This part was for variable "r". No we need to set "g" and "b".

Let's set the number for "g".
For "g = (var >> 8 )" we do the same as above ( I won't write it down now since you should be able to understand it) The result of this "var" would be: 0x0000FF00

Now we get another unknown thing and it is written down as "& 0xFF".
That means we make an "AND-Operation" with the result of the shifted variable "var" and the value 0xFF.
Simply put: we compare eachother if they match. For hexadecimal it would be like:

   FF00
& 00FF
--------
= 0000

Or i binary form:

   1111       1111 0000 0000
& 0000 0000 1111 1111
---------------------------
= 0000 0000 0000 0000

The Table for the AND-Operation is:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Only if we have a 1 and another 1 matching to eachother the result would be 1. Everything else would be 0.

So now that we compard "var" and 0xFF which ended in a result of 0 the variable "g" contains the value 0.

Finally we come to the variable "b" which is only compared with "var & 0xFF"
Now that you now how to do this I won't write it down. The Result would be: "b = 0" (remember that "var" still contains the value "0x00FF0000")

Now we're done.
We have for:
r = 255
g = 0
b = 0

Now we're handing those values to "analogWrite()" and we're done:
Code: [Select]

//analogWrite(PIN, Value)
analogWrite(redPin, r) //Containing value of 255
analogWrite(greenPin, g) //Containing value of 0
analogWrite(bluePin, b) //Containing value of 0

Result: The Red LED is lighten up

Now you can do that for all other colors too.

I hope you understand it.

PaulRB

Well done for getting your head around all that very detailed bit shifting and masking! Now I am wondering, if you can do that, why are you still struggling with setting the brightness?

Using that hex format to describe colours can be quite convenient because there are lots of resources available on the web to allow you to find specific colours by clicking on a colour map or by a descriptive name like "Goldenrod" (which, by the way, is a yellow flower).

If you want to switch between colours while maintaining the same level of brightness, you will need to take the r, g & b values from the hex number and then apply the same dimming level to each of the 3 values. You could use the map() function for this, or simply multiply by a fraction (e.g. 224/256 which is 87.5%).

Grumpy_Mike

Quote
Since 0x00FF0000 is a hex number, we need to translate it into binary.
That might be true for your understanding of it but there is no need to do this at all.

Any variable is stored as a bit pattern. That bit pattern can be expressed to us humans in many ways. Some of these are binary, hex or decimal. With the first two you can see the bit pattern with the third you can't. Most programmers use hex because it is simpler to read than binary. With binary it is easy to miss count zeros or ones especially if there is a long run when they are all the same. With hex it is much simpler. Placing a gap in binary numbers every four bits makes them easy for us to understand but not the majority of compilers.

So 0x00FF0000 would be:-
0000 0000 1111 1111 0000 0000 0000 0000
but you would have to write it like this in binary
0B00000000111111110000000000000000

SchnoppDog

Quote
That might be true for your understanding of it but there is no need to do this at all.
You're right. But since it's only for understanding it might be uesefull for those who never did something with hex numbers. But you're right. No programmer would ever write with binary numbers since it be chaos.

Quote
why are you still struggling with setting the brightness?
I still don't know how to do that. I somewhat understand bitshifting but I don't know how it can help me going further on.

Right now I am trying to understand this code section:
Code: [Select]

void variable (byte* color, char bright_steps) {
    if (bright_steps > 0) {
        if ( *color + bright_steps <= 255) {
            *color += bright_steps;
        } else {
            *color = 255;
        }
    } else {
        if (*color + bright_steps >= 0) {
            *color += bright_steps;
        } else {
            *color = 0;
        }
  }
}

This function is called when those buttons are pressed:
Code: [Select]

switch (results.value) {
           case BRIGHTNESS_UP :
               variar (&r, INCREMENTO);
               variar (&g, INCREMENTO);
               variar (&b, INCREMENTO);
               break;
           case BRIGHTNESS_DOWN :
               variar (&r, -INCREMENTO);
               variar (&g, -INCREMENTO);
               variar (&b, -INCREMENTO);
               break;
}

PS: "INCREMENTO" has the value of "10".

I try to figured that one out, but I don't understand it. When I implement that with my code I can lower the light with 10 steps but when I reach "0" I can't press any other button to lighten up the led anymore. I have to compile it again and it works. When that Error occurs when I press another button on my remote it tells me "0xFF". When I press the button for gaining brightness the led stwiches from state "off" to turning on blued and green and then the programm freezes.

I try to figure out the problem why it occurs.

maxim2511

Why to play with binary shifting method??
You can use decimal values and extra binary boolean value to remember witch last color was chosen, and then two buttons can adjust that value for this color.


Grumpy_Mike

#10
Nov 20, 2018, 10:19 am Last Edit: Nov 20, 2018, 10:22 am by Grumpy_Mike
The use of * in front of a variable name means that it is the pointer to the variable not the variable itself. All that means in the context of your first clip is that the variable used to call that function will be changed by the function.

First if checks to see if the variable bright_steps is positive if so:-
Then if adding the value of the colour variable to the value of the bright_steps variable would result in a value less than 256 then you do it otherwise it just sets the colour variable to 255.

If the variable bright_steps is negitave:-
It then if subtracting the value of the colour variable to the value of the bright_steps variable would result in a value less than 0 then you do it otherwise it just sets the colour variable to 0.

I other words the value of the variable in the first parameter passed to the function will increase or decrees by an amount given by the second value passed to the function but the result will always be between 0 and 255. As had been said this code is way way more complex than it needs to be to achieve the effect he is looking for.

Exactly the same thing could be done by:-
Code: [Select]

void variable (byte* color, char bright_steps) {
   *color += bright_steps;
   if(*color >255) *color = 255;
   if(*color <0) *color = 0;


The second code makes all three LEDs get brighter or dimmer according to the value of results.value

SchnoppDog

I knew the pointer-thing. The Problem i didn't understand is:
Code: [Select]
           case BRIGHTNESS_UP :
               variar (&r, INCREMENTO);
               variar (&g, INCREMENTO);
               variar (&b, INCREMENTO);
               break;

When I take this code and execute it there is one thing I don't understand. Let's say that the value of "r" is "235", the value of "g" and "b" are "0". Now, when I hit the "+" button to gain brightness, then the result would look like this:
- r would contain 245
- g would contain 10
- b would contain 10
or am I mistaken?

If not then I don't know why b & g don't light up aswell when I hit the "+"-button.
So let's say I have for "r" the value of "15" and for "g" and "b" again "0" and would always press the +-button to gain more brightness. The value of "r" would end up to "255" and "g" and "b" should have the value "245" correct?
If so, then this isn't happening. The LED is only red and does not contain any other color.

Grumpy_Mike

Quote
- r would contain 245
- g would contain 10
- b would contain 10
or am I mistaken?
No that is correct.

Quote
The value of "r" would end up to "255" and "g" and "b" should have the value "245" correct?
No g and b will be 10 like you said above.

Quote
The LED is only red and does not contain any other color.
Yes it will, only it will have very little contribution to the colour so you will not notice it.

PaulRB

I think you should be able to see the difference. If you stand back and look at the colour reflected around the room, it will be difficult to see the difference. But if you look up close at one led and squint your eyes so that you are not blinded by the intensity of the red light, you should be able to see the blue and green light also.

If you cannot see the blue and green light, maybe there is a problem.

I would also like to point out that this code does not only change the brightness. It will change the colour also, or at least distort the colour away from the desired colour. Because the same quantity is added/removed from the red, green and blue components, the red, green and blue levels will not keep the same ratios, altering the colour.

To maintain the same colour, it would be better to maintain the brightness level as a single, separate value, separate from the desired red, green and blue colour values. When either the desired colour or the brightness values change, calculate the pwm values for analogWrite() by combining the red, green, blue and brightness values together.

SchnoppDog

Well this project is now paused. I can't figure out how to set the brightness otherwise. I can't figure out the error of the "void brightness". It makes me unhappy that I can't figure it out and less motivated to work on it in the future.

But still thank you for helping so far.

Go Up