褪色Arduino RGB LED从一种颜色到另一种颜色?

Kin*_*gon 7 c++ rgb arduino colors led

我目前设法让我的LED循环显示我选择的八种颜色.一切都正常,除了我想要更自然的感觉,并希望淡化/从一种颜色过渡到下一种颜色,而不是让它们只是互相替换.

到目前为止,这是我的代码:

int redPin = 11;
int greenPin = 10;
int bluePin = 9;

void setup()
{
    pinMode(redPin, OUTPUT);
    pinMode(greenPin, OUTPUT);
    pinMode(bluePin, OUTPUT);
}

void loop()
{
    setColor(250, 105, 0);   // Yellow
    delay(1000);

    setColor(250, 40, 0);    // Orange
    delay(1000);

    setColor(255, 0, 0);     // Red
    delay(1000);

    setColor(10, 10, 255);   // Blue
    delay(1000);

    setColor(255, 0, 100);   // Pink
    delay(1000);

    setColor(200, 0, 255);   // Purple
    delay(1000);

    setColor(0, 255, 0);     // Green
    delay(1000);

    setColor(255, 255, 255); // White
    delay(1000);
}

void setColor(int red, int green, int blue)
{
    analogWrite(redPin, 255-red);
    analogWrite(greenPin, 255-green);
    analogWrite(bluePin, 255-blue);
}
Run Code Online (Sandbox Code Playgroud)

ang*_*rge 13

其他答案省略了关于这个主题的事实是人类对光强度的感知是对数的,而不是线性的.该analogWrite()程序是设置输出引脚的PWM占空比,并是线性的.因此,通过采用最小占空比(比如说0)和最大占空比(比如,为了便于数学运算10)并将其分成相等的块,您将线性地控制强度,这将不会给出令人满意的结果.

您需要做的是将指数强度设置为强度.假设你的最大强度是255.您可以通过将强度视为将某些数字增加到的幂来生成此结果.在我们的例子中,鉴于我们正在处理类似二进制的计算机,两个权限是方便的.所以,

2^0 =1
2^8=256
Run Code Online (Sandbox Code Playgroud)

所以我们可以有8个强度等级.实际上,请注意,最小值现在没有完全关闭(它1不是0),我们的最大值超出范围(256不是255).所以我们修改公式

output = 2 ^ intensity - 1
Run Code Online (Sandbox Code Playgroud)

或者在代码中

int output = 1<<intensity - 1;
Run Code Online (Sandbox Code Playgroud)

这就产生了强度级别值从0到255,从08(含),所以我们实际上得到九个级别的强度.如果您想要更平滑的过渡(即更高强度级别),并且仍然使用对数强度,则需要浮点数学.

如果您将这种计算强度的方法应用于每个通道(R,G,B),那么您的感知将与您的代码所说的一致.


作为如何在各种颜色之间平滑过渡的争论,答案取决于您想要如何导航颜色空间.最简单的方法是将您的色彩空间视为三角形,将R,G和B视为椎体:

在此输入图像描述

接下来的问题是如何导航这个三角形:你可以沿着两边,从R到G,再到B.这样你永远不会看到白色(所有通道完全打开)或"黑色"(全部完全关闭).您可以将您的色彩空间视为六边形,带有额外的紫色(R + B),黄色(G + B)和棕色(R + G)颜色,并且还可以导航周边(再次,没有白色或黑色).有许多褪色的可能性,因为有这些方法可以导航这些内容,以及我们可能会想到的其他数据.

当我构建这样的淡入淡出程序时,颜色空间和我喜欢的遍历如下:将每个通道视为二进制位,所以现在你有三个(R,G和B).如果您认为每种颜色都完全打开了这些通道的某些组合,则会获得7种颜色(不包括黑色,但包括白色).取这些颜色中的第一种,从黑色渐变为黑色,然后转到下一种颜色.这里有一些类似的代码:

int targetColor = 1;
int nIntensity = 0;
int nDirection = 1;         // When direction is 1 we fade towards the color (fade IN)
                            // when 0 we fade towards black (fade OUT)
#define MAX_INTENSITY 8
#define MIN_INTENSITY 0
#define MAX_TARGETCOLOR 7

void loop() {
    for (;;) {

        // Update the intensity value
        if (nDirection) {
            // Direction is positive, fading towards the color
            if (++nIntensity >= MAX_INTENSITY) {
                // Maximum intensity reached
                nIntensity = MAX_INTENSITY;  // Just in case
                nDirection = 0;             // Now going to fade OUT
            } // else : nothing to do
        } else {
            if (--nIntensity <= MIN_INTENSITY) {
                nIntensity = MIN_INTENSITY; // Just in case
                // When we get back to black, find the next target color
                if (++targetColor>MAX_TARGETCOLOR) 
                    targetColor=1;          // We'll skip fading in and out of black
                nDirection = 1;             // Now going to fade IN
            } // else: nothing to do
        }

        // Compute the colors
        int colors[3];
        for (int i=0;i<3;i++) {
            // If the corresponding bit in targetColor is set, it's part of the target color
            colors[i] = (targetColor & (1<<i)) ? (1<<nIntensity) -1 : 0;
        }

        // Set the color
        setColor(colors[0], colors[1], colors[2]);

        // Wait
        delay(100);     
    }
}
Run Code Online (Sandbox Code Playgroud)


het*_*fan 8

确实可以在不同颜色之间淡化.我在Arduino书籍和网络代码中通常也缺少的是,可以在Arduino IDE中编写C++类.因此,我将展示一个使用C++类在颜色之间淡化的示例.

应该解决的问题是应该对哪些引脚进行模拟写操作,因为并非所有引脚都能够进行脉冲宽度调制(PWM).在Arduino器件上,支持PWM的引脚用波形符号'〜'表示.Arduino UNO具有数字引脚〜3,~5,~6,~9,~10和~11.大多数Arduino都将这些引脚用于PWM,但请检查您的设备.您可以通过将导通开启1ms并持续1 ms来在常规数字引脚上创建PWM,这样可以模拟LED上的50%功率.或者将其打开3毫秒和1毫秒,这模仿了75%的功率.

为了淡化LED,您必须降低/增加PWM值并稍等一下.你将不得不等待一段时间,因为否则arduino会尝试每秒褪色/调暗LED数千次,你不会看到褪色效果,尽管它可能存在.所以你正在寻找一种方法来逐步减少/增加analogWrite( )三个LED 的第二个参数; 有关更详尽的解释,请参阅Arduino Cookbook的第7章.无论如何,这本书对于Arduino粉丝来说都是一本很好的读物!

因此我调整了OP中的代码以包含一个'rgb_color'类,它或多或少只是红色,绿色和蓝色值的容器.但更重要的是推子类.当构造一个推子的实例时,正确的引脚应分别在构造函数中为红色,绿色和蓝色.比推子包含一个成员函数void fade( const rgb_color& const rgb_color&),它将在进出颜色之间进行淡入淡出.默认情况下,该功能将从输入颜色到输出颜色采取256步10ms.(注意这里由于整数除法,这并不意味着每一步都是1/256,但是你不会注意到它).

/*
 * LedBrightness sketch
 * controls the brightness of LEDs on "analog" (PWM) output ports.
 */

class rgb_color {

  private:
    int my_r;
    int my_g;
    int my_b;
  public:
    rgb_color (int red, int green, int blue)
      :
        my_r(red),
        my_g(green),
        my_b(blue)
    {
    }

    int r() const {return my_r;}
    int b() const {return my_b;}
    int g() const {return my_g;}
};

/*instances of fader can fade between two colors*/
class fader {

  private:
    int r_pin;
    int g_pin;
    int b_pin;

  public:
    /* construct the fader for the pins to manipulate.
     * make sure these are pins that support Pulse
     * width modulation (PWM), these are the digital pins
     * denoted with a tilde(~) common are ~3, ~5, ~6, ~9, ~10 
     * and ~11 but check this on your type of arduino. 
     */ 
    fader( int red_pin, int green_pin, int blue_pin)
      :
        r_pin(red_pin),
        g_pin(green_pin),
        b_pin(blue_pin)
    {
    }

    /*fade from rgb_in to rgb_out*/
    void fade( const rgb_color& in,
               const rgb_color& out,
               unsigned n_steps = 256,  //default take 256 steps
               unsigned time    = 10)   //wait 10 ms per step
    {
      int red_diff   = out.r() - in.r();
      int green_diff = out.g() - in.g();
      int blue_diff  = out.b() - in.b();
      for ( unsigned i = 0; i < n_steps; ++i){
        /* output is the color that is actually written to the pins
         * and output nicely fades from in to out.
         */
        rgb_color output ( in.r() + i * red_diff / n_steps,
                           in.g() + i * green_diff / n_steps,
                           in.b() + i * blue_diff/ n_steps);
        /*put the analog pins to the proper output.*/
        analogWrite( r_pin, output.r() );
        analogWrite( g_pin, output.g() );
        analogWrite( b_pin, output.b() );
        delay(time);
      }
    }

};

void setup()
{
  //pins driven by analogWrite do not need to be declared as outputs
}

void loop()
{
  fader f (3, 5, 6); //note OP uses 9 10 and 11
  /*colors*/
  rgb_color yellow( 250, 105,   0 );
  rgb_color orange( 250,  40,   0 );
  rgb_color red   ( 255,   0,   0 );
  rgb_color blue  (  10,  10, 255 );
  rgb_color pink  ( 255,   0, 100 );
  rgb_color purple( 200,   0, 255 );
  rgb_color green (   0, 255,   0 );
  rgb_color white ( 255, 255, 255 );

  /*fade colors*/
  f.fade( white, yellow);
  f.fade( yellow, orange);
  f.fade( orange, red);
  f.fade( red, blue);
  f.fade( blue, pink);
  f.fade( pink, purple);
  f.fade( purple, green);
  f.fade( green, white);
}
Run Code Online (Sandbox Code Playgroud)


Sm0*_*33n 5

这可能就是您正在寻找的。每当我们想要在光谱上移动颜色并以圆形和平滑的运动移动颜色时,我们真正要做的是在 HSI/HSV(色相、饱和度、强度/值)颜色空间中使用 HUE 来移动光。

如果你愿意,请看这个数字:

在此处输入图片说明

我们将为色调附加一个 0-360 的值,因为色调具有 360 度的颜色。饱和度值为 0.00 - 1.00,强度/值值为 0.00 -1.00

这是我在 MEGA 2560 上的电路: 在此处输入图片说明

这是这段代码运行的视频:

<iframe width="560" height="315" src="https://www.youtube.com/embed/gGG-GndSKi0" frameborder="0" allowfullscreen></iframe>
Run Code Online (Sandbox Code Playgroud)

因此,让我们构建一个函数,我们可以在循环函数中传递色调值和 for 循环来调用该值 360 次以在整个彩虹色上移动。

//Define the pins we will use with our rgb led
int redPin = 9;
int greenPin = 10;
int bluePin = 11;

//define that we are using common anode leds
#define COMMON_ANODE

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
}

int rgb[3];
//Arduino has no prebuilt function for hsi to rgb so we make one:
void hsi_to_rgb(float H, float S, float I) {
  int r, g, b;
  if (H > 360) {
    H = H - 360;
  }
  // Serial.println("H: "+String(H));
  H = fmod(H, 360); // cycle H around to 0-360 degrees
  H = 3.14159 * H / (float)180; // Convert to radians.
  S = S > 0 ? (S < 1 ? S : 1) : 0; // clamp S and I to interval [0,1]
  I = I > 0 ? (I < 1 ? I : 1) : 0;
  if (H < 2.09439) {
    r = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    g = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    b = 255 * I / 3 * (1 - S);
  } else if (H < 4.188787) {
    H = H - 2.09439;
    g = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    b = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    r = 255 * I / 3 * (1 - S);
  } else {
    H = H - 4.188787;
    b = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    r = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    g = 255 * I / 3 * (1 - S);
  }
  rgb[0] = r;
  rgb[1] = g;
  rgb[2] = b;

}
void setColor(int red, int green, int blue)
{
  #ifdef COMMON_ANODE
    red = 255 - red;
    green = 255 - green;
    blue = 255 - blue;
  #endif
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}


///here we have our main loop and the for loop to shift color
void loop()
{
//the for loop counts to 360 and because its in our control loop it will run forever
// We will use int i to increment the actual desired color 
for (int i=0; i<=360;i++){
  hsi_to_rgb(i,1,1);
  setColor(rgb[0],rgb[1],rgb[2]);
  //Changing the delay() value in milliseconds will change how fast the
  //the light moves over the hue values 
  delay(5);
  }


}
Run Code Online (Sandbox Code Playgroud)


ogn*_*i42 1

您可以通过使用颜色结构来简化代码。

struct Color
{
    unsigned char r;
    unsigned char g;
    unsigned char b;
};
Run Code Online (Sandbox Code Playgroud)

那么,很容易就有淡入淡出的功能

// the old color will be modified, hence it is not given as reference
void fade(Color old, const Color& newColor)
{
    // get the direction of increment first (count up or down)
    // each of the inc_x will be either 1 or -1
    char inc_r = (newColor.r - old.r)/abs(newColor.r-old.r); // note, that the right hand side will be sign extended to int according to the standard.
    char inc_g = (newColor.g - old.g)/abs(newColor.g-old.g);
    char inc_b = (newColor.g - old.g)/abs(newColor.g-old.g);

    fadeOneColor(old.r, newColor.r, inc_r, old);
    fadeOneColor(old.g, newColor.g, inc_g, old);
    fadeOneColor(old.b, newColor.b, inc_b, old);
}

void fadeOneColor( unsigned char& col_old, 
                   const unsigned char& col_new, 
                   const char inc, 
                   Color& col)
{
    while(col_old != col_new)
    {
        col_old += inc;
        SetColor(col); 
        delay(20);
    }        
}
Run Code Online (Sandbox Code Playgroud)

  • 这真的能回答“褪色”的问题吗? (3认同)