Assalamualaikum, jumpa lagi di triyonos.com dengan tutorial-tutorial implementasi pemrograman yang menarik untuk dipelajari.

Tutorial pertama triyonos.com di tahun 2024 ini kembali membahas lampu animasi addressable LED Strip WS2812.

Pada kesempatan ini saya akan membuat rangkaian elektrikal yang berfungsi untuk menjalankan 5 pattern animasi yang cukup populer yaitu Color Wipe, Fade, Rainbow Cycle, Scanner dan Theater Case secara bergantian dengan menggunakan 1 tombol.

adafruit ws2812 multitasking

Sebelum saya lanjutkan, tak lupa saya ucapkan terima kasih kepada semua pengunjung website kesayangan saya ini dan juga kepada semua pemirsa channel Kode Erik, khususnya bagi semua subscriber Kode Erik. Karena ternyata selama kesibukan ngoding saya sehari-hari yang membuat saya cukup lama tidak membuat content, secara perlahan namun pasti jumlah subscribernya bertambah. Hal inilah yang membuat saya terpanggil untuk segera membuat content menarik berikutnya.

Tutorial ini merupakan modifikasi dari tutorial seri ke-3 Adafruit Multi-tasking the Arduino yang saya dapat dari link https://cdn-learn.adafruit.com/downloads/pdf/multi-tasking-the-arduino-part-3.pdf. Secara ringkas tutorial tersebut membahas tentang penerapan arduino multitasking pada LED strip dengan menggunakan teknik Object Oriented Programming. Implementasi multitasking-nya dengan menjalankan pattern animasi Adafruit Neopixel pada 3 LED strip secara bersamaan dan ada interaksi penggunaan 2 push button untuk pergantian pattern animasi.

adafruit ws2812 multitasking

Di pembahasan kali ini, triyonos.com akan menyederhanakan rangkaian elektrikal pada tutorial Adafruit Multi-tasking the Arduino Part 3 sekaligus memodifikasi source code-nya, agar pergantian 5 pattern animasi tersebut di atas bisa dilakukan dengan cara menekan sebuah push button.

Komponen elektrikal yang diperlukan antara lain:

  • Arduino Uno
  • LED strip WS2812 5 Volt (16 Leds)
  • Breadboard
  • Push button
  • Kabel jumper
Rangkai kelima komponen-komponen di atas menjadi seperti gambar di bawah ini:
adafruit ws2812 multitasking



Modifikasi Source Code

  • Colokkan Arduino ke PC atau Laptop
    manage library
  • Install Adafruit Neopixel Library
    manage library
  • Copy Paste code .ino di bawah ini:
    #include <Adafruit_NeoPixel.h>
      
    // Pattern types supported:
    enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
    // Patern directions supported:
    enum direction { FORWARD, REVERSE };
    
    #define ON LOW  // active low
    #define OFF !ON
    
    const byte BUTTON_PIN = 2;
    int pb_sequence;
    int fade_cnt;
    
    boolean data = OFF;
    boolean data_last = data;
    
    unsigned long delay_press = 150; // in milliseconds
    unsigned long delay_press_last = 0;
    
    // NeoPattern Class - derived from the Adafruit_NeoPixel class
    class NeoPatterns : public Adafruit_NeoPixel
    {
      public:
      // Member Variables:
      pattern ActivePattern;  // which pattern is running
      direction Direction;    // direction to run the pattern
    
      unsigned long Interval;   // milliseconds between updates
      unsigned long lastUpdate; // last update of position
    
      uint32_t Color1, Color2;  // What colors are in use
      uint16_t TotalSteps;      // total number of steps in the pattern
      uint16_t Index;           // current step within the pattern
    
      void (*OnComplete)();     // Callback on completion of pattern
    
      // Constructor - calls base-class constructor to initialize strip
      NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()):Adafruit_NeoPixel(pixels, pin, type)
      {
        OnComplete = callback;
      }
    
      void Update() {
        if ((millis() - lastUpdate) > Interval)   // time to update
        {
          lastUpdate = millis();
          switch(ActivePattern) {
            case NONE:
              None();
              break;
            case RAINBOW_CYCLE:
              RainbowCycleUpdate();
              break;
            case THEATER_CHASE:
              TheaterChaseUpdate();
              break;
            case COLOR_WIPE:
              ColorWipeUpdate();
              break;
            case SCANNER:
              ScannerUpdate();
              break;
            case FADE:
              FadeUpdate();
              break;          
            default:
              break;
          }
        }
      }
    
      // Increment the Index and reset at the end
      void Increment() {
        if (Direction == FORWARD) {
          Index++;
          if (Index >= TotalSteps) {
            Index = 0;
            if (OnComplete != NULL) {
              OnComplete();   // call the completion callback
            }
          }
        } else {    // Direction == REVERSE
          --Index;
          if (Index <= 0) {
            Index = TotalSteps-1;
            if (OnComplete != NULL) {
              OnComplete();   // call the comlpetion callback
            }
          }
        }
      }
    
      // Reverse pattern direction
      void Reverse() {
        if (Direction == FORWARD) {
          Direction = REVERSE;
          Index = TotalSteps-1;
        } else {
          Direction = FORWARD;
          Index = 0;
        }
      }
    
    
      ///////// ANIMATION AREA ////////////////////////////////////////////
      void None() {
        ActivePattern = NONE;
        for (int i=0; i < numPixels(); i++) {
          setPixelColor(i, (0,0,0));
        }
    
        show();
        Increment();
      }
        
      void RainbowCycle(uint8_t interval, direction dir = FORWARD) {
        ActivePattern = RAINBOW_CYCLE;
        Interval = interval;
        TotalSteps = 255;
        Index = 0;
        Direction = dir;        
      }
    
      void RainbowCycleUpdate() {
        for (int i=0; i < numPixels(); i++) {
          setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index)& 255));
        }
    
        show();
        Increment();
      }
    
      void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD) {
        ActivePattern = THEATER_CHASE;
        Interval = interval;
        TotalSteps = numPixels();
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        Direction = dir;    
      }
    
      void TheaterChaseUpdate() {
        for (int i=0; i < numPixels(); i++) {
          if ((i + Index) % 3 == 0) {
            setPixelColor(i, Color1);
          } else {
            setPixelColor(i, Color2);
          }
        }
    
        show();
        Increment();
      }
    
      void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD) {
        ActivePattern = COLOR_WIPE;
        Interval = interval;
        TotalSteps = numPixels();
        Color1 = color;
        Index = 0;
        Direction = dir;
      }
    
      void ColorWipeUpdate() {
        setPixelColor(Index, Color1);
        show();
        Increment();
      }
    
      void Scanner(uint32_t color1, uint8_t interval, direction dir = FORWARD) {
        ActivePattern = SCANNER;
        Interval = interval;
        TotalSteps = (numPixels() - 1) * 2;
        Color1 = color1;
        Index = 0;
        Direction = dir;
      }
    
      void ScannerUpdate() { 
        for (int i = 0; i < numPixels(); i++) {
          if (i == Index) // Scan Pixel to the right
          {
            setPixelColor(i, Color1);
          }
          else if (i == TotalSteps - Index) // Scan Pixel to the left
          {
            setPixelColor(i, Color1);
          }
          else // Fading tail
          {
            setPixelColor(i, DimColor(getPixelColor(i)));
          }
        }
        show();
        Increment();
      }
    
      void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD) {
        ActivePattern = FADE;
        Interval = interval;
        TotalSteps = steps;
        Color1 = color1;
        Color2 = color2;    
        Index = 0;
        Direction = dir;
      }
    
      void FadeUpdate() {
        // Calculate linear interpolation between Color1 and Color2
        // Optimise order of operations to minimize truncation error
        uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
        uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
        uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
    
        ColorSet(Color(red, green, blue));
        show();
        Increment();
      }
      ///////// ////////////// ////////////////////////////////////////////
    
      // Calculate 50% dimmed version of a color (used by ScannerUpdate)  
      uint32_t DimColor(uint32_t color) {
        // Shift R, G and B components one bit to the right
        uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
        return dimColor;  
      }
    
      // Set all pixels to a color (synchronously)
      void ColorSet(uint32_t color) {
        for (int i = 0; i < numPixels(); i++)
        {
          setPixelColor(i, color);
        }
    
        show();
      }
    
      
    
      // Returns the Red component of a 32-bit color
      uint8_t Red(uint32_t color) {
        return (color >> 16)& 0xFF;
      }
    
      // Returns the Green component of a 32-bit color
      uint8_t Green(uint32_t color) {
        return (color >> 8)& 0xFF;
      }
    
      // Returns the Blue component of a 32-bit color
      uint8_t Blue(uint32_t color) {
        return color& 0xFF;    
      }
      
      // Input a value 0 to 255 to get a color value.
      // The colours are a transition r - g - b - back to r.  
      uint32_t Wheel(byte WheelPos) {
        WheelPos = 255 - WheelPos;
        if (WheelPos < 85) {
          return Color(255 - WheelPos * 3, 0, WheelPos * 3);
        } else if ( WheelPos < 170) {
          WheelPos -= 85;
          return Color(0, WheelPos * 3, 255 - WheelPos * 3);      
        } else {
          WheelPos -= 170;
          return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
        }
      }
    
    };
    
    void Ledstrip1Complete();
    
    NeoPatterns Ledstrip1(16, 4, NEO_GRB + NEO_KHZ800, &Ledstrip1Complete);
    
    void setup() {
      Serial.begin(115200);
    
      Ledstrip1.begin();
    
      pinMode(BUTTON_PIN, INPUT_PULLUP);
      
      pb_sequence = 0;
    }
    
    void loop() {
    
    }
    
    void Ledstrip1Complete() {
      Ledstrip1.Reverse();
    
      Serial.println(fade_cnt);
    
      if (pb_sequence == 5) {
        fade_cnt++;
    
        if (fade_cnt == 2) {
          fade_cnt = 0;
    
          Ledstrip1.Color1 = Ledstrip1.Wheel(random(255));
        }
      } else {
        fade_cnt = 1;
            
        Ledstrip1.Color1 = Ledstrip1.Wheel(random(255));
      }
    }
    
              
  • Modifikasi void loop()

Untuk lebih jelasnya silakan tonton video dari channel youtube Kode Erik di bawah ini. Kalau ada pertanyaan silakan komen di youtube dan jangan lupa subscribe: