Diody LED ze sterownikem WS2801
W dzisiejszym wpisie postaram się Wam przybliżyć, jak w prosty sposób można sterować taśmami diod RGB. Można zrobić to na wiele sposobów - na przykład podłączyć każdą diodę z osobna i wysterować za pomocą sterownika. Jednak takie rozwiązanie wiązałoby się (w zależności od ilości diod RGB) z prowadzeniem ogromnej ilości przewodów. Dodatkowo musielibyśmy rozbudować nasz układ o rejestry przesuwne, gdyż jak wiemy platforma Arduino ma ograniczoną liczbę wyjść PWM, które będziemy potrzebowali do określenia natężenia świecenia każdej diody.
Na pomoc przyjdzie nam układ WS2801 - wyspecjalizowany właśnie do sterowania diodami LED połączonych ze sobą szeregowo. Zaletą wykorzystania tego układu w taśmach LED jest bardzo mała ilość przewodów, ponieważ układy są ze sobą połączone linią zegarową, linią danych i zasilaniem. Dane przekazywane są od pierwszego, aż do ostatniego układu, tworząc coś w rodzaju rejestru przesuwnego. Każdy układ z zapamiętuje dane z linii danych i z otrzymaniem sygnału zegarowego przesyła zapamiętane wartości dalej, zapamiętując nowe. Ułatwieniem dla nas jest fakt, że układ posiada wejścia z modulacją PWM, co pozwoli nam na sterowanie jasnością diod oraz bezpośrednie podłączenie do Arduino.
Jak sterować?
Sterowanie układami WS2801 jest proste jak budowa cepa, tym bardziej, że jest do tego stworzona specjalna biblioteka dla Arduino. Wystarczy ją tylko pobrać i skopiować do naszych bibliotek:
- git clone https://github.com/adafruit/Adafruit-WS2801-Library
Następnie do naszego szkicu dodajemy nagłówki oraz tworzymy odpowiednią instancję Adafruit_WS2801
- #include "SPI.h"
- #include "Adafruit_WS2801.h"
- int dataPin = 2; // Pin danych
- int clockPin = 3; // Pin zegara
- // Tworzymy instancję Adafruit_WS2801
- // Liczba "25" oznacza liczbę układów połączonych szerogowo
- Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin);
- // Można również określić w matrycy 7x7:
- // Adafruit_WS2801 strip = Adafruit_WS2801((uint16_t)7, (uint16_t)7, dataPin, clockPin);
W konstruktorze setup() inicjujemy tylko naszą "taśmę" LED:
- void setup() {
- ...
- strip.begin();
- // Wywołanie od drazu metody show() spowoduje wyłączenie wszystkich diod
- strip.show();
- ...
- }
Biblioteka udostępnia najbardziej istotne metody:
- show() - wysłanie danych
- setPixelColor(...) - ustawienie koloru wybranej diody w układzie linii lub matrycy
- setPixelColor(numer_diody, skladowa_r, skladowa_g, skladowa_b)
- setPixelColor(numer_diody, spakowany_kolor_rgb_32bit)
- setPixelColor(x, y, skladowa_r, skladowa_g, skladowa_b)
- setPixelColor(x, y, spakowany_kolor_rgb_32bit)
- getPixelColor(numer_diody) - pobranie koloru wybranej diody
- numPixels() - zwraca liczbę diod
- updateLength(liczba_diod) - zmiana definicji ilości diod
Zastosowanie w praktyce
Bazując na wpisie wielozadaniowości w Arduino rozbudujemy układ do zadania sterownika lampek choinkowych, ale nie byle jakich. Dodamy bowiem trzeci przycisk do zmiany programu efektów. Jako diody RGB wykorzystano łańcuch diod RGB z wbudowanymi już układami WS2801 z oferry Adafruit.
Bez problemu można znaleźć takie diody w ofercie polskiego dystrybutora, firmy Nettigo.
Układ połączeń. Vcc = 5V
Jak to działa?
Listing programu
- #include <Bounce.h>
- #include "leOS2.h"
- #include "SPI.h"
- #include "Adafruit_WS2801.h"
- leOS2 threads;
- int buttonStartStopPin = 2; // PIN2 - Przycisk włącz / wyłącz
- int buttonSpeedPin = 4; // PIN4 - Przycisk zmiany prędkości
- int buttonModePin = 8; // PIN8 - Przycisk zmiany efektu
- int greenLedPin = 3; // PIN3 - Dioda zielona
- int yellowLedPin = 5; // PIN5 - Dioda żółta
- int redRGBPin = 9; // PIN9 - RGB - Dioda czerwona
- int greenRGBPin = 10; // PIN10 - RGB - Dioda zielona
- int blueRGBPin = 11; // PIN11 - RGB - Dioda niebieska
- int yellowLedSpeed = 100; // Prędkość początkowa procesu mrugania
- int greenLedPWM = 255; // Wypełnienie początkowe PWM diody zielonej
- byte greenLedStatus = 1; // Status diody zielonej
- byte yellowLedStatus = 0; // Status diody żóltej
- byte actualMode = 0; // Numer aktualnego progroamu
- typedef void (* DigitFuncPtr) (); // Programy efektów
- DigitFuncPtr modes[4] = {wipe, rainbow, cycle, stars};
- int step = 0; // Licznik kroków do efektów
- int randomR = 0; // Losowa wartość R do efektu "wipe"
- int randomG = 0; // Losowa wartość G do efektu "wipe"
- int randomB = 0; // Losowa wartość B do efektu "wipe"
- int dataPin = 6; // Dane taśmy LED
- int clockPin = 7; // Zegar taśmy LED
- // Ustawiamy nasze "bouncery" z interwałem czasowym 40ms
- Bounce bouncerStartStop = Bounce(buttonStartStopPin, 40);
- Bounce bouncerSpeed = Bounce(buttonSpeedPin, 40);
- Bounce bouncerMode = Bounce(buttonModePin, 40);
- // Konfigurujemy taśmę LED jako łańcuch 25 diod
- Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin);
- // Konfiguracja pinów i wątków
- void setup()
- {
- randomSeed(analogRead(0));
- strip.begin(); // Inicjujemy taśmę LED
- threads.begin(); // Rozpoczynamy pracę z wątkami
- // Przyciski
- pinMode(buttonStartStopPin, INPUT);
- pinMode(buttonSpeedPin, INPUT);
- pinMode(buttonModePin, INPUT);
- // Diody
- pinMode(redRGBPin, OUTPUT);
- pinMode(greenRGBPin, OUTPUT);
- pinMode(blueRGBPin, OUTPUT);
- pinMode(yellowLedPin, OUTPUT);
- pinMode(greenLedPin, OUTPUT);
- // Aktualizujemy zawartość taśmy LED (na start gasimy)
- strip.show();
- // Dodajemy zadania uruchamiane od razu
- threads.addTask(flashGreenLed, threads.convertMs(25), SCHEDULED_IMMEDIATESTART);
- threads.addTask(onOffPush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
- threads.addTask(speedPush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
- threads.addTask(modePush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
- // Dodajemy zadania do uruchomienia później
- threads.addTask(flashYellowLed, threads.convertMs(yellowLedSpeed), PAUSED);
- }
- // Główna pętla programu - tym razem pusta
- void loop()
- {
- }
- // Wątek obsługi przycisku zmiany prędkości
- void modePush()
- {
- int i;
- // Aktualizujemy status przycisku
- bouncerMode.update();
- // Reagujemy na zbocze narastające
- if (bouncerMode.risingEdge())
- {
- // Ustawiamy tryb
- actualMode++;
- if (actualMode > 3)
- {
- actualMode = 0;
- }
- // Czyścimy taśmę LED
- for (i = 0; i < strip.numPixels(); i++)
- {
- strip.setPixelColor(i, 0);
- }
- // Wyświetlamy
- strip.show();
- step = 0;
- // Zapalamy niebieską didę
- digitalWrite(blueRGBPin, HIGH);
- }
- }
- // Wątek obsługi przycisku zmiany prędkości
- void speedPush()
- {
- // Aktualizujemy status przycisku
- bouncerSpeed.update();
- // Reagujemy na zbocze narastające
- if (bouncerSpeed.risingEdge())
- {
- // Zmniejszamy czas oczekiwania na wątek
- yellowLedSpeed -= 20;
- // Jeśli prędkość wynosi 0, ustawiamy na 100
- if (yellowLedSpeed == 0)
- {
- yellowLedSpeed = 100;
- }
- // Sygnalizujemy zieloną diodą RGB
- digitalWrite(greenRGBPin, HIGH);
- // Zapamiętujemy status naszego wątka flashYellowLed
- byte taskStatus = threads.getTaskStatus(flashYellowLed);
- // Usuwamy wątek mrugania żółtą diodą
- threads.removeTask(flashYellowLed);
- // Dodajemy nowy wątek ze starym statusem i nowym czasem
- threads.addTask(flashYellowLed, threads.convertMs(yellowLedSpeed), taskStatus);
- } else
- {
- // Gasimy diodę RGB, zieloną i niebieską
- digitalWrite(greenRGBPin, LOW);
- digitalWrite(blueRGBPin, LOW);
- }
- }
- // Wątek obsługi przycisku wlącz/wyłącz
- void onOffPush()
- {
- // Aktualizujemy status przycisku
- bouncerStartStop.update();
- // Reagujemy na zbocze narastające
- if (bouncerStartStop.risingEdge())
- {
- // Sygnalizujemy czerwoną diodą RGB
- digitalWrite(redRGBPin, HIGH);
- // Pobieramy status naszego wątka flashYellowLed
- byte taskStatus = threads.getTaskStatus(flashYellowLed);
- // Jeśli jest zatrzymany to wznawiamy
- // Jeśli nie jest zatrzymany to zatrzymujemy i gasimy diodę żółtą
- if (taskStatus == 0)
- {
- threads.restartTask(flashYellowLed);
- } else
- {
- threads.pauseTask(flashYellowLed);
- digitalWrite(yellowLedPin, 0);
- }
- } else
- {
- // Gasimy diodę RGB, czerwoną
- digitalWrite(redRGBPin, LOW);
- }
- }
- // Wątek mrugania PWM diodą zieloną
- void flashGreenLed()
- {
- // Zmniejszamy wartość PWM dla diody zielonej
- greenLedPWM -= 5;
- // Jeśli była zapalona to wysyłamy
- if (greenLedStatus == 1)
- {
- analogWrite(greenLedPin, greenLedPWM);
- }
- // Jeśli PWM wyniosło 0 to ustawiamy pełne PWM i zmieniamy status diody
- if (greenLedPWM == 0)
- {
- greenLedPWM = 255;
- greenLedStatus ^= 1;
- }
- }
- // Efekt "wipe"
- void wipe()
- {
- // Jeśli nie mamy wylosowanego koloru - losujemy
- if ((randomR == 0) && (randomG == 0) && (randomB == 0))
- {
- randomR = random(255);
- randomG = random(255);
- randomB = random(255);
- }
- strip.setPixelColor(step, randomR, randomG, randomB);
- step++;
- // Jeśli cała taśma świeci - losujemy nowy kolor
- if (step == strip.numPixels())
- {
- step = 0;
- randomR = 0;
- randomG = 0;
- randomB = 0;
- }
- strip.show();
- }
- // Efekt "stars"
- void stars()
- {
- int i, h, n;
- int leds = 0;
- // Badamy ile diod się świeci
- for (i = 0; i < strip.numPixels(); i++)
- {
- uint32_t color = strip.getPixelColor(i);
- // Jeśli świeci
- if (color != 0)
- {
- leds++;
- // Przygaszamy
- h = (color & 0x0000ff) - 1;
- if (h < 0)
- {
- leds--;
- h = 0;
- }
- strip.setPixelColor(i, h, h, h);
- }
- }
- // Maksymalnie może być 5 zapalonych
- for (i = leds; i < 5; i++)
- {
- h = random(128, 255);
- n = random(0, strip.numPixels());
- strip.setPixelColor(n, h, h, h);
- }
- strip.show();
- }
- // Efekt "rainbow"
- void rainbow()
- {
- int i;
- for (i = 0; i < strip.numPixels(); i++)
- {
- strip.setPixelColor(i, Wheel((i + step) % 255));
- }
- step++;
- if (step == 256)
- {
- step = 0;
- }
- strip.show();
- }
- // Efekt "cycle"
- void cycle()
- {
- int i;
- for (i = 0; i < strip.numPixels(); i++)
- {
- strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + step) % 256));
- }
- step++;
- if (step == 1280)
- {
- step = 0;
- }
- strip.show();
- }
- // Wątek mrugania diodą żółtą i wykonania kroku wybranego programu
- void flashYellowLed()
- {
- // Negujemy status diody żółtej
- yellowLedStatus ^= 1;
- // Wysyłamy
- digitalWrite(yellowLedPin, yellowLedStatus);
- // Wykonuj wybrany program
- modes[actualMode]();
- }
- // Funkcja pomocnicza, tworząca kolor 32-bitowy ze składowych RGB
- uint32_t Color(byte r, byte g, byte b)
- {
- uint32_t c;
- c = r;
- c <<= 8;
- c |= g;
- c <<= 8;
- c |= b;
- return c;
- }
- // Funkcja pomocnicza, tworząca definicję okręgu koloru z przejściami R-G-B-R
- uint32_t Wheel(byte WheelPos)
- {
- if (WheelPos < 85)
- {
- return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
- } else
- if (WheelPos < 170)
- {
- WheelPos -= 85;
- return Color(255 - WheelPos * 3, 0, WheelPos * 3);
- } else
- {
- WheelPos -= 170;
- return Color(0, WheelPos * 3, 255 - WheelPos * 3);
- }
- }
Wszystkie materiały wykorzystane w tym wpisie, możecie znaleźć tutaj.
Reklama
Komentarze
Witam Panie Korneliuszu,
Czy mógłbym mieć do Pana prośbę?
kombinuję z efektem \'rainbow\' lecz nie idzie mi animacja...
Diody się zapalają (74szt) w okręgu w ładnych kolorach, ale animacja stoi w miejscu...
Czy mógłby mi Pan podpowiedzieć czego mi może brakować?
z góry dziekuję
Marcin
Ustawił Pan odpowiednią ilość diod w linii 44?
Witam,
Na schemacie jest błąd wynikający z konfiguracji samego kodu. Przycisk nr 3 na schemacie podpięty jest do pinu D6 podczas gdy w programie jest przypisany do pinu D12. Poza tym program obłędny. Gratuluje i pozdrawiam.
Właściwie to do D8 :) dzięki - poprawione
Plik z kodem pobrany ze strony akurat miał 12 ;) ale nie wazne. Co do tej linii 44, po wyżej ilości 99 program głupieje i zawiesza arduino. :/ jest na to jakieś logiczne wytłumaczenie??
Witam
Chciałem zapytać o dodawanie nagłówków do naszego szkicu i konstruktor setup().Nie jestem biegły w tych sprawach.Czy,możesz mi bardziej wytłumaczyć,gdzie to ma być dodane[wklejone],bo nie bardzo rozumiem.
Czy ,tu chodzi o bibliotekę którą sciągneliśmy dla WS2801,czyli Adfruit_WS2801.cpp oraz Adfruit_WS2801.h
Biblioteki instalujesz do katalogu sketchbook/libraries/ tu masz przykład na innej bibliotece: http://www.jarzebski.pl/arduino/biblioteki/bounce-jako-lek-na-migotanie-przyciskow.html
Witam serdecznie.
Chcę uruchomić efekt ambilight na RPi B+.
Niestety nie mogę nigdzie odszukać pliku
boblight-25-5-8-5-7.conf -O /etc/boblight.conf.
czy jest możliwość podesłania go na email lub o linka skąd można go pobrać?
Z góry bardzo dziękuję.
Witam czy jest opcja, żeby podłączyć do tego układu diody led rgb ws2811 lub ws2812 czy trzeba coś zmieniać?
Zasadnicze pytanie - po co ?
Chciałbym wykorzystać ten układ sterowania głownie chodzi steowanie przyciskami wybór programu itd do led ws2812 lub ws2811. Nie znam się więc pytam :)
Chciałbym wykorzystać ten układ sterowania głownie chodzi steowanie przyciskami wybór programu itd do led ws2812 lub ws2811. Nie znam się więc pytam :)
Witam !
Podczas kompilacji zatrzymuje się mi na 28 linii:
DigitFuncPtr modes[4] = {wipe, rainbow, cycle, stars};
i twierdzi:
example03_ws2801:29: error: \'wipe\' was not declared in this scope
i tak z każdym modem: wipe, rainbow, cycle, stars
co robić ?