Arduino IDE
Все светодиодные ленты, матрицы и кольца на основе WS2812b имеют три контакта на входе и столько же на выходе. Ниже разберемся почему так.
Теперь о подключении к Ардуино. Контакты на входе WS2812b маркируются как: VDC, DIN, GND. Контакты на выходе: VDC, DOUT, GND. Для подключения модуля к контроллеру используем только входную группу контактов:
Ардуино Уно | +5V | Gnd | D6 |
Модуль WS2812b | VDC | GND | DIN |
Вместо D6 можно использовать любой цифровой выход (включая A0..A5).
Соединение модулей цепочку
Зачем нужен контакт DOUT? Опять же из ранних уроков мы знаем, что обычные сдвиговые регистры легко соединяются в цепочку — то же самое с 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() {
}
Загружаем программу на Ардуино и наблюдаем радугу.
Надо также сказать, что компоненты цветов в нашей программе имеют уменьшенные в два раза значения яркости, в противном случае лента светит слишком ярко. Но даже при такой урезанной яркости, фотоаппарат сильно засвечивается и невозможно нормально передать всю палитру.
Программа: шкальный индикатор
Используем линейку адресных светодиодов в качестве индикатора уровня чего-либо. Для примера, сделаем индикатор уровня освещенности. Нам понадобится самый простой фоторезистор и обычный резистор на 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. Однако, в этой программе мы как и раньше явно задали весь градиент радуги.
Результат — плавно пробегающая по модулю радуга.