Функция светодиодного фейдера зависает и перестает реагировать после нескольких циклов

rgb-led led-strip

У моего светодиодного контроллера есть режим изменения цвета, который я создаю. Функция контроллера loop() захватывает входящие последовательные данные, чтобы установить количество цветов, скорость затухания, режим и другую информацию, а затем запускает правильный режим с цветами, которые она считывает из последовательного порта

В режиме изменения цвета контроллер «зависает» на определенном цвете и перестает реагировать на ввод данных до тех пор, пока я не отключу его и снова не включу или не загружу код повторно (последнее означает, что он по-прежнему на что-то реагирует).

В целях тестирования я использую красный, зеленый и синий цвета в указанном порядке. Этот остановившийся цвет может произойти где угодно: от середины перехода от красного к зеленому в первом цикле до прохождения нескольких циклов и остановки на синем в зависимости от скорости затухания. Это стало проблемой только после того, как я переключился с использования delay() на millis(). Почему это так и что я могу сделать, чтобы это исправить?

Причина, по которой я перешел на использование миллиса, заключается в том, что задержки будут складываться бесконечно, и Arduino перестанет реагировать на команды

Вот мой соответствующий код:

#include <Adafruit_DotStar.h>
#include <SPI.h>

#define NUMPIXELS 60
#define DATAPIN    4
#define CLOCKPIN   5

Adafruit_DotStar strip(NUMPIXELS, DOTSTAR_BRG);

// Переменные
int mode;
int numColors;
int fadeSpeed;
int BBCC;
int R[100];
int G[100];
int B[100];
int Bright[100];

int currColor;

void setup() {

#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  clock_prescale_set(clock_div_1); // Включить 16 МГц на Trinket
#endif
  strip.begin(); // Инициализируем выводы для вывода
  strip.show();  // Выключить все светодиоды как можно скорее

  currColor = 0;
}

void loop() {
  strip.show();                     // Обновить полосу
  delay(20);                        // Пауза 20 миллисекунд (~50 FPS)

  getData();


  switch (mode)
  {
    case 1:                  // Режим 1: Сплошной цвет
    {
      for (int i = 0; i < NUMPIXELS; i++)
      {
        if (i % 2 == 0)
          strip.setPixelColor(i, G[0], R[0], B[0]);// Устанавливает для всей полосы цвет 1
      }
      strip.setBrightness(Bright[0]);
      strip.show();
      break;
    }
    case 2:                  // Режим 2: Многоцветный фейдер
    {
      colorFade();
      break;
    }
    case 3:                  // Режим 3: Многоцветный шаблон
    {
      int j = 0;
      for (int i = 0; i < NUMPIXELS; i++)
      {
        if (i % 2 == 0)
        {
          strip.setPixelColor(i, G[j], R[j], B[j]); // устанавливает повторяющийся шаблон
          if (j == (numColors - 1))
            j = 0;
          else
            j++;
        }
      }
      strip.setBrightness(Bright[0]);
      strip.show();
      break;
    }
    case 4:                  // Mode 4: Music-Reactive Wave Form
    {

      break;
    }
    case 5:                  // Mode 5: Music-Reactive Color Jump
    {

      break;
    }
    default:                 // Режим по умолчанию: Симуляция накаливания
    {
      for (int i = 0; i < NUMPIXELS; i++)
      {
        if (i % 2 == 0)
          strip.setPixelColor(i, 150, 200, 40); // Устанавливает для всей полосы значение по умолчанию
      }
      strip.setBrightness(255);
      strip.show();
      break;
    }
  }

}


void colorFade()
{
  int del = 100;     // 100 миллисекунд
  if (currColor >= numColors - 1)
  {

    int steps = fadeSpeed * del;
    int Rdiff, Gdiff, Bdiff, BrightDiff;

    Rdiff = R[0] - R[currColor];
    Gdiff = G[0] - G[currColor];
    Bdiff = B[0] - B[currColor];
    BrightDiff = Bright[0] - Bright[currColor];

    for (int i = 0; i <= steps + 5; i++)
    {
      for (int j = 0; j < NUMPIXELS; j++)
      {
        if (j % 2 == 0)
          strip.setPixelColor(j, (G[currColor] - (Gdiff * i)), (R[currColor] - (Rdiff * i)), (B[currColor] - (Bdiff * i))); // Устанавливает всю полосу в значение
      }
      //strip.setBrightness((Bright[currColor] - (BrightDiff * i)));
      strip.show();    
      // задержка (удаление);
      int timer = millis() + del;
      while(millis() < timer)
      {

      }
    }
    currColor = 0;
  }
  else
  {
    int steps = fadeSpeed * del;
    int Rdiff, Gdiff, Bdiff, BrightDiff;

    Rdiff = R[currColor + 1] - R[currColor];
    Gdiff = G[currColor + 1] - G[currColor];
    Bdiff = B[currColor + 1] - B[currColor];
    BrightDiff = Bright[currColor + 1] - Bright[currColor];

    for (int i = 0; i <= steps + 5; i++)
    {
      for (int j = 0; j < NUMPIXELS; j++)
      {
        if (j % 2 == 0)
          strip.setPixelColor(j, (G[currColor] - (Gdiff * i)), (R[currColor] - (Rdiff * i)), (B[currColor] - (Bdiff * i))); // Устанавливает всю полосу в значение
      }
      //strip.setBrightness((Bright[currColor] - (BrightDiff * i)));
      strip.show();    
      // задержка (удаление);

      int timer = millis() + del;
      while(millis() < timer)
      {

      }
    }
    currColor++;
  }
}

, 👍0

Обсуждение

начните отладку, запустив только выбор затухания... предустановленный режим до 2.... закомментируйте getData(); в цикле(), @jsotola

как мне отладить это в arduino IDE? Я не могу найти команду для точек останова, и я не знаю, что мне нужно было бы посмотреть, если бы я использовал serial.println() для чтения значений, @BoatHouse

В обычной встроенной прошивке нет отладки в смысле программирования WRT Arduino. Именно поэтому нужно начинать с малого и не добавлять ничего более сложного, пока мелочь не заработает., @st2000

это не "Arduino" ... это "C++" .... вставьте mode = 2; в setup() ... замените getData(); на // getData();, @jsotola

Посмотрев в другом месте, вы можете отладить arduino, отправив что-то на последовательный монитор через Serial.println(). Было бы полезно упомянуть об этом, так как я мог проверить значения таймера и millis() с помощью этой команды. timer переполнялся из-за типа данных int, и millis() в конечном итоге переворачивался и останавливался на верхнем пределе. Это было причиной проблемы, @BoatHouse

@BoatHouse Пожалуйста, напишите ответ на свой вопрос, чтобы другие могли извлечь из этого пользу. Спасибо, @chrisl


1 ответ


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

0

Проблема с приведенным выше кодом связана с переполнением. timer должен быть unsigned long, потому что millis() выводит unsigned long. Это вызывает зависание, потому что после того, как таймер достигает своего верхнего предела, эта настройка работает лучше:

unsigned long timer = (unsigned long)millis() + del;
      while((unsigned long)millis() < timer)
      {
        //ждем пока del скажет
      }

Эта установка должна работать в течение длительного времени без переполнения

,