SantyagoSantyago
Avatar

Witaj!
Blog archiwalny. Już niebawem nowy serwis!

YouTube RSS Facebook GitHub

Arduino poradnik

Wstęp

Teoria

Biblioteki

Komponenty

Czujniki i sensory

Rozwiązania i algorytmy

Narzędzia

Mikrokontrolery i Arduino IDE

Arduino i klony

Poradniki wideo

Reklama na Blogu

Najnowsze poradniki

Ostatnie komentarze

Ostatnie fotografie

polskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorywieliczka-szyb-danilowicza

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.

Typowy układ aplikacyjny WS2801

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:

  1. git clone https://github.com/adafruit/Adafruit-WS2801-Library

Następnie do naszego szkicu dodajemy nagłówki oraz tworzymy odpowiednią instancję Adafruit_WS2801

  1. #include "SPI.h"
  2. #include "Adafruit_WS2801.h"
  3.  
  4. int dataPin = 2;  // Pin danych
  5. int clockPin = 3; // Pin zegara
  6.  
  7. // Tworzymy instancję Adafruit_WS2801
  8. // Liczba "25" oznacza liczbę układów połączonych szerogowo
  9. Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin);
  10. // Można również określić w matrycy 7x7:
  11. // Adafruit_WS2801 strip = Adafruit_WS2801((uint16_t)7, (uint16_t)7, dataPin, clockPin);

W konstruktorze setup() inicjujemy tylko naszą "taśmę" LED:

  1. void setup() {
  2.   ...
  3.   strip.begin();
  4.  
  5.   // Wywołanie od drazu metody show() spowoduje wyłączenie wszystkich diod
  6.   strip.show();
  7.   ...
  8. }

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

  1. #include <Bounce.h>
  2. #include "leOS2.h"
  3. #include "SPI.h"
  4. #include "Adafruit_WS2801.h"
  5.  
  6. leOS2 threads;
  7.  
  8. int buttonStartStopPin = 2;    // PIN2 - Przycisk włącz / wyłącz
  9. int buttonSpeedPin = 4;        // PIN4 - Przycisk zmiany prędkości
  10. int buttonModePin = 8;        // PIN8 - Przycisk zmiany efektu
  11.  
  12. int greenLedPin = 3;           // PIN3  - Dioda zielona
  13. int yellowLedPin = 5;          // PIN5  - Dioda żółta
  14.  
  15. int redRGBPin = 9;             // PIN9  - RGB - Dioda czerwona
  16. int greenRGBPin = 10;          // PIN10 - RGB - Dioda zielona
  17. int blueRGBPin = 11;           // PIN11 - RGB - Dioda niebieska
  18.  
  19. int yellowLedSpeed = 100;      // Prędkość początkowa procesu mrugania
  20. int greenLedPWM = 255;         // Wypełnienie początkowe PWM diody zielonej
  21.  
  22. byte greenLedStatus = 1;       // Status diody zielonej
  23. byte yellowLedStatus = 0;      // Status diody żóltej
  24.  
  25. byte actualMode = 0;           // Numer aktualnego progroamu
  26.  
  27. typedef void (* DigitFuncPtr) (); // Programy efektów
  28. DigitFuncPtr modes[4] = {wipe, rainbow, cycle, stars};
  29.  
  30. int step = 0;                  // Licznik kroków do efektów
  31. int randomR = 0;               // Losowa wartość R do efektu "wipe"
  32. int randomG = 0;               // Losowa wartość G do efektu "wipe"
  33. int randomB = 0;               // Losowa wartość B do efektu "wipe"
  34.  
  35. int dataPin = 6;               // Dane taśmy LED
  36. int clockPin = 7;              // Zegar taśmy LED
  37.  
  38. // Ustawiamy nasze "bouncery" z interwałem czasowym 40ms
  39. Bounce bouncerStartStop = Bounce(buttonStartStopPin, 40);
  40. Bounce bouncerSpeed = Bounce(buttonSpeedPin, 40);
  41. Bounce bouncerMode = Bounce(buttonModePin, 40);
  42.  
  43. // Konfigurujemy taśmę LED jako łańcuch 25 diod
  44. Adafruit_WS2801 strip = Adafruit_WS2801(25, dataPin, clockPin);
  45.  
  46. // Konfiguracja pinów i wątków
  47. void setup()
  48. {
  49.   randomSeed(analogRead(0));
  50.  
  51.   strip.begin();   // Inicjujemy taśmę LED
  52.   threads.begin(); // Rozpoczynamy pracę z wątkami
  53.  
  54.   // Przyciski
  55.   pinMode(buttonStartStopPin, INPUT);
  56.   pinMode(buttonSpeedPin, INPUT);
  57.   pinMode(buttonModePin, INPUT);
  58.  
  59.   // Diody
  60.   pinMode(redRGBPin, OUTPUT);
  61.   pinMode(greenRGBPin, OUTPUT);
  62.   pinMode(blueRGBPin, OUTPUT);
  63.   pinMode(yellowLedPin, OUTPUT);
  64.   pinMode(greenLedPin, OUTPUT);
  65.  
  66.   // Aktualizujemy zawartość taśmy LED (na start gasimy)
  67.   strip.show();
  68.  
  69.   // Dodajemy zadania uruchamiane od razu
  70.   threads.addTask(flashGreenLed, threads.convertMs(25), SCHEDULED_IMMEDIATESTART);
  71.   threads.addTask(onOffPush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
  72.   threads.addTask(speedPush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
  73.   threads.addTask(modePush, threads.convertMs(50), SCHEDULED_IMMEDIATESTART);
  74.  
  75.   // Dodajemy zadania do uruchomienia później  
  76.   threads.addTask(flashYellowLed, threads.convertMs(yellowLedSpeed), PAUSED);
  77. }
  78.  
  79. // Główna pętla programu - tym razem pusta
  80. void loop()
  81. {
  82. }
  83.  
  84. // Wątek obsługi przycisku zmiany prędkości
  85. void modePush()
  86. {
  87.   int i;
  88.  
  89.   // Aktualizujemy status przycisku
  90.   bouncerMode.update();
  91.  
  92.   // Reagujemy na zbocze narastające
  93.   if (bouncerMode.risingEdge())
  94.   {
  95.     // Ustawiamy tryb
  96.     actualMode++;
  97.     
  98.     if (actualMode > 3)
  99.     {
  100.        actualMode = 0;
  101.     }
  102.     
  103.     // Czyścimy taśmę LED
  104.     for (i = 0; i < strip.numPixels(); i++)
  105.     {
  106.       strip.setPixelColor(i, 0);
  107.     }
  108.     
  109.     // Wyświetlamy
  110.     strip.show();
  111.     step = 0;
  112.     
  113.     // Zapalamy niebieską didę
  114.     digitalWrite(blueRGBPin, HIGH);
  115.   }
  116. }
  117.  
  118. // Wątek obsługi przycisku zmiany prędkości
  119. void speedPush()
  120. {
  121.   // Aktualizujemy status przycisku
  122.   bouncerSpeed.update();  
  123.  
  124.   // Reagujemy na zbocze narastające
  125.   if (bouncerSpeed.risingEdge())
  126.   {
  127.     // Zmniejszamy czas oczekiwania na wątek
  128.     yellowLedSpeed -= 20;
  129.     
  130.     // Jeśli prędkość wynosi 0, ustawiamy na 100
  131.     if (yellowLedSpeed == 0)
  132.     {
  133.         yellowLedSpeed = 100;
  134.     }
  135.     
  136.     // Sygnalizujemy zieloną diodą RGB
  137.     digitalWrite(greenRGBPin, HIGH);
  138.     
  139.     // Zapamiętujemy status naszego wątka flashYellowLed  
  140.     byte taskStatus = threads.getTaskStatus(flashYellowLed);
  141.     
  142.     // Usuwamy wątek mrugania żółtą diodą
  143.     threads.removeTask(flashYellowLed);
  144.     
  145.     // Dodajemy nowy wątek ze starym statusem i nowym czasem
  146.     threads.addTask(flashYellowLed, threads.convertMs(yellowLedSpeed), taskStatus);
  147.  } else
  148.  {
  149.     // Gasimy diodę RGB, zieloną i niebieską
  150.     digitalWrite(greenRGBPin, LOW);
  151.     digitalWrite(blueRGBPin, LOW);
  152.  }  
  153. }
  154.  
  155. // Wątek obsługi przycisku wlącz/wyłącz
  156. void onOffPush()
  157. {
  158.   // Aktualizujemy status przycisku
  159.   bouncerStartStop.update();
  160.  
  161.   // Reagujemy na zbocze narastające
  162.   if (bouncerStartStop.risingEdge())
  163.   {
  164.     // Sygnalizujemy czerwoną diodą RGB
  165.     digitalWrite(redRGBPin, HIGH);
  166.     
  167.     // Pobieramy status naszego wątka flashYellowLed
  168.     byte taskStatus = threads.getTaskStatus(flashYellowLed);
  169.     
  170.     // Jeśli jest zatrzymany to wznawiamy
  171.     // Jeśli nie jest zatrzymany to zatrzymujemy i gasimy diodę żółtą
  172.     if (taskStatus == 0)
  173.     {
  174.       threads.restartTask(flashYellowLed);
  175.     } else
  176.     {
  177.       threads.pauseTask(flashYellowLed);
  178.       digitalWrite(yellowLedPin, 0);      
  179.     }
  180.   } else
  181.   {
  182.     // Gasimy diodę RGB, czerwoną
  183.     digitalWrite(redRGBPin, LOW);
  184.   }
  185. }
  186.  
  187. // Wątek mrugania PWM diodą zieloną
  188. void flashGreenLed()
  189. {
  190.   // Zmniejszamy wartość PWM dla diody zielonej
  191.   greenLedPWM -= 5;
  192.  
  193.   // Jeśli była zapalona to wysyłamy
  194.   if (greenLedStatus == 1)
  195.   {
  196.     analogWrite(greenLedPin, greenLedPWM);
  197.   }
  198.  
  199.   // Jeśli PWM wyniosło 0 to ustawiamy pełne PWM i zmieniamy status diody
  200.   if (greenLedPWM == 0)
  201.   {
  202.     greenLedPWM = 255;
  203.     greenLedStatus ^= 1;
  204.   }  
  205. }
  206.  
  207. // Efekt "wipe"
  208. void wipe()
  209. {
  210.   // Jeśli nie mamy wylosowanego koloru - losujemy
  211.   if ((randomR == 0) &amp;&amp; (randomG == 0) &amp;&amp; (randomB == 0))
  212.   {
  213.     randomR = random(255);
  214.     randomG = random(255);
  215.     randomB = random(255);
  216.   }
  217.  
  218.   strip.setPixelColor(step, randomR, randomG, randomB);
  219.  
  220.   step++;
  221.  
  222.   // Jeśli cała taśma świeci - losujemy nowy kolor
  223.   if (step == strip.numPixels())
  224.   {
  225.     step = 0;
  226.     randomR = 0;
  227.     randomG = 0;
  228.     randomB = 0;
  229.   }
  230.  
  231.   strip.show();
  232. }
  233.  
  234. // Efekt "stars"
  235. void stars()
  236. {
  237.   int i, h, n;
  238.   int leds = 0;
  239.  
  240.   // Badamy ile diod się świeci
  241.   for (i = 0; i < strip.numPixels(); i++)
  242.   {
  243.     uint32_t color = strip.getPixelColor(i);
  244.     
  245.     // Jeśli świeci
  246.     if (color != 0)
  247.     {
  248.       leds++;
  249.       
  250.       // Przygaszamy
  251.       h = (color &amp; 0x0000ff) - 1;
  252.       
  253.       if (h < 0)
  254.       {
  255.         leds--;
  256.         h = 0;
  257.       }
  258.       
  259.       strip.setPixelColor(i, h, h, h);
  260.     }
  261.   }
  262.  
  263.   // Maksymalnie może być 5 zapalonych   
  264.   for (i = leds; i < 5; i++)
  265.   {
  266.     h = random(128, 255);
  267.     n = random(0, strip.numPixels());
  268.     strip.setPixelColor(n, h, h, h);
  269.   }
  270.  
  271.   strip.show();
  272. }
  273.  
  274. // Efekt "rainbow"
  275. void rainbow()
  276. {
  277.   int i;
  278.  
  279.   for (i = 0; i < strip.numPixels(); i++)
  280.   {
  281.     strip.setPixelColor(i, Wheel((i + step) % 255));
  282.   }
  283.  
  284.   step++;
  285.  
  286.   if (step == 256)
  287.   {
  288.     step = 0;  
  289.   }
  290.  
  291.   strip.show();
  292. }
  293.  
  294. // Efekt "cycle"
  295. void cycle()
  296. {
  297.   int i;
  298.  
  299.   for (i = 0; i < strip.numPixels(); i++)
  300.   {
  301.     strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + step) % 256));
  302.   }  
  303.  
  304.   step++;
  305.  
  306.   if (step == 1280)
  307.   {
  308.     step = 0;
  309.   }
  310.     
  311.   strip.show();
  312. }
  313.  
  314. // Wątek mrugania diodą żółtą i wykonania kroku wybranego programu
  315. void flashYellowLed()
  316. {
  317.   // Negujemy status diody żółtej
  318.   yellowLedStatus ^= 1;
  319.  
  320.   // Wysyłamy
  321.   digitalWrite(yellowLedPin, yellowLedStatus);
  322.  
  323.   // Wykonuj wybrany program
  324.   modes[actualMode]();
  325. }
  326.  
  327. // Funkcja pomocnicza, tworząca kolor 32-bitowy ze składowych RGB
  328. uint32_t Color(byte r, byte g, byte b)
  329. {
  330.   uint32_t c;
  331.   c = r;
  332.   c <<= 8;
  333.   c |= g;
  334.   c <<= 8;
  335.   c |= b;
  336.   return c;
  337. }
  338.  
  339. // Funkcja pomocnicza, tworząca definicję okręgu koloru z przejściami R-G-B-R
  340. uint32_t Wheel(byte WheelPos)
  341. {
  342.   if (WheelPos < 85)
  343.   {
  344.     return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  345.   } else
  346.   if (WheelPos < 170)
  347.   {
  348.     WheelPos -= 85;
  349.     return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  350.   } else
  351.   {
  352.     WheelPos -= 170;
  353.     return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  354.   }
  355. }

Wszystkie materiały wykorzystane w tym wpisie, możecie znaleźć tutaj.

Reklama

Komentarze Komentarze
Avatar 1
Marcin Windows 7 / Safari 537.36
25 September 2014 - 22:06 Warszawa

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

Avatar 2
Korneliusz Linux x86_64 / Mozilla Firefox 33.0
05 November 2014 - 01:37 Bytom

Ustawił Pan odpowiednią ilość diod w linii 44?

Avatar 1
silverro Windows 7 / Mozilla Firefox 33.0
04 November 2014 - 10:53 Tarnobrzeg

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.

Avatar 2
Korneliusz Linux x86_64 / Mozilla Firefox 33.0
05 November 2014 - 01:35 Bytom

Właściwie to do D8 :) dzięki - poprawione

Avatar 1
silverro Windows 7 / Mozilla Firefox 33.0
05 November 2014 - 10:15 Tarnobrzeg

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??

Avatar 1
zoltar2012 Windows 7 / Mozilla Firefox 33.0
12 November 2014 - 22:52 Warszawa

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

Avatar 2
Korneliusz Linux x86_64 / Mozilla Firefox 33.0
14 November 2014 - 01:13 Bytom

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

Avatar 1
Damian Windows 7 / Safari 537.36
09 January 2015 - 18:28 Brak informacji

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ę.

Avatar 2
Korneliusz Linux x86_64 / Mozilla Firefox 34.0
10 January 2015 - 04:39 Bytom
Avatar 1
kiper86 Windows 7 / Safari 537.36
08 August 2015 - 17:00 Grabów

Witam czy jest opcja, żeby podłączyć do tego układu diody led rgb ws2811 lub ws2812 czy trzeba coś zmieniać?

Avatar 2
Korneliusz Linux Ubuntu / Mozilla Firefox 39.0
09 August 2015 - 13:39 Bytom

Zasadnicze pytanie - po co ?

Avatar 1
kiper86 Windows 7 / Safari 537.36
09 August 2015 - 22:44 Grabów

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 :)

Avatar 1
kiper86 Windows 7 / Safari 537.36
23 September 2015 - 23:33 Grabów

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 :)

Avatar 1
Artur Windows 7 / Safari 537.36
17 December 2017 - 23:45 Brak informacji

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ć ?