راه اندازی ماژول WS2812 – LED RGB با آردوینو
اطلاعاتی در مورد نحوه برنامه ریزی و سیگنال دهی به WS2812
در این بخش به بررسی روش سیگنال دهی این آی سی خواهیم پرداخت. در ابتدا نیز لازم به ذکر است که با توجه به اینکه برای استفاده از این آی سی از کتابخانه های آماده بهره خواهیم گرفت لذا درک عمیق این مباحث ضروری نیست و صرفا جهت آشنایی با این ساختار مطرح می شود.
همان گونه که گفته شد برای اتصال این آی سی ها و تشکیل یک زنجیره باید دیتا از پایه ورودی اولین آی سی وارد و از پایه خروجی اولین آی سی به بعدی تا انتها اتصال یابد. به تصویر زیر توجه نمائید:
برای کنترل هر آی سی از 24 بیت استفاده می شود که 8 بیت برای هر رنگ قرمز، سبز و آبی استفاده می شود که در واقع امکان 256 حالت نوری(Grayscale) را ممکن می سازد. تصویر زیر ترتیب ارسال این سیگنال را نمایش می دهد:
این سیگنال ها باید به صورت پشت سر هم و به صورت سریال ارسال شود یعنی با فرض سه پیکسل به صورت پشت سر هم، یک بسته 24 بیتی به ازای هر پیکسل ارسال می شود. هر پیکسل اولین 24 بیت دریافتی را به خود اختصاص داده و باقی بیت های دریافتی را به پیکسل های بعدی منتقل می نماید. این روند تا آخرین پیکسل ادامه می یابد. با یک سیگنال ریست نیز کل آی سی های زنجیره خاموش می شود. در تصویر زیر شیوه اجرایی این فرآیند مشاهده می شود:
با توجه به اینکه برای ارتباط و انتقال اطلاعات از یک خط دیتا(سریال) استفاده شده است لذا از روش خاصی برای تعیین صفر و یک منطقی و همچنین سیگنال ریست استفاده شده است. در این حالت برای نمایش صفر و یک منطقی از زمان بندی های خاص بهره گرفته شده است. یعنی با ست و ریست شدن خط دیتا به زمان معین سیگنال معرف صفر، یک و ریست خواهد بود.
همان گونه که قبلا نیز گفته شد این آی سی دارای دو مد کاری 400 کیلو هرتز(Low Speed) و 800 کیلوهرتز (High Speed) می باشد. با توجه به اینکه زمان بندی های سیگنال با توجه به مد کاری تغییر می کند و همچنین سرعت بالاتر مد پر سرعت و متداول تر بودن این مد کاری، زمان بندی ها بر اساس آن قرار داده می شود: (لازم به ذکر است زمان بندی های مد 400 کیلو دو برابر جدول زیر است)
روند ارسال سیگنال بدین صورت است که در ابتدا یک سیگنال ریست از طریق خط دیتا ارسال می شود. در این حالت حافظه کل چیپ ها پاک (Clear) می شود. بعد از این حالت سیگنال های ارتباطی با زمان بندی ها مناسب ارسال می گردد برای مثال با وجود دو آی سی پشت سر هم و به جهت رنگ سفید و سبز باید ابتدا 0xFFF (رنگ سفید) و سپس 0x0F0 (رنگ سبز خالص) به صورت پشت هم ارسال گردد.
ابزار لازم برای راه اندازی ماژول WS2812 – LED RGB با آردوینو
- برد آردوینو UNO
- ماژول WS2812 – LED RGB
ترتیب پایه های ماژولWS2812 – LED RGB
نحوه اتصال ماژول WS2812 – LED RGB به آردوینو
نمونه برنامه لازم برای راه اندازی ماژول WS2812 – LED RGB با آردوینو
#include <Adafruit_NeoPixel.h> #include "WS2812_Definitions.h" #define PIN 4 #define LED_COUNT 5 // Create an instance of the Adafruit_NeoPixel class called "leds". // That'll be what we refer to from here on... Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_COUNT, PIN, NEO_GRB + NEO_KHZ800); void setup() { leds.begin(); // Call this to start up the LED strip. clearLEDs(); // This function, defined below, turns all LEDs off... leds.show(); // ...but the LEDs don't actually update until you call this. } void loop() { // Ride the Rainbow Road for (int i=0; i<LED_COUNT*10; i++) { rainbow(i); delay(100); // Delay between rainbow slides } // Indigo cylon // Do a cylon (larson scanner) cycle 10 times for (int i=0; i<10; i++) { // cylon function: first param is color, second is time (in ms) between cycles cylon(INDIGO, 500); // Indigo cylon eye! } // A light shower of spring green rain // This will run the cascade from top->bottom 20 times for (int i=0; i<20; i++) { // First parameter is the color, second is direction, third is ms between falls cascade(MEDIUMSPRINGGREEN, TOP_DOWN, 100); } } // Implements a little larson "cylon" sanner. // This'll run one full cycle, down one way and back the other void cylon(unsigned long color, byte wait) { // weight determines how much lighter the outer "eye" colors are const byte weight = 4; // It'll be easier to decrement each of these colors individually // so we'll split them out of the 24-bit color value byte red = (color & 0xFF0000) >> 16; byte green = (color & 0x00FF00) >> 8; byte blue = (color & 0x0000FF); // Start at closest LED, and move to the outside for (int i=0; i<=LED_COUNT-1; i++) { clearLEDs(); leds.setPixelColor(i, red, green, blue); // Set the bright middle eye // Now set two eyes to each side to get progressively dimmer for (int j=1; j<3; j++) { if (i-j >= 0) leds.setPixelColor(i-j, red/(weight*j), green/(weight*j), blue/(weight*j)); if (i-j <= LED_COUNT) leds.setPixelColor(i+j, red/(weight*j), green/(weight*j), blue/(weight*j)); } leds.show(); // Turn the LEDs on delay(wait); // Delay for visibility } // Now we go back to where we came. Do the same thing. for (int i=LED_COUNT-2; i>=1; i--) { clearLEDs(); leds.setPixelColor(i, red, green, blue); for (int j=1; j<3; j++) { if (i-j >= 0) leds.setPixelColor(i-j, red/(weight*j), green/(weight*j), blue/(weight*j)); if (i-j <= LED_COUNT) leds.setPixelColor(i+j, red/(weight*j), green/(weight*j), blue/(weight*j)); } leds.show(); delay(wait); } } // Cascades a single direction. One time. void cascade(unsigned long color, byte direction, byte wait) { if (direction == TOP_DOWN) { for (int i=0; i<LED_COUNT; i++) { clearLEDs(); // Turn off all LEDs leds.setPixelColor(i, color); // Set just this one leds.show(); delay(wait); } } else { for (int i=LED_COUNT-1; i>=0; i--) { clearLEDs(); leds.setPixelColor(i, color); leds.show(); delay(wait); } } } // Sets all LEDs to off, but DOES NOT update the display; // call leds.show() to actually turn them off after this. void clearLEDs() { for (int i=0; i<LED_COUNT; i++) { leds.setPixelColor(i, 0); } } // Prints a rainbow on the ENTIRE LED strip. // The rainbow begins at a specified position. // ROY G BIV! void rainbow(byte startPosition) { // Need to scale our rainbow. We want a variety of colors, even if there // are just 10 or so pixels. int rainbowScale = 192 / LED_COUNT; // Next we setup each pixel with the right color for (int i=0; i<LED_COUNT; i++) { // There are 192 total colors we can get out of the rainbowOrder function. // It'll return a color between red->orange->green->...->violet for 0-191. leds.setPixelColor(i, rainbowOrder((rainbowScale * (i + startPosition)) % 192)); } // Finally, actually turn the LEDs on: leds.show(); } // Input a value 0 to 191 to get a color value. // The colors are a transition red->yellow->green->aqua->blue->fuchsia->red... // Adapted from Wheel function in the Adafruit_NeoPixel library example sketch uint32_t rainbowOrder(byte position) { // 6 total zones of color change: if (position < 31) // Red -> Yellow (Red = FF, blue = 0, green goes 00-FF) { return leds.Color(0xFF, position * 8, 0); } else if (position < 63) // Yellow -> Green (Green = FF, blue = 0, red goes FF->00) { position -= 31; return leds.Color(0xFF - position * 8, 0xFF, 0); } else if (position < 95) // Green->Aqua (Green = FF, red = 0, blue goes 00->FF) { position -= 63; return leds.Color(0, 0xFF, position * 8); } else if (position < 127) // Aqua->Blue (Blue = FF, red = 0, green goes FF->00) { position -= 95; return leds.Color(0, 0xFF - position * 8, 0xFF); } else if (position < 159) // Blue->Fuchsia (Blue = FF, green = 0, red goes 00->FF) { position -= 127; return leds.Color(position * 8, 0, 0xFF); } else //160 <position< 191 Fuchsia->Red (Red = FF, green = 0, blue goes FF->00) { position -= 159; return leds.Color(0xFF, 0x00, 0xFF - position * 8); } }
منابع لازم برای راه اندازی ماژول
- Breakout Board Schematic
- Breakout Board Eagle Files
- Breakout Board github Repository
- WS2812 Datasheet
- Example Code and NeoPixel Library
- Adafruit NeoPixel Library github