2013-04-04 53 views
6

Tôi hiện đang quản lý để có được LED của tôi để chu kỳ thông qua tám màu sắc mà tôi đã chọn. Mọi thứ đều hoạt động chính xác, ngoại trừ việc tôi muốn có cảm giác tự nhiên hơn, và muốn mờ dần/chuyển đổi từ màu này sang màu khác, thay vì để chúng thay thế nhau.Làm mờ LED RGB RGB từ màu này sang màu khác?

Dưới đây là mã của tôi cho đến nay:

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); 
} 
+0

Các đèn LED có được kết nối với cổng AVR bằng cathode của chúng không? Hoặc những gì giải thích '255 - x' trong' AnalogWrite() '? –

+0

Xin chào! Tôi đang sử dụng một cực dương (+) RGB LED, đó là lý do tại sao "255 -" là cần thiết. – KingPolygon

+0

@userXXX OK, tôi hiểu, cảm ơn. –

Trả lời

0

Bạn có thể đơn giản hóa mã của bạn bằng cách sử dụng một cấu trúc cho màu của bạn.

struct Color 
{ 
    unsigned char r; 
    unsigned char g; 
    unsigned char b; 
}; 

Sau đó, nó rất dễ dàng để có một chức năng mờ dần

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

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

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); 
    }   
} 
+3

Điều này thực sự trả lời "phai" câu hỏi? –

+0

@ ogni42: Ví dụ về cách sử dụng? – fuzz

12

gì câu trả lời khác bỏ qua về chủ đề này là một thực tế rằng nhận thức của con người có cường độ ánh sáng là logarithmic, not linear. Các thói quen analogWrite() đang đặt chu kỳ nhiệm vụ PWM của pin đầu ra và là tuyến tính. Vì vậy, bằng cách lấy chu kỳ nhiệm vụ tối thiểu (ví dụ: 0) và chu kỳ nhiệm vụ tối đa (ví dụ, vì lợi ích của toán học dễ dàng này là 10) và chia thành các phần bằng nhau, bạn sẽ kiểm soát intensitiy tuyến tính. .

Những gì bạn cần làm thay vào đó là đặt cường độ theo cấp số nhân. Giả sử cường độ tối đa của bạn là 255. Bạn có thể tạo kết quả này bằng cách xử lý cường độ của bạn như một sức mạnh để nâng cao một số số. Trong trường hợp của chúng tôi, cho rằng chúng tôi đang đối phó với các máy tính như nhị phân, quyền hạn của hai là thuận tiện. Vì vậy,

2^0 =1 
2^8=256 

vì vậy chúng tôi có thể có 8 mức cường độ. Trên thực tế, lưu ý rằng tối thiểu hiện không hoàn toàn tắt (đó là 1 không 0) và tối đa của chúng tôi nằm ngoài phạm vi (256 không phải 255). Vì vậy, chúng tôi thay đổi công thức để được

output = 2^intensity - 1 

Hoặc trong mã

int output = 1<<intensity - 1; 

này mang lại giá trị từ 0 đến 255 cho mức cường độ 0-8 (bao gồm), vì vậy chúng tôi thực sự nhận được chín mức độ cường độ. Nếu bạn muốn chuyển tiếp mượt mà hơn (tức là mức độ cường độ cao hơn), và vẫn sử dụng cường độ loga, bạn sẽ cần toán học dấu phẩy động.

Nếu bạn áp dụng phương pháp tính cường độ này cho mỗi kênh (R, G, B) thì nhận thức của bạn sẽ phù hợp với mã của bạn.


Vì là cách chuyển đổi thuận lợi giữa các màu khác nhau, câu trả lời tùy thuộc vào cách bạn muốn điều hướng không gian màu. Điều đơn giản nhất để làm là để suy nghĩ về không gian màu của bạn như một hình tam giác, với R, G và B, như verteces:

enter image description here

Câu hỏi đặt ra sau đó là làm thế nào để điều hướng tam giác này: bạn có thể đi dọc theo các cạnh, từ R, đến G, đến B. Bằng cách này bạn sẽ không bao giờ thấy màu trắng (tất cả các kênh đầy đủ trên) hoặc "đen" (tất cả hoàn toàn tắt).Bạn có thể nghĩ về không gian màu của bạn như một hình lục giác, với màu tím (R + B), màu vàng (G + B) và màu nâu (R + G), và cũng điều hướng chu vi (một lần nữa, không có màu trắng hoặc đen). Có nhiều khả năng phai mờ vì có nhiều cách điều hướng bên trong chúng, và những con số khác mà chúng ta có thể nghĩ đến.

Khi tôi xây dựng các chương trình giảm dần như thế này, không gian màu và giao thoa tôi thích như sau: suy nghĩ của từng kênh dưới dạng bit nhị phân, vì vậy bây giờ bạn có ba (R, G và B). Nếu bạn nghĩ rằng mỗi màu có sự kết hợp của các kênh này được hoàn toàn, bạn sẽ nhận được tổng cộng 7 màu (trừ màu đen, nhưng bao gồm màu trắng). Đi đầu tiên của những màu sắc, mờ dần nó từ màu đen và trở lại màu đen, và sau đó đi đến màu sắc tiếp theo. Dưới đây là một số mã mà không một cái gì đó như thế:

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);  
    } 
} 
+0

Điều này không thực sự cung cấp nhiều nỗ lực để trả lời câu hỏi "mờ dần giữa các màu" (IMHO) –

+0

@MartinThompson: Đã thêm một số mã để thực sự làm điều này. Tôi nghĩ đó là những gì bạn đang tìm kiếm. – angelatlarge

+0

cảm ơn, mã hữu ích. Mặc dù ... Tôi vẫn nghĩ rằng sử dụng một colourspace màu đại diện là hữu ích hơn - 'tuyến đường lục giác' của bạn có vẻ là một xấp xỉ đi quanh vòng tròn của một không gian kiểu HSV. –

4

Nếu bạn muốn phai giữa màu sắc, làm việc trong một colourspace mà làm cho nó dễ dàng và sau đó chuyển đổi trở lại RGB ở cuối.

Ví dụ, làm việc trong HSL colour space, giữ S và L liên tục (nói một màu sắc hoàn toàn bão hòa và tươi sáng) và sau đó "phai" xung quanh vòng tròn - bạn sẽ chuyển từ màu đỏ sang màu xanh lục, xanh dương và trở lại màu đỏ. Chuyển đổi trở lại RGB và sau đó sử dụng các giá trị đó cho ổ đĩa LED của bạn. Tôi đã sử dụng kỹ thuật này cho một số "mood lamp" app và có thể tìm thấy code for the colour space conversion khác trên SO.

6

Nó thực sự có thể mờ dần giữa các màu khác nhau. Những gì tôi cũng thường thiếu trong các cuốn sách và mã Arduino trên web là, có thể viết các lớp C++ trong Arduino IDE. Vì vậy, tôi sẽ hiển thị một ví dụ mờ dần giữa các màu sử dụng các lớp C++.

Một vấn đề cần được giải quyết là trên đó pins analogWrite nên được thực hiện để, bởi vì không phải tất cả các chân có khả năng điều chế độ rộng xung (PWM). Trên một thiết bị Arduino, các chân hỗ trợ PWM được biểu thị bằng dấu ngã '~'. Arduino UNO có chân số ~ 3, ~ 5, ~ 6, ~ 9, ~ 10 và ~ 11. Và hầu hết Arduino sử dụng các chân cho PWM, nhưng hãy kiểm tra thiết bị của bạn để chắc chắn. Bạn có thể tạo PWM trên các chân kỹ thuật số thông thường bằng cách bật đèn LED của bạn trên 1ms và trong 1 mili giây này bắt chước 50% công suất trên đèn LED. Hoặc bật nó trên 3 ms và 1 ms này bắt chước 75% công suất.

Để làm mờ đèn LED, bạn sẽ phải giảm/tăng giá trị PWM và chờ một chút. Youl sẽ phải chờ một chút, bởi vì nếu không arduino sẽ cố gắng mờ dần/mờ dẫn hàng ngàn lần mỗi giây và bạn sẽ không thấy một hiệu ứng mờ dần, mặc dù nó có thể ở đó. Vì vậy, bạn đang tìm kiếm một phương pháp để giảm dần/tăng tham số thứ hai thành analogWrite() cho ba đèn LED; Để được giải thích kỹ lưỡng hơn, xem ví dụ chương 7 của Arduino Cookbook. Cuốn sách đó là một cuốn sách tốt cho người hâm mộ Arduino!

Vì vậy, tôi đã điều chỉnh mã từ OP để chứa một lớp 'rgb_color' nhiều hơn hoặc ít hơn chỉ là một vùng chứa cho các giá trị màu đỏ, xanh lục và xanh dương. Nhưng quan trọng hơn là lớp fader. Khi một thể hiện của fader được xây dựng, các chốt thích hợp phải có trong hàm tạo đỏ, xanh lá cây và xanh dương tương ứng. So với fader chứa hàm thành viên void fade(const rgb_color& const rgb_color&) sẽ làm mờ dần giữa màu trong và ngoài. Theo mặc định, chức năng sẽ mất 256 bước 10ms từ màu đầu vào đến màu đầu ra. (lưu ý ở đây do số nguyên phân chia này không thực sự có nghĩa là mỗi bước 1/256 th, nhưng nhận thức bạn sẽ không nhận thấy nó).

/* 
* 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); 
} 
0

Dưới đây là một phai tuyến tính nhanh giữa hai giá trị RGB lưu trữ trong uint32_t như 0x00RRGGBB như được sử dụng trong nhiều dải RGB Pixel địa chỉ như trong NeoPixel (và được lấy cảm hứng từ một số mã trong thư viện NeoPixel Arduino).

Nó không chiếm không gian màu nhưng vẫn trông đẹp và mượt mà trong thực tế.

uint32_t fadeColor(uint32_t const x, uint32_t const y, uint8_t const fade) 
{ 
    // boundary cases don't work with bitwise stuff below 
    if (fade == 0) 
    { 
    return x; 
    } 
    else if (fade == 255) 
    { 
    return y; 
    } 

    uint16_t const invFadeMod = (255 - fade) + 1; 
    uint16_t const fadeMod = fade + 1; 
    // overflows below to give right result in significant byte 
    uint8_t const xx[3] // r g b 
    { 
    static_cast<uint8_t>((uint8_t(x >> 16) * invFadeMod) >> 8), 
    static_cast<uint8_t>((uint8_t(x >> 8) * invFadeMod) >> 8), 
    static_cast<uint8_t>((uint8_t(x >> 0) * invFadeMod) >> 8), 
    }; 
    uint8_t const yy[3] // r g b 
    { 
    static_cast<uint8_t>((uint8_t(y >> 16) * fadeMod) >> 8), 
    static_cast<uint8_t>((uint8_t(y >> 8)* fadeMod) >> 8), 
    static_cast<uint8_t>((uint8_t(y >> 0)* fadeMod) >> 8), 
    }; 
    return ((uint32_t)(xx[0] + yy[0]) << 16) | ((uint32_t)(xx[1] + yy[1]) << 8) | (xx[2] + yy[2]); 
} 
1

Đây có lẽ là những gì bạn đang tìm kiếm. Bất cứ khi nào chúng ta muốn chuyển màu qua quang phổ và chuyển màu theo chuyển động tròn và mượt mà, những gì chúng ta đang thực hiện đang chuyển ánh sáng bằng cách sử dụng HUE trong không gian màu HSI/HSV (Hue, Saturation, Intensity/Value).

Hãy nếu bạn sẽ con số này:

enter image description here

Chúng tôi sẽ đính kèm một giá trị 0-360 cho màu sắc vì màu sắc có 360 độ của màu sắc. Một giá trị của 0,00-1,00 cho độ bão hòa, và một giá trị 0.00 -1.00 cho cường độ/giá trị

Đây là mạch của tôi trên MEGA 2560: enter image description here

Dưới đây là đoạn video của mã này chạy:

<iframe width="560" height="315" src="https://www.youtube.com/embed/gGG-GndSKi0" frameborder="0" allowfullscreen></iframe>

vì vậy, cho phép xây dựng một chức năng mà chúng ta có thể vượt qua các giá trị màu sắc và một vòng lặp for bên trong chức năng vòng lặp của chúng tôi để gọi đó là giá trị 360 lần để dịch chuyển qua cầu vồng đầy màu sắc.

//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); 
    } 


} 
Các vấn đề liên quan