Исчезает ли Arduino RGB 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);
}

7

Решение

Что другие ответы опускают по этой теме, так это то, что человеческое восприятие интенсивности света логарифмический, не линейный. analogWrite() подпрограммы устанавливают выходные выводы PWM рабочий цикл, и являются линейными. Таким образом, принимая минимальный рабочий цикл (скажем, 0) и максимальный рабочий цикл (скажем, ради простоты математики это 10) и разделив его на равные куски, вы будете контролировать интенсивность линейно что не даст удовлетворительных результатов.

Вместо этого вам нужно установить вашу интенсивность в геометрической прогрессии. Допустим, ваша максимальная интенсивность 255, Вы можете получить этот результат, рассматривая свою интенсивность как способность поднять некоторое число до. В нашем случае, учитывая, что мы имеем дело с компьютерами, которые, как двоичные, удобны степени двойки. Так,

2^0 =1
2^8=256

так что мы можем иметь 8 уровней интенсивности. На самом деле, обратите внимание, что минимум теперь не полностью отключен (это 1 не 0) и наш максимум вне диапазона (256 не 255). Таким образом, мы модифицируем формулу, чтобы

output = 2 ^ intensity - 1

Или в коде

int output = 1<<intensity - 1;

Это дает значения от 0 до 255 для уровней интенсивности от 0 в 8 (включительно), поэтому мы на самом деле получаем девять уровней интенсивности. Если вы хотели более плавные переходы (то есть больше уровней интенсивности) и все еще использовали логарифмическую интенсивность, вам понадобится математика с плавающей точкой.

Если вы примените этот метод расчета интенсивности к каждому каналу (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);
}
}
13

Другие решения

Действительно возможно исчезать между различными цветами. То, что я обычно пропускаю в книгах и коде Arduino в сети, так это то, что можно писать классы C ++ в Arduino IDE. Поэтому я собираюсь показать пример, который исчезает между цветами, используя классы C ++.

Проблема, которая должна быть решена, заключается в том, какие выводы должны быть выполнены аналоговым письмом, потому что не все контакты способны к широтно-импульсной модуляции (PWM). На устройстве Arduino контакты, поддерживающие ШИМ, обозначены тильдой ‘~’. Arduino UNO имеет цифровые контакты ~ 3, ~ 5, ~ 6, ~ 9, ~ 10 и ~ 11. И большинство Arduino используют эти контакты для ШИМ, но проверьте ваше устройство, чтобы быть уверенным. Вы можете создать ШИМ на обычных цифровых выводах, включив светодиод на 1 мс и на 1 мс, это имитирует 50% мощности светодиода. Или включите его на 3 мс, и на 1 мс это имитирует 75% мощности.

Чтобы погас светодиод, вам нужно уменьшить / увеличить значение ШИМ и немного подождать. Вам придется немного подождать, потому что в противном случае arduino будет пытаться угасать / затухать светодиодами тысячи раз в секунду, и вы не увидите эффекта затухания, хотя, вероятно, он есть. Итак, вы ищете способ постепенно уменьшить / увеличить второй параметр до analogWrite( ) для трех светодиодов; Для более подробного объяснения см., Например, главу 7 Arduino Cookbook. В любом случае, эта книга хорошо читается фанатами Arduino!

Поэтому я адаптировал код из OP, чтобы он содержал класс ‘rgb_color’, который более или менее просто является контейнером для значений красного, зеленого и синего. Но что более важно, это класс фейдеров. Когда создается экземпляр фейдера, правильные выводы должны быть в конструкторе красного, зеленого и синего соответственно. Чем фейдер содержит функцию-член void fade( const rgb_color& const rgb_color&) который будет делать затухание между входным и выходным цветом. По умолчанию функция принимает 256 шагов по 10 мс от цвета ввода до цвета вывода. (обратите внимание, здесь из-за целочисленных делений это не означает, что каждый шаг 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);
}
7

Если вы хотите плавно переходить между цветами, работайте в цветовом пространстве, что облегчает его, а затем в конце преобразуйте обратно в RGB.

Например, работа в HSL цветовое пространство, сохраняйте постоянными S и L (скажем, полностью насыщенный и яркий цвет), а затем «плавно» H по кругу — вы перейдете от красного к зеленому, синему и обратно к красному. Преобразуйте обратно в RGB и затем используйте эти значения для ваших светодиодных накопителей. Я использовал эту технику для Приложение «Лампа настроения», и другие код для преобразования цветового пространства можно найти на SO.

4

Это, наверное, то, что вы ищете. Всякий раз, когда мы хотим сместить цвет по спектру и перемещать цвета круговым и плавным движением, мы действительно смещаем свет с использованием HUE в цветовом пространстве HSI / HSV (Hue, Saturation, Intensity / Value).

Возьмите, если хотите, эту цифру:

введите описание изображения здесь

Мы добавим значение от 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>
3

Вы можете упростить свой код, используя структуру для вашего цвета.

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

Тогда легко иметь функцию затухания

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

Вот быстрое линейное затухание между двумя значениями RGB, хранящимися в uint32_t как 0x00RRGGBB as используется во многих адресуемых пиксельных полосах RGB, таких как NeoPixel (и вдохновлен некоторым кодом из библиотеки NeoPixel Arduino).

Он не учитывает цветовое пространство, но на практике выглядит красиво и гладко.

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]);
}
0
По вопросам рекламы [email protected]