Arduino IDE

Все светодиодные ленты, матрицы и кольца на основе WS2812b имеют три контакта на входе и столько же на выходе. Ниже разберемся почему так.

Теперь о подключении к Ардуино. Контакты на входе WS2812b маркируются как: VDC, DIN, GND. Контакты на выходе: VDC, DOUT, GND. Для подключения модуля к контроллеру используем только входную группу контактов:

Ардуино Уно+5VGndD6
Модуль WS2812bVDCGNDDIN

Вместо D6 можно использовать любой цифровой выход (включая A0..A5).

Соединение модулей цепочку

Зачем нужен контакт DOUT? Опять же из ранних уроков мы знаем, что обычные сдвиговые регистры легко соединяются в цепочку — то же самое с WS2812b. Как правило, на всех сборках адресных модулей выведены контакты первого светодиода и последнего.

Адресные светодиоды ws2812b

Благодаря этому, мы можем подключать один модуль к другому, наращивая цепочку до нужных размеров.

Адресные светодиоды ws2812b в цепочке

Программа: радуга

В первой программе для WS2812b мы попробуем зажечь линейку семью цветами радуги, а оставшийся 8-й светодиод пусть горит белым.

Для работы с адресными модулями используем библиотеку Adafruit_NeoPixel. Установить её можно с помощью менеджера библиотек в Arduino IDE.

#include <Adafruit_NeoPixel.h>

#define PIN            6 // это контакт, к которому подключен DIN
#define NUMPIXELS      8 // количество светодиодов, которыми мы хотим управлять

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// определим массив с цветами радуги, указав RGB компоненты каждого цвета
byte rainbow[8][3] = {{128,0,0},{128,64,0},{128,128,0},{0,128,0},{0,128,128},{0,0,128},{128,0,128},{128,128,128}};

void setup() {
    // инициализации модуля Adafruit_NeoPixel
    pixels.begin();
    // перебираем светодиоды и выводим ка каждый нужный цвет
    for(int i=0; i<NUMPIXELS; i++){
        pixels.setPixelColor(i, pixels.Color(rainbow[i][0],rainbow[i][1],rainbow[i][2]));
    }
    // выводим цветовую последовательность на модуль WS2812b
    pixels.show();
}

void loop() {
}

Загружаем программу на Ардуино и наблюдаем радугу.

Адресные светодиоды ws2812b

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

Программа: шкальный индикатор

Используем линейку адресных светодиодов в качестве индикатора уровня чего-либо. Для примера, сделаем индикатор уровня освещенности. Нам понадобится самый простой фоторезистор и обычный резистор на 10 кОм в пару к нему. Схему подключения фоторезистора возьмем из урока.

В суперцикле loop будем считывать значение с ноги A0, нормировать его в диапазон 0..8 и зажигать соответствующие светодиоды.

#include <Adafruit_NeoPixel.h>

#define PIN            6
#define NUMPIXELS      8

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

const int photoPin = A0;

// палитра
byte pallete[4][3] = {
  {0,0,0},
  {128,0,0},
  {128,64,0},
  {0,128,0}
};

void setup() {
    pinMode(photoPin, INPUT);
    pixels.begin();
    Serial.begin(9600);

    // немного помигаем первым светодиодом
    // чтобы проверить работоспособность
    for(byte i=0; i<5; i++){
        pixels.setPixelColor(0, 128,0,0);
        pixels.show();
        delay(100);
        pixels.setPixelColor(0, 0,0,0);
        pixels.show();
        delay(100);
    }
}

void loop() {
    // считываем значения с аналогового входа
    int v = analogRead(photoPin);
    // нормируем значения в диапазон от 0 до 7
    v = v/128; 
    for(byte i=0; i<NUMPIXELS; i++){
        // всё что выше v-го светодиода окрашиваем в чёрный
        // что означает - выключаем светодиод
        if (i>v){ 
            pixels.setPixelColor(i, pallete[0][0], pallete[0][1], pallete[0][2]);
        // остальные светодиоды делим на группы
        // каждая группа горит своим цветом
        } else {
            // сначала три красных
            if (i<3)
                pixels.setPixelColor(i, pallete[1][0], pallete[1][1], pallete[1][2]);
            // затем три оранжевых
            else if (i<6)
                pixels.setPixelColor(i, pallete[2][0], pallete[2][1], pallete[2][2]);
            // в конце два зелёных
            else if (i<8)
                pixels.setPixelColor(i, pallete[3][0], pallete[3][1], pallete[3][2]);
        }
    }

    pixels.show();
    delay(10);
}

Здесь нужно пояснить, почему мы поделили v на 128. Предположим, что значения, которые приходят с фоторезистора на аналоговый вход A0 могут изменяться от 0 до 1024. В таком случае, чтобы отображать на нашей шкале изменения пропорционально изменению значения на A0, нам придется поделить v как раз на 128, ведь 1024 — это 8 раз по 128. Но если внешнее освещение изменится, или у нас будут фоторезистор и резистор других номиналов — придётся отредактировать эту формулу.

А вот и результат:

Программа: анимация

Следующая программа заставит радугу двигаться! Даже переливаться.

#include <Adafruit_NeoPixel.h>

#define PIN            6 // это контакт, к которому подключен DIN
#define NUMPIXELS      8 // количество светодиодов, которыми мы хотим управлять
#define NUMCOLORS      24 // количество цветов в палитре

byte start_pixel = 0; // номер светодиода, с которого начинает строиться радуга

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// расширенная палитра радуги
byte rainbow[NUMCOLORS][3] = {
  {128,0,0}, {128,32,0}, {128,64,0}, {128,96,0},
  {128,128,0}, {96,128,0}, {64,128,0}, {32,128,0},
  {0,128,0}, {0,128,32}, {0,128,64}, {0,128,96},
  {0,128,128}, {0,96,128}, {0,64,128}, {0,32,128},
  {0,0,128}, {32,0,128}, {64,0,128}, {96,0,128},
  {128,0,128}, {128,0,96}, {128,0,64}, {128,0,32}
};

void setup() {
    // инициализации модуля Adafruit_NeoPixel
    pixels.begin();
}

void loop() {
    byte k = start_pixel;
    for(int i=0; i<NUMPIXELS; i++){
        // вычисляем текущий номер цвета k в палитре rainbow для i-го светодиода
        k ++;
        if( k == NUMCOLORS )
            k = 0;
        pixels.setPixelColor(i, rainbow[k][0],rainbow[k][1],rainbow[k][2]);
    }

    pixels.show();

    // увеличиваем точку старта на единицу
    // при достижении края палитры - обнуляем
    start_pixel ++;
    if( start_pixel == NUMCOLORS )
        start_pixel = 0;

    delay(50);
}

Большую палитру нерационально хранить в массиве, ведь оперативной памяти у Ардуино не так много. Имеет смысл генерировать каждый последующий цвет радуги на лету, прямо перед выводом на WS2812b. Однако, в этой программе мы как и раньше явно задали весь градиент радуги.

Результат — плавно пробегающая по модулю радуга.


Изменено: