Мерцает лента ws2812b при использовании FastLED

aaneznanov

✩✩✩✩✩✩✩
12 Июл 2025
1
0
Всех приветствую.
Сейчас пытаюсь сделать часы, управляемую с ИК-пульта (либа NecDecoder), используя светодиодную ленту ws2812b длиной 1 м, на 144 светодиода (у меня используются 142). Программировать пробовал на библиотеке microLED, но ни скетч с радугой из гайда по светодиодкам, ни мой скетч не заставили ленту светиться: она не реагировала вообще.
Перешёл на FastLED, скопировал скетч из гайда, выводящий радугу: он заработал правильно, и лента выводила радугу корректно. Но когда я написал и загрузил свой скетч, возникла проблема. При выполнении функции setup() всё нормально (там я поочерёдно заполняю ленту красным, зелёным и синим цветом). Далее выполняется функция loop(), и тут чуть более половины ленты (где-то 80-90 светодиодов) работает нормально, а остальная часть мерцает в разных местах, но не случайными цветами, а такими же, как у остальных светодиодов.
Так как с другими скетчами всё работает правильно, с питанием всё в порядке, а сигнальный кабель короткий (10 см) и вряд ли ему мешают помехи, то могу предположить, что дело именно в программе. Подключал по схеме, тоже взятой из гайда.
Сам скетч:

C++:
#define LED_PIN 6       // пин ленты
#define LED_NUM 142     // кол-во светодидов

#define SEGMENT_LENGTH 5  // количество светодиодов на один сегмент часов
#define DOT_LENGTH 1      // количество светодиодов на одну точку - разделитель

// коды всех нужных кнопок пульта:
#define BTN_1 0xa2
#define BTN_2 0x62
#define BTN_3 0xe2
#define BTN_4 0x22
#define BTN_5 0x2
#define BTN_6 0xc2
#define BTN_7 0xe0
#define BTN_8 0xa8
#define BTN_9 0x90
#define BTN_0 0x98
#define BTN_UP 0x18
#define BTN_DOWN 0x4a
#define BTN_LEFT 0x10
#define BTN_RIGHT 0x5a
#define BTN_OK 0x38

#include <Arduino.h>    // стандартная библиотека Arduino
#include <NecDecoder.h> // библиотека для использования ИК-пульта
#include <FastLED.h>   // библиотека для управления светодиодной лентой
#include <limits.h>     // определитель лимитов значений типов переменных

CRGB leds[LED_NUM]; // массив светодиодов

NecDecoder ir;  // инициализация приёмника ИК-пульта

static uint8_t minute = 0;        // текущая минута
static uint8_t hour = 0;          // текущий час

void irIsr() {
  ir.tick();
}

void set_time(uint8_t number);                                            // режим установки времени
void time_add(uint8_t number, uint8_t digit);                             // прибавление переменных времени
void display(uint8_t number, uint8_t digit, CRGB disp_color);       // вывод значений на часы в заданном цвете
void fill_leds(uint8_t from_led, uint8_t to_led, CRGB fill_color);  // заполнение участка ленты заданным цветом

void setup(){
  pinMode(6, OUTPUT);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, LED_NUM).setCorrection(TypicalLEDStrip); // инициализация ленты
  attachInterrupt(0, irIsr, FALLING);
  FastLED.setBrightness(40);  // яркость = 40
  FastLED.clear();            
  fill_leds(0, LED_NUM, CRGB::Red);
  FastLED.show();
  delay(800);
  FastLED.clear();          
  fill_leds(0, LED_NUM, CRGB::Green);
  FastLED.show();
  delay(800);
  FastLED.clear();            
  fill_leds(0, LED_NUM, CRGB::Blue);
  FastLED.show();
  delay(800);
}

void loop() {
  static uint8_t brightness = 255;  // текущая яркость
  static uint8_t color = 0;         // текущий цвет
  static uint8_t color_mode = 0;    // режим цвета (0 - плавное изменение цвета, 1 - установленный пользователем цвет)
  static unsigned long last_minute_millis = millis(); // последнее прибавление минуты [в миллисекундах с начала работы часов]

  if(millis() - 60000 >= last_minute_millis || (last_minute_millis > millis() && ULONG_MAX - last_minute_millis + millis() >= 60000)){  // счётчик минут
    if(minute == 59){
      if(hour == 23){
        hour = 0;
      }
      else{
        ++hour;
      }
      minute = 0;
    }
    else{
      ++minute;
    }
    last_minute_millis = millis();
  }

  FastLED.clear();

  // чтение команд с ИК-пульта:
  if(ir.available()){
    switch(ir.readCommand()){
      case BTN_0:
        minute = 0;
        hour = 0;
        FastLED.clear();
        fill_leds(SEGMENT_LENGTH * 14, SEGMENT_LENGTH * 14 + DOT_LENGTH * 2, CRGB::Green);
        display(0, 0, CRGB::Green);
        set_time(1);
        last_minute_millis = millis();
        FastLED.show();
        break;
      case BTN_1:
        minute = 0;
        hour = 10;
        FastLED.clear();
        fill_leds(SEGMENT_LENGTH * 14, SEGMENT_LENGTH * 14 + DOT_LENGTH * 2, CRGB::Green);
        display(0, 1, CRGB::Green);
        set_time(1);
        last_minute_millis = millis();
        FastLED.show();
        break;
      case BTN_2:
        minute = 0;
        hour = 20;
        FastLED.clear();
        fill_leds(SEGMENT_LENGTH * 14, SEGMENT_LENGTH * 14 + DOT_LENGTH * 2, CRGB::Green);
        display(0, 2, CRGB::Green);
        set_time(1);
        last_minute_millis = millis();
        FastLED.show();
        break;
      case BTN_UP: brightness++; break;
      case BTN_DOWN: brightness--; break;
      case BTN_OK: color_mode = 0; break;
      case BTN_RIGHT:
        color_mode = 1;
        color += 10;
        break;
      case BTN_LEFT:
        color_mode = 1;
        color -= 10;
        break;
    }
  }

  if(color_mode == 0){ // плавное изменение цвета при режиме цвета == 0
    color++;
  }

  fill_leds(SEGMENT_LENGTH * 14, SEGMENT_LENGTH * 14 + DOT_LENGTH * 2, CHSV(color, 255, brightness)); // вывод точек

  // поочерёдный вывод всех цифр:
  display(0, hour / 10, CHSV(color, 255, brightness));
  display(1, hour % 10, CHSV(color, 255, brightness));
  display(2, minute / 10, CHSV(color, 255, brightness));
  display(3, minute % 10, CHSV(color, 255, brightness));

  FastLED.show();
  FastLED.delay(200);
}

void set_time(uint8_t number){ // функция cчитывания нажатий для установки времени
  if(ir.available()){
    switch(ir.readCommand()){
      case BTN_0: time_add(number, 0); break;
      case BTN_1: time_add(number, 1); break;
      case BTN_2: time_add(number, 2); break;
      case BTN_3: time_add(number, 3); break;
      case BTN_4: time_add(number, 4); break;
      case BTN_5: time_add(number, 5); break;
      case BTN_6: time_add(number, 6); break;
      case BTN_7: time_add(number, 7); break;
      case BTN_8: time_add(number, 8); break;
      case BTN_9: time_add(number, 9); break;
    }
  }
  if(number < 3){
    set_time(number + 1);
  }
}

void time_add(uint8_t number, uint8_t digit){ // функция установки времени
  if(number == 1){
    hour += digit;
  }
  else if(number == 2){
    minute += (digit * 10);
  }
  else{
    minute += digit;
  }
  display(number, digit, CRGB::Green);
}

void display(uint8_t number, uint8_t digit, CRGB disp_color) { // функция вывода цифр на часы, где number - место выведения цифры, digit - выводимая цифра
  int offset = number * SEGMENT_LENGTH * 7; // смещение в зависимости от места выведения цифры
  if(digit > 1){
    offset += DOT_LENGTH * 2;
  }
  switch(digit){
    case 0:
      fill_leds(0 + offset, SEGMENT_LENGTH * 6 + offset, disp_color);
      break;
    case 1:
      fill_leds(SEGMENT_LENGTH * 2 + offset, SEGMENT_LENGTH * 4 + offset, disp_color);
      break;
    case 2:
      fill_leds(SEGMENT_LENGTH + offset, SEGMENT_LENGTH * 3 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 4 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
    case 3:
      fill_leds(SEGMENT_LENGTH + offset, SEGMENT_LENGTH * 5 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 6 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
    case 4:
      fill_leds(0 + offset, SEGMENT_LENGTH + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 2 + offset, SEGMENT_LENGTH * 4 + offset, disp_color);
      break;
    case 5:
      fill_leds(0 + offset, SEGMENT_LENGTH * 2 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 3 + offset, SEGMENT_LENGTH * 5 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 6 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
    case 6:
      fill_leds(0 + offset, SEGMENT_LENGTH * 2 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 3 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
    case 7:
      fill_leds(SEGMENT_LENGTH + offset, SEGMENT_LENGTH * 4 + offset, disp_color);
      break;
    case 8:
      fill_leds(0 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
    case 9:
      fill_leds(0 + offset, SEGMENT_LENGTH * 5 + offset, disp_color);
      fill_leds(SEGMENT_LENGTH * 6 + offset, SEGMENT_LENGTH * 7 + offset, disp_color);
      break;
  }
}

void fill_leds(uint8_t from_led, uint8_t to_led, CRGB fill_color){ // функция заполнения участка ленты определённым цветом
  for(uint8_t i = from_led; i < to_led; i++){
    leds[i] = fill_color;
  }
}
Занимаюсь программированием не так долго, поэтому код может быть корявым
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
634
189
Чтобы ответить на ваш вопрос надо сначала понять, что вы хотите сделать, потом что и как вы делаете, потом найти там ошибку (если она программная а не оборудования).
Если никто не захочет этого делать, то попробуйте сами локализовать ошибку. Проверяйте код по шагам. Проверили, что работает заливка. Проверьте вывод цифры. Потом нескольких цифр, потом всех. Потом один режим, потом все. Потом добавляйте управление по ИК. Определив на каком шаге появляется ошибка, будет проще понять ее причину. Можно идти с конца и постепенно удалять функционал из вашего скетча, до работоспособного состояния.
 
  • Лойс +1
Реакции: aaneznanov