Постепенно включать RGB led

Почему я не могу использовать "timeA = delay", чтобы свет включался постепенно. Проблема в том, что задержка не работает, и светодиодный индикатор переходит непосредственно к последнему цвету. Что мне нужно сделать в своем коде, чтобы исправить это?

Вот мой код ↓

// C++ code
//

void setup()
{
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
}

void loop(){
  
  static unsigned long timeA = 10;
  const long interval = 10;
  
  static unsigned long timeB = 10;
  const long interval2 = 10;
  
  static unsigned long timeC = 10;
  const long interval3 = 10;
    
  unsigned long delay = millis();
  static unsigned long state = 0;
  int i = 0;
    
  
  if(delay - timeA >= interval && state == 0){
    state += 1;
    for(i=0;i<=255;i++){
        analogWrite(3, i);
        analogWrite(5, 0);
        analogWrite(6, 0);
        timeA = delay;
    }
  }
   if(delay - timeB >= interval2 && state == 1){
    state += 1;
    for(i=0;i<=255;i++){
        analogWrite(3, 0);
        analogWrite(5, i);
        analogWrite(6, 0);
        timeB = delay;
    }
  }
  if(delay - timeC >= interval3 && state == 2){
   state += 1;
   for(i=0;i<=255;i++){
        analogWrite(3, 0);
        analogWrite(5, 0);
        analogWrite(6, i);
        timeC = delay;
    }
  }
   
}

, 👍1


2 ответа


0

Я думаю, что ниже приведено то, к чему вы стремились. Я удалил цикл for и использовал статическую переменную i, чтобы каждое состояние занимало 256 интервалов. Обратите внимание, что вам не нужно иметь отдельные переменные timeA/B/C. Использование одного из них также гарантирует, что первая "задержка" действительно произойдет. Это не так уж критично для выцветания светодиода, но в других случаях это возможно.

void setup()
{
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
}

void loop(){
  
  static unsigned long timeA = 10;
  const long interval = 10;
  
  static unsigned long timeB = 10;
  const long interval2 = 10;
  
  static unsigned long timeC = 10;
  const long interval3 = 10;
    
  static unsigned long state = 0;
  static int i = 0;

  unsigned long delay = millis();
    
  
  if(delay - timeA >= interval && state == 0){
    analogWrite(3, i);
    analogWrite(5, 0);
    analogWrite(6, 0);
    timeA = delay;
    
    i++;
    if( i==256 )
    {
      i=0;
      state++;
    }
  }
   if(delay - timeB >= interval2 && state == 1){
    analogWrite(3, 0);
    analogWrite(5, i);
    analogWrite(6, 0);
    timeB = delay;

    i++;
    if( i==256 )
    {
      i=0;
      state++;
    }
  }
  if(delay - timeC >= interval3 && state == 2){
    analogWrite(3, 0);
    analogWrite(5, 0);
    analogWrite(6, i);
    timeC = delay;

    i++;
    if( i==256 )
    {
      i=0;
      state++; // вы, вероятно, хотите использовать `state=0;`, поэтому все начинается сначала
    }
  }
   
}```
,

Спасибо! Но у меня все еще есть сомнения, могу ли я использовать "для", потому что это работа в колледже, и мне нужно ее использовать., @Ian Rapini


1

Ваш код millis() структурирован неправильно. Давайте посмотрим, что происходит:

timeA и co инициируются со значением 10. Таким образом, как только программа пробежит 10 мс, будет выполнен первый оператор if (тот, что для состояния 0). Сначала вы увеличиваете состояние, чтобы можно было достичь следующего состояния. Тогда у вас есть цикл for без какого-либо временного кода. Он будет выполняться очень быстро, не давая аппаратному обеспечению PWM возможности фактически выводить значения analogWrite (). Затем вы обновляете timeA (который обычно не входит в цикл for). Мы оставляем оператор if и переходим к следующему. Почти не прошло времени с тех пор, как мы ввели первый оператор if. И теперь мы выполняем следующий оператор if, так как состояние теперь равно 1, а программа работала более 10 мс. Здесь то же самое, что и выше.

Таким образом, программа мчится через вызовы analogWrite (), заканчивающиеся последним, так как состояние никогда не сбрасывается, давая последнему значению analogWrite() изменение, которое будет выведено на вывод.

Вся структура кода на самом деле не имеет смысла. Я предполагаю, что вы хотели сделать это неблокирующим, таким образом, используя millis(). Циклы For на самом деле не соответствуют этому, и значение millis() должно быть сравнено с правильными значениями, чтобы получить правильный порядок.

Что теперь делать: с переменной состояния у вас почти есть то, что называется конечным автоматом (FSM). Это мощная концепция программирования. В основном состояние программы решает, какой блок кода должен выполняться на каждой итерации цикла (). Лучше всего это сделать с помощью оператора switch. Затем в каждом случае мы используем оператор if, использующий значение millis (), чтобы решить, пришло ли время выполнить новую analogWrite():

void setup()
{
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
}

void loop(){
  
  static unsigned long timeA = 10;
  const long interval = 10;
  
  static unsigned long timeB = 10;
  const long interval2 = 10;
  
  static unsigned long timeC = 10;
  const long interval3 = 10;
    
  unsigned long delay = millis();
  static unsigned long state = 0;
  static int i = 0;

  switch(state){
    case 0:
      if(delay - timeA >= interval){
        analogWrite(3, i);
        analogWrite(5, 0);
        analogWrite(6, 0);
        i++;
        timeA = delay;
      }
      if(i > 255){
        state = 1;
        i = 0;
      }
      break;
    case 1:
      if(delay - timeB >= interval2){
        analogWrite(3, 0);
        analogWrite(5, i);
        analogWrite(6, 0);
        i++;
        timeB = delay;
      }
      if(i > 255){
        state = 2;
        i = 0;
      }
      break;
    case 2:
      if(delay - timeC >= interval3){
        analogWrite(3, 0);
        analogWrite(5, 0);
        analogWrite(6, i);
        i++;
        timeC = delay;
      }
      if(i > 255){
        state = 0;
        i = 0;
      }
      break;
  }
}

Установив переменную state, мы можем выбрать, что должно быть выполнено дальше. Переменная i обрабатывает затухание каждого светодиода, в то время как интервальные переменные устанавливают скорость затухания. Этот принцип кодирования может быть использован в самых разных ситуациях, так что изучение его действительно стоит того.

Примечание:

  • Я не тестировал приведенный выше код.
  • Код все еще может быть оптимизирован/обобщен.
,

Спасибо тебе, братан! Но еще одно сомнение: не могу ли я использовать "для" в этом случае? Потому что это работа в колледже, которую мне нужно использовать., @Ian Rapini

Если вы используете цикл for, вам также нужно будет использовать " delay ()", чтобы создать правильное время затухания. Я предположил, что вы не хотите использовать delay() (что хорошо для добавления дополнительных функций в будущем). циклы for - это всего лишь один из способов создания циклов. Есть и другие, и вышеприведенный принцип кода также должен работать. Это зависит от вас, хотите ли вы использовать " for "(и, следовательно, " delay ()", создавая блокирующий код) или вышеприведенную структуру кода (и, следовательно, неблокирующий код)., @chrisl