Светодиодная лента RGB с дистанционным управлением Arduino, проблемы с яркостью/затемнением

У меня есть этот скетч:

#include <TimerOne.h>
#include <IRremote.h>
#include <RGBMood.h>

int RECV_PIN = 2;  // PIN-код ИК-приемника
int led = 13;       // Satus-LED PIN
int modus;          // Метод прерывания-запроса
int ledr = 11;       // Красный светодиод RGB PIN
int ledg = 12;       // RGB-светодиод зеленый PIN-код
int ledb = 13;       // RGB-светодиод синий PIN-код
int SerialBuffer = 0; 

RGBMood m(ledr, ledg, ledb);

int timerwert = 20;   // Время таймера прерывания в мс

String readString;

// Массивы цветов
int black[3]  = { 0, 0, 0 };
int white[3]  = { 100, 100, 100 };
int red[3]    = { 100, 0, 0 };
int green[3]  = { 0, 100, 0 };
int blue[3]   = { 0, 0, 100 };
int yellow[3] = { 40, 95, 0 };
int dimWhite[3] = { 30, 30, 30 };

int brightness = 0;    // насколько яркий светодиод
int fadeAmount = 5;    // на сколько точек затухать светодиод
// и т. д.

// Установить начальный цвет
int redVal = black[0];
int grnVal = black[1]; 
int bluVal = black[2];

int wait = 10;      // 10 мс внутренняя задержка кроссфейда; увеличить для более медленного затухания
int hold = 0;       // Необязательная задержка, когда цвет завершен, до следующего кроссфейда
int DEBUG = 1;      // счетчик ОТЛАДКИ; если установлено значение 1, значения будут записываться обратно через последовательный порт
int loopCount = 60; // Как часто должен сообщать DEBUG?
int repeat = 3;     // Сколько раз мы должны выполнить цикл перед остановкой? (0 без остановки)
int j = 0;          // Счетчик цикла для повтора

// Инициализировать цветовые переменные
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;

#define ON                0xF4F37A66
#define OFF               0x1363ADB4
#define BRIGHTNESS_UP     0xE6721691
#define BRIGHTNESS_DOWN   0xE9721B48
#define FLASH             0xFFF00F
#define STROBE            0xFFE817
#define FADE              0x39ED1255
#define SMOOTH            0xFFC837

#define RED               0x9D561314
#define GREEN             0XCB8E93A5
#define BLUE              0xC88E8EEC
#define WHITE             0x16DBBEE3

#define ORANGE            0xFFB04F
#define YELLOW_DARK       0xFFA857
#define YELLOW_MEDIUM     0xFF9867
#define YELLOW_LIGHT      0xFF8877

#define GREEN_LIGHT       0XFF30CF
#define GREEN_BLUE1       0XFF28D7
#define GREEN_BLUE2       0XFF18E7
#define GREEN_BLUE3       0XFF08F7

#define BLUE_RED          0XFF708F
#define PURPLE_DARK       0XFF6897
#define PURPLE_LIGHT      0XFF58A7
#define PINK              0XFF48B7


IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(ledr, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(ledg, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(ledb, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(led, OUTPUT); // установить светодиод состояния как выход
  m.setMode(RGBMood::RANDOM_HUE_MODE);  // Автоматическое случайное затухание.
  m.setHoldingTime(4000);  // Сохраняйте тот же цвет в течение 4 секунд, прежде чем снова исчезнуть.
  m.setFadingSteps(150);   // Затухание со 150 шагами.
  m.setFadingSpeed(50);    // Каждый шаг длится 50 мс. Полное исчезновение занимает 50 * 150 = 7,5 секунд.
  m.setHSB(random(359), 255, 255);

Serial.begin(9600);

  irrecv.enableIRIn(); // Начало ИК-приема

  Timer1.initialize(timerwert); // Инициализация прерываний по таймеру
  Timer1.attachInterrupt(leseIR); // ИК-чтение из прерывания
}

void leseIR(){
  if (irrecv.decode(&results)){
     irrecv.resume();  // Получаем следующее значение
    switch (results.value)  {

      case FADE: // Modus Fade (DIY 4)
        modus = 1;  
      break;

      case 0xFF906F: // Modus pcambi (DIY 5)
        modus = 2;  
      break;

      case ON:  //Питание
       modus = 0;
        crossFade(white);         // Светодиоды RGB выключены
      break;
            case OFF:  //Питание
       modus = 0;
        crossFade(black);         // Светодиоды RGB выключены
      break;

      case BLUE:  //Синий 0,0,255
        modus = 0;
      crossFade(blue);
      break;

      case RED: // Гниль
        modus = 0;
        crossFade(red);
      break;

      case GREEN://Grün
        modus = 0;
        crossFade(green);
      break;  

      case WHITE: //Weiss
        modus = 0;
        crossFade(white);
      break;

      case BRIGHTNESS_UP: // ЗАТЕМНЕНИЕ
        modus = 0;
        // переход от минимального к максимальному с шагом 5 пунктов:
  for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    // устанавливаем значение (диапазон от 0 до 255):
    analogWrite(ledg, fadeValue);    

  }

      break;

       case BRIGHTNESS_DOWN: //оранжевый
        modus = 0;
      for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
    // устанавливаем значение (диапазон от 0 до 255):
    analogWrite(ledg, fadeValue);    
      }

      break;

      case 0xFFAA55://Grün mitrtel
        modus = 0;

      break;  

      case 0xFF926D: // синий миттель
        modus = 0;

      break; 

      case 0xFF12ED: //роза
        modus = 0;

      break;      


     }             // Переключение КОНЕЦ

  }               

}                  

void loop() {
if(modus==1){    // Запрос pb Modus:1
m.tick();
}

      Serial.println(results.value, HEX);
      Serial.println(DEC);
      Serial.println(DEC);
      Serial.println(DEC);

  } 


  int calculateStep(int prevValue, int endValue) {
  int step = endValue - prevValue; // Каков общий разрыв?
  if (step) {                      // Если не ноль,
    step = 1020/step;              // делим на 1020
  } 
  return step;
}

/* The next function is calculateVal. When the loop value, i,
*  reaches the step size appropriate for one of the
*  colors, it increases or decreases the value of that color by 1. 
*  (R, G, and B are each calculated separately.)
*/

int calculateVal(int step, int val, int i) {

  if ((step) && i % step == 0) { // Если шаг не равен нулю и пришло время изменить значение,
    if (step > 0) {              // увеличиваем значение, если шаг положительный...
      val += 1;           
    } 
    else if (step < 0) {         // ...или уменьшить его, если шаг отрицательный
      val -= 1;
    } 
  }
  // Защитное вождение: убедитесь, что значение val находится в диапазоне 0-255.
  if (val > 255) {
    val = 255;
  } 
  else if (val < 0) {
    val = 0;
  }
  return val;
}

/* crossFade() converts the percentage colors to a 
*  0-255 range, then loops 1020 times, checking to see if  
*  the value needs to be updated each time, then writing
*  the color values to the correct pins.
*/

void crossFade(int color[3]) {
  // Преобразование в 0-255
  int R = (color[0] * 255) / 100;
  int G = (color[1] * 255) / 100;
  int B = (color[2] * 255) / 100;

  int stepR = calculateStep(prevR, R);
  int stepG = calculateStep(prevG, G); 
  int stepB = calculateStep(prevB, B);

  for (int i = 0; i <= 1020; i++) {
    redVal = calculateVal(stepR, redVal, i);
    grnVal = calculateVal(stepG, grnVal, i);
    bluVal = calculateVal(stepB, bluVal, i);

    analogWrite(ledr, redVal);   // Записываем текущие значения на выводы светодиода
    analogWrite(ledg, grnVal);      
    analogWrite(ledb, bluVal); 

    delay(wait); // Пауза в миллисекундах ожидания перед возобновлением цикла


  }
  // Обновить текущие значения для следующего цикла
  prevR = redVal; 
  prevG = grnVal; 
  prevB = bluVal;
  delay(hold); // Пауза для необязательных миллисекунд ожидания перед возобновлением цикла
}

Он работает как шарм, затухание работает плавно с использованием timer1, цвета на светодиодах отображаются правильно, но я не могу исправить часть яркости. Может ли кто-нибудь предоставить пример кода для этого?

Если кто-то еще хочет использовать код, я использую Arduino Mega 2560, пожалуйста, используйте те же PIN-коды, что и у меня, поскольку таймеры работают только на 11,12,13 на этом Arduino. (ссылка с информацией о выводах для нескольких плат Arduino)

  • библиотека настроений RGB
  • библиотека TimerOne
  • ИК-библиотека

Я использую маленькое ИК-управление Xbox 360 (без цифровой клавиатуры), некоторые шестнадцатеричные коды остались нетронутыми из оригинального скетча, найденного в Интернете.

исходная тема

, 👍5

Обсуждение

Что не так с яркостью?, @geometrikal

не могу настроить яркость светодиодов. Возможно, мне следует использовать выражение «тусклый» вместо «яркость», чтобы было более понятно. Если я установлю цвет КРАСНЫЙ, я не смогу увеличить или уменьшить его яркость, то же самое относится и к ЗЕЛЕНОМУ и СИНЕМУ., @Stathis Ntonas

Никакая «яркость» не была ясна, я просто не мог понять, что не работает из вашего вопроса. :П, @geometrikal


2 ответа


Лучший ответ:

2

У вас нет задержки в цикле затухания, он изменяется от 0 до 255 почти мгновенно:

for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
    // устанавливаем значение (диапазон от 0 до 255):
    analogWrite(ledg, fadeValue);    
}

Но я не уверен, что вы хотите переходить от выключенного к включенному за один раз. Если вы хотите просто увеличивать и уменьшать яркость:

Сначала обратите внимание, что prevR, prevG, prevB содержат текущие значения светодиодов. Поэтому мы будем использовать их.

Измените регистр переключателя на:

case BRIGHTNESS_UP:
    modus = 0;
    int c[3];
    // уменьшаем на 0,9*значение, но также уменьшаем на 2, так что получаем ноль
    c[0] = (prevR-2) * 90 / 100;
    c[1] = (prevG-2) * 90 / 100;
    c[2] = (prevB-2) * 90 / 100;
    for( int j = 0; j < 3; j++ ) {
        if (c[j] < 0) c[j] = 0;
    }
    crossFade(c);
    break;

case BRIGHTNESS_DOWN:
    modus = 0;
    int c[3];
    // увеличим значение на 1/0,9, но также добавим 2, чтобы получить ноль
    c[0] = (prevR+2) * 100 / 90 + 2;
    c[1] = (prevG+2) * 100 / 90 + 2;
    c[2] = (prevB+2) * 100 / 90 + 2;
    for( int j = 0; j < 3; j++ ) {
        if (c[j] > 100) c[j] = 100;
    }
    crossFade(c);
    break;

Я не могу проверить, работает ли это, пожалуйста, проверьте и посмотрите.

Другой подход:

Глобальная переменная яркости:

int brightness = 100;
int c[3];

Изменяйте это значение каждый раз:

case BRIGHTNESS_UP:
    modus = 0;
    brightness += 5;
    if (brightness > 255) brightness = 255;
    c[0] = prevR; c[1] = prevG; c[2] = prevB;
    crossFade(c);
    break;

case BRIGHTNESS_DOWN:
    modus = 0;
    brightness -= 5;
    if (brightness < 0) brightness = 0;
    c[0] = prevR; c[1] = prevG; c[2] = prevB;
    crossFade(c);
    break;

Затем в crossFade мы меняем последние несколько строк:

analogWrite(ledr, redVal * brightness / 255);   // Записываем текущие значения на выводы светодиода
analogWrite(ledg, grnVal * brightness / 255);      
analogWrite(ledb, bluVal * brightness / 255); 

Обновление 2:

Я думаю, что может произойти то, что цвет уменьшается на яркость, а затем это уменьшенное значение сохраняется в prevR/G/B, хотя на самом деле это должно быть просто полное значение яркости. Попробуйте изменить последний бит crossFade на :

prevR = color[0]; 
prevG = color[1]; 
prevB = color[2];
,

IDE сообщает, что происходит переобъявление 'int c [3], @Stathis Ntonas

Попробуйте переместить int c[3] за пределы leseIR() и сделать его глобальным. Удалите все экземпляры в операторе переключения., @geometrikal

возможно, вам захочется повозиться и с соотношениями, скажем, использовать 80 вместо 90, 5 вместо 2 и т. д. Я пытался использовать соотношение, потому что наши глаза воспринимают яркость в логарифмическом масштабе, поэтому небольшое изменение низкой яркости похоже на большое изменение высокой яркости., @geometrikal

Я удалил его, код скомпилировал, но когда я нажимаю кнопку увеличения яркости, цвет становится черным (выключается), а когда я нажимаю кнопку уменьшения яркости, после нескольких нажатий кнопки цвет становится белым., @Stathis Ntonas

упс, я неправильно перепутал BRIGHTNESS_UP и BRIGHTNESS_DOWN, @geometrikal

см. этот вопрос, чтобы узнать о подходе некоторых людей к правильному изменению яркости http://electronics.stackexchange.com/questions/1983/correcting-for-non-linear-brightness-in-leds-when-using-pwm, @geometrikal

Яркость, возможно, придется сделать отдельной переменной и применить в CrossFade., @geometrikal

Привет, я попробовал отредактированный подход: все цвета тускнеют до 0 одним нажатием кнопки, независимо от того, увеличиваете или уменьшаете яркость. Итак, если я выбрал ЗЕЛЕНЫЙ цвет, он затемняется до 0, то же самое относится ко всем. Класс Crossfade выполняет следующие действия: когда выбран цвет «КРАСНЫЙ» и нажмите кнопку «ЗЕЛЕНАЯ», цвет «КРАСНЫЙ» тускнеет до «0», а «ЗЕЛЕНЫЙ» — до «100». Я предполагаю, что нам не следует использовать класс Crossfade для управления яркостью., @Stathis Ntonas

Эй, не могли бы вы заставить crossFade распечатать значения color и RGB и просто проверить, все ли в порядке? например Serial.println(color[0],DEC); и так далее., @geometrikal

Нажатие кнопки RED приводит к crossfade **:** 100,0,0 и color **:** 255,0,0 . ЗЕЛЕНЫЙ crossfade **:** 0,100,0 и color **:** 0,255,0 **.** СИНИЙ crossfade **:** 0,0,100 и color **:** 0,0,255 **.** БЕЛЫЙ crossfade **:** 100,100,100 и цвет 255,255,255 **.** Итак, вроде бы все в порядке., @Stathis Ntonas

Ой, извините, я имел в виду увеличение/уменьшение яркости с помощью кода, который я опубликовал. :), @geometrikal


1

Я переместил часть кода analogWrite внутрь переключателя BRIGHTNESS_UP & BRIGHTNESS_DOWN, и это работает. Я также удалил строку crossFade(c);.

Вот рабочий код:

#include <TimerOne.h>
#include <IRremote.h>
#include <RGBMood.h>

int RECV_PIN = 2;  // PIN-код ИК-приемника
int led = 13;       // Satus-LED PIN
int modus;          // Метод прерывания-запроса
int ledr = 11;       // Красный светодиод RGB PIN
int ledg = 12;       // RGB-светодиод зеленый PIN-код
int ledb = 13;       // RGB-светодиод синий PIN-код
int SerialBuffer = 0; 
int c[3];


// Массив контактов RGB
int CH[3] = {11, 12, 13};
int val[3] = {0, 0, 0}; // яркость светодиода 0-255


RGBMood m(ledr, ledg, ledb);

int timerwert = 20;   // Время таймера прерывания в мс

String readString;

// Массивы цветов
int black[3]  = { 0, 0, 0 };
int white[3]  = { 100, 100, 100 };
int red[3]    = { 100, 0, 0 };
int green[3]  = { 0, 100, 0 };
int blue[3]   = { 0, 0, 100 };
int yellow[3] = { 40, 95, 0 };
int dimWhite[3] = { 30, 30, 30 };

int brightness = 100;    // насколько яркий светодиод
int fadeAmount = 5;    // на сколько точек затухать светодиод
// и т. д.

// Установить начальный цвет
int redVal = black[0];
int grnVal = black[1]; 
int bluVal = black[2];

int wait = 10;      // 10 мс внутренняя задержка кроссфейда; увеличить для более медленного затухания
int hold = 0;       // Необязательная задержка, когда цвет завершен, до следующего кроссфейда
int DEBUG = 1;      // счетчик ОТЛАДКИ; если установлено значение 1, значения будут записываться обратно через последовательный порт
int loopCount = 60; // Как часто должен сообщать DEBUG?
int repeat = 3;     // Сколько раз мы должны выполнить цикл перед остановкой? (0 без остановки)
int j = 0;          // Счетчик цикла для повтора


// Инициализировать цветовые переменные
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;

#define ON                0xF4F37A66
#define OFF               0x1363ADB4
#define BRIGHTNESS_UP     0xE6721691
#define BRIGHTNESS_DOWN   0xE9721B48
#define FLASH             0xFFF00F
#define STROBE            0xFFE817
#define FADE              0x39ED1255
#define SMOOTH            0xFFC837

#define RED               0x9D561314
#define GREEN             0XCB8E93A5
#define BLUE              0xC88E8EEC
#define WHITE             0x16DBBEE3

#define ORANGE            0xFFB04F
#define YELLOW_DARK       0xFFA857
#define YELLOW_MEDIUM     0xFF9867
#define YELLOW_LIGHT      0xFF8877

#define GREEN_LIGHT       0XFF30CF
#define GREEN_BLUE1       0XFF28D7
#define GREEN_BLUE2       0XFF18E7
#define GREEN_BLUE3       0XFF08F7

#define BLUE_RED          0XFF708F
#define PURPLE_DARK       0XFF6897
#define PURPLE_LIGHT      0XFF58A7
#define PINK              0XFF48B7
#define MAX 255 

IRrecv irrecv(RECV_PIN);
decode_results results;

void setup()
{
  pinMode(ledr, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(ledg, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(ledb, OUTPUT); // Установить выводы RGB-светодиода в качестве вывода
  pinMode(led, OUTPUT); // установить светодиод состояния как выход
 // инициируем вывод rgb pins
    for (int i=0; i<3; i++)
  {
    pinMode(CH[i], OUTPUT);
  }

  m.setMode(RGBMood::RANDOM_HUE_MODE);  // Автоматическое случайное затухание.
  m.setHoldingTime(4000);  // Сохраняйте тот же цвет в течение 4 секунд, прежде чем снова исчезнуть.
  m.setFadingSteps(150);   // Затухание со 150 шагами.
  m.setFadingSpeed(50);    // Каждый шаг длится 50 мс. Полное исчезновение занимает 50 * 150 = 7,5 секунд.
  m.setHSB(random(359), 255, 255);

Serial.begin(9600);

  irrecv.enableIRIn(); // Начало ИК-приема

  Timer1.initialize(timerwert); // Инициализация прерываний по таймеру
  Timer1.attachInterrupt(leseIR); // ИК-чтение из прерывания
}

void leseIR(){
  if (irrecv.decode(&results)){
     irrecv.resume();  // Получаем следующее значение
    switch (results.value)  {

      case FADE: // Modus Fade (DIY 4)
        modus = 1;  
      break;

      case 0xFF906F: // Modus pcambi (DIY 5)
        modus = 2;  
      break;

      case ON:  //Питание
       modus = 0;
        crossFade(white);         // Светодиоды RGB выключены
      break;
            case OFF:  //Питание
       modus = 0;
        crossFade(black);         // Светодиоды RGB выключены
      break;

      case BLUE:  //Синий 0,0,255
        modus = 0;
      crossFade(blue);
      break;

      case RED: // Гниль
        modus = 0;
        crossFade(red);
      break;

      case GREEN://Grün
        modus = 0;
        crossFade(green);
      break;  

      case WHITE: //Weiss
        modus = 0;
        crossFade(white);
      break;

      case BRIGHTNESS_UP: // ЗАМЕЧАНИЕ
        modus = 0;
    brightness += 5;
    if (brightness > 255) brightness = 255;
    c[0] = prevR; c[1] = prevG; c[2] = prevB;
    analogWrite(ledr, redVal * brightness / 255);   // Записываем текущие значения на выводы светодиода
    analogWrite(ledg, grnVal * brightness / 255);      
    analogWrite(ledb, bluVal * brightness / 255);

      break;

       case BRIGHTNESS_DOWN: // затемнение вниз
         modus = 0;
    brightness -= 5;
    if (brightness < 0) brightness = 0;
    c[0] = prevR; c[1] = prevG; c[2] = prevB;
    analogWrite(ledr, redVal * brightness / 255);   // Записываем текущие значения на выводы светодиода
    analogWrite(ledg, grnVal * brightness / 255);      
    analogWrite(ledb, bluVal * brightness / 255);


      break;

      case 0xFFAA55://Grün mitrtel
        modus = 0;
      break;  

      case 0xFF926D: // синий миттель
        modus = 0;

      break; 

      case 0xFF12ED: //роза
        modus = 0;

      break;      


     }             // Переключение КОНЕЦ

  }               
}                  

void loop() {
if(modus==1){    // Запрос pb Modus:1
m.tick();
}
if(modus==2){    // Запрос pb Modus:1

}
        Serial.println(prevR);
        Serial.println(prevG);
        Serial.println(prevB);
// Serial.println(results.value, HEX);
// Serial.println(DEC);
// Serial.println(DEC);
// Serial.println(DEC);
// Serial.print("Значения каналов 1,2,3:"); // отправляет значения яркости на последовательный монитор
    // for(int i=0; i<3; i++){ // при каждом нажатии пульта
    // Serial.print(CH[i]);
// Serial.print(" ");
    // }
  } 


  int calculateStep(int prevValue, int endValue) {
  int step = endValue - prevValue; // Каков общий разрыв?
  if (step) {                      // Если не ноль,
    step = 1020/step;              // делим на 1020
  } 
  return step;
}

/* The next function is calculateVal. When the loop value, i,
*  reaches the step size appropriate for one of the
*  colors, it increases or decreases the value of that color by 1. 
*  (R, G, and B are each calculated separately.)
*/

int calculateVal(int step, int val, int i) {

  if ((step) && i % step == 0) { // Если шаг не равен нулю и пришло время изменить значение,
    if (step > 0) {              // увеличиваем значение, если шаг положительный...
      val += 1;           
    } 
    else if (step < 0) {         // ...или уменьшить его, если шаг отрицательный
      val -= 1;
    } 
  }
  // Защитное вождение: убедитесь, что значение val находится в диапазоне 0-255.
  if (val > 255) {
    val = 255;
  } 
  else if (val < 0) {
    val = 0;
  }
  return val;
}

/* crossFade() converts the percentage colors to a 
*  0-255 range, then loops 1020 times, checking to see if  
*  the value needs to be updated each time, then writing
*  the color values to the correct pins.
*/

void crossFade(int color[3]) {
  // Преобразование в 0-255
  int R = (color[0] * 255) / 100;
  int G = (color[1] * 255) / 100;
  int B = (color[2] * 255) / 100;

  int stepR = calculateStep(prevR, R);
  int stepG = calculateStep(prevG, G); 
  int stepB = calculateStep(prevB, B);

  for (int i = 0; i <= 1020; i++) {
    redVal = calculateVal(stepR, redVal, i);
    grnVal = calculateVal(stepG, grnVal, i);
    bluVal = calculateVal(stepB, bluVal, i);

    analogWrite(ledr, redVal);   // Записываем текущие значения на выводы светодиода
    analogWrite(ledg, grnVal);      
    analogWrite(ledb, bluVal); 

    delay(wait); // Пауза в миллисекундах ожидания перед возобновлением цикла


  }
  // Обновить текущие значения для следующего цикла
  prevR = redVal; 
  prevG = grnVal; 
  prevB = bluVal;
  delay(hold); // Пауза для необязательных миллисекунд ожидания перед возобновлением цикла
}

Спасибо, geometrikal, за вашу поддержку! Вы верите, что можно также манипулировать затемнением эффекта затухания? Он использует класс RGBMood для создания сочетания цветов HSB.

,