W projektach elektronicznych dużą popularnością cieszą się taśmy LED. Są tanie, efektowne i wygodne w użyciu. Taśmy LED to nic innego jak połączone ze sobą diody RBG. Zwykle sprzedawane są ze sterownikiem, za pomocą którego możemy zarządzać diodami (ich kolorem, jasnością).
Moduł WS2812
Na listwie modułu znajduje się 8 małych diod LED RGB 5050 (5 mm x 5 mm) z otworami montażowymi i łańcuchową konstrukcją. Każda dioda LED jest adresowana, dzięki sterownikowi, który znajduje się wewnątrz diody.
Moduł może być zasilany napięciem od 4 do 7V. Koszt tego urządzenia jest niewielki (około 15 zł).
W jednym z projektów w naszej firmie postanowiliśmy zastosować ten moduł jako panel informujący o pracy czujników w ramach danego urządzenia.
Skąd ten wybór?
Możemy sterować 8 diodami korzystając wyłącznie z jednego portu GPIO. W przypadku zastosowania klasycznych diod byłoby to aż 8 zajętych portów mikrokontrolera (w tym przypadku ESP8266).
O ile istnieją biblioteki do zarządzania diodami pozwalające zapalać i gasić wiele diod naraz to gdy chcemy sterować wyłącznie jedną diodą bez zmiany stanu pozostałych, to możemy napotkać się z nie lada problemem. W tym artykule podpowiemy, jak ten problem rozwiązać.
WS2812 i ESP8266
W tym przypadku za serce naszego układu będzie odpowiadać ESP8266 ale nie ma żadnego problemu by było to np. Arduino. Wszelkie opisywane metody będą działać dokładnie tak samo na Arduino.
Do zarządzania diodami użyjemy popularnej biblioteki NeoPixel od Adafruit.
Poniżej przykładowy kod, który zapali diody jedna po drugiej na kolor czerwony.
#include <Adafruit_NeoPixel.h>
// PIXELS
#define PIXELS_PIN D6
#define PIXEL_COUNT 8
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXELS_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
// PIXELS
pixels.begin();
pixels.clear();
pixels.setBrightness(80);
for (int i = 0; i < PIXEL_COUNT; i++)
{
pixels.setPixelColor(i, 255,0,0);
pixels.show();
delay(100);
}
}
void loop() {
}
Użyte funkcje:
begin() – włączenie modułu.
setBrightness() – ustawianie jasności paska z diodami. Funkcja przyjmuje wartości od 0 do 255.
setPixelColor() – za pomocą tej funkcji deklarujemy kolor jaki my wyświetlać poszczególna dioda. Diody oznaczamy od zaczynając od numeru 0. W naszym przykładzie nr diody przypisany jest do zmiennej i. W dalszej części funkcji deklarujemy kolor w postaci wartości RGB.
pixels.show() – zadeklarowanie koloru nic nam nie da, dopóki nie włączymy diod, robimy to za pomocą tej funkcji. Gdy zmienimy cokolwiek w diodach to by zauważyć różnicę, musimy wywołać tę funkcję po każdej zmianie.
Wynik naszego programu prezentuje się w następujący sposób:
WS2812 i utrzymanie stanu diody
Jak zauważyliście możemy zapalić wszystkie diody na raz (z lekkim opóźnieniem). Możemy zmienić kolor poszczególnej diody, ale gdy to zrobimy, to nadpiszemy stan pozostałych diod. Ich ustawienia zostaną “zresetowane”.
Co zatem zrobić gdy chcemy wyłączyć / wyłączyć jedną diodę i zachować stan pozostałych? Musimy stan z każdej z diody zapisać w tablicy.
Tworzymy nową tablicę zawierającą 8 elementów. Każdy element będzie reprezentować jedną diodę.
int PIXELS_DATA[8]={0,0,0,0,0,0,0,0};
Gdzie:
0 - dioda wyłączona
1 - dioda włączona
Wyłączenie diody uzyskamy nadając jej “czarny” kolor. Parametry RGB ustawiamy na zero.
Zanim napiszemy funkcję do zmiany stanu poszczególnej diody, warto zoptymalizować możliwość zmiany jej koloru. Możemy stworzyć np. taką funkcję:
void setPixel(int pixel, byte red, byte green, byte blue) {
pixels.setPixelColor(pixel, pixels.Color(red, green, blue));
}
Oczywiście możemy dowolnie ustalać kolory. W moim urządzeniu pierwsza dioda informuje czy urządzenie działa a pozostałe pokazują czy dany czujnik pracuje prawidłowo.
Jak zmienić stan poszczególnej diody?
Musimy zmienić wartość z 0 do 1 lub z 0 do 1 w tablicy PIXELS_DATA.
Stwórzmy do tego funkcję:
void setLED(int led, int state){
PIXELS_DATA[led] = state;
for (int i = 0; i < PIXEL_COUNT; i++){
if(PIXELS_DATA[i] == 1){
setPixel(i, colors[i][0], colors[i][1], colors[i][2]);
} else{
setPixel(i, 0, 0, 0);
}
}
pixels.show();
}
Funkcja początkowo zmienia stan na poszczególnym elemencie tablicy a następnie przechodzi kolejno po tablicy PIXELS_DATA i w zależności od wartości stanu ustala kolor przypisany w tablicy colors lub ustala kolor czarny.
Przykład użycia:
setLED(0,1);
setLED(1,0);
delay(500);
setLED(1,1);
setLED(2,1);
setLED(3,1);
delay(500);
Wywołanie tego kodu w funkcji loop spowoduje zapalenie pierwszej diody na kolor czerwony. Druga dioda będzie migać a 3 i 4 będą świeciły się na kolor zielony.
Cały kod prezentuje się w ten sposób:
#include <Adafruit_NeoPixel.h>
// PIXELS
#define PIXELS_PIN D6
#define PIXEL_COUNT 8
int PIXELS_DATA[8]={0,0,0,0,0,0,0,0};
const byte colors[8][3] = {
{255, 0, 0}, //red
{0, 255, 0}, //green
{0, 255, 0}, //green
{0, 255, 0}, //green
{0, 255, 0}, //green
{0, 255, 0}, //green
{0, 255, 0}, //green
{0, 255, 0}, //green
};
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_COUNT, PIXELS_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
// PIXELS
pixels.begin();
pixels.clear();
pixels.setBrightness(80);
for (int i = 0; i < PIXEL_COUNT; i++)
{
setPixel(i, 255, 0, 0);
pixels.show();
delay(100);
}
}
void loop() {
setLED(0,1);
setLED(1,0);
delay(500);
setLED(1,1);
setLED(2,1);
setLED(3,1);
delay(500);
}
void setPixel(int pixel, byte red, byte green, byte blue) {
pixels.setPixelColor(pixel, pixels.Color(red, green, blue));
}
void setLED(int led, int state){
PIXELS_DATA[led] = state;
for (int i = 0; i < PIXEL_COUNT; i++){
if(PIXELS_DATA[i] == 1){
setPixel(i, colors[i][0], colors[i][1], colors[i][2]);
} else{
setPixel(i, 0, 0, 0);
}
}
pixels.show();
}
Wynik naszego programu:
Kod wykorzystany w projekcie możesz pobrać z naszego repozytorium na Githubie, a jeśli chcesz nauczyć się więcej, to zachęcamy do skorzystania z naszego darmowego, na bieżąco aktualizowanego kursu.