Close

Hrátky s NeoPixel RGB LED páskem

NeoPixel LED pásek

Arduino s NeoPixel jedou v barvách!

Ukažte se, co ve vás je, a vybarvěte svůj Arduino projekt použitím barevného LED pásku! V dnešním článku si ukážeme pár možností využití tohoto barevného LED hada.

Práce s NeoPixel LED pásky je jednoduchá a intuitivní díky dobře zpracovaným knihovnám a nenáročnému zapojení. Po přečtení tohoto článku vám asi bude doma všechno hrát barvami! 🙂

NeoPixel LED pásek s adresovatelnými RGB svítivými diodami je napájený přímo z Arduina pěti volty. Není tak potřeba napětí 12V, jako u běžných LED pásků. Hlavní výhodou řešení s NeoPixel je ale to, že můžete ovládat barvu a jas u každé LED zvlášť a přitom pro připojení potřebujete jen 3 vodiče! Dva vodiče pro napájení pásku a jeden pro data. Pásky můžete navíc spojovat za sebe (vyžaduje pájení) a vytvořit delšího svítícího hada.

Co je potřeba, aby to svítilo a blikalo?

ZDE ke stažení

Schéma zapojení

LED pásek připojte k Arduinu na +5V, GND a na Arduino pin č. 6. Můžete připojit také Bluetooth modul HC-06 nebo HC-05 a akumulátor pro mobilní použití – třeba při nošení pod tričkem :).

Pokud se vám nechce hledat, kde co připojit, můžete využít pro připojení RJ25 Adaptér a Arduino desku mCore. Adaptér zajistí pohodlné připojení pásku s možností připojení ještě dalšího pásku. Deska mCore zase umožní jednoduché připojení dalších modulů, například pohybového čidla PIR, snímače zvuku, světelného senzoru apod. Na desce mCore je navíc integrovaný měnič napětí, a tak váš Arduino projekt bude z akumulátoru fungovat i pokud klesne jeho napětí pod 3,5V. Napadá vás, co by se s tím vším dalo vytvořit za projekt? 😉

Schéma zapojení LED pásku s Arduinem
Schéma zapojení LED pásku s Arduinem

Vložení knihovny

Stáhněte si a nainstalujte knihovny (Neo_pixel a GFX). Otevřete Arduino IDE – záložka projekt, přidat zip knihovnu a hotovo.

Příklad ovládání z mobilu si ukážeme později. Teď tady mám něco opravdu speciálního!

NeoPixel pásek jako efektní doplněk obrazovky

Tento příklad využití LED pásku ukazuje potenciál propojení s PC a prostředím Processing3. LED pásek v tomto projektu tvoří efektní doplnění monitoru a osvětluje prostor za ním. Rozložení barev je vytvořeno podle toho, co je zrovna na monitoru. Cool!

S využitím prostředí Processing3 jsem vytvořil jednoduchý sketch, který si načte printscreen monitoru a uloží si ho jako image. Poté se používá jen šířka obrazovky a 200 pixelů výšky. Ty se rozdělí na šestnáct stejných okýnek a vypočítá se průměrná hodnota barvy jednoho okýnka v RGB. Ta se uloží do pole pixelcolor [číslo NeoPixel diody][barva 0=červená, 1=zelená, 2=modrá]. Celé pole pixelcolor[][] se odešle po sériové lince do Arduina. To jen načte pixelcolor[][] a pod for() cyklem doplní dle pořadí na výstup k pásku. Stáhni si prostředí Processing 3.

Rychlokurz Processing3 zde:

Processing3 stáhnout:

Nejprve si nainstalujte knihovny, pak nahrajte program do Arduina. Nastartujte Processing3, otevřete program „pasek_za_televizi“ a spusťte. Najděte v programu šestnáctý řádek:

String portName = Serial.list()[ číslo portu ];

V konzoli dole v okně vidíte názvy COM portů a jejich index. Bude vás zajímat index. To je to první číslo v hranaté závorce. Zkontrolujte v Arduino IDE, jaký COM port používá připojené Arduino s již nahraným kódem, u mě je to COM27. V konzoli processingu najdu COM27, podívám se na index, u mě je to [0] a do řádku dám nulu takhle

String portName = Serial.list()[0];

V Arduino IDE nesmíte mít otevřený Sériový monitor, pak Procesing háže chybu Serail port „COM27“  port busy!  Oba zdrojové kódy jsou odkomentovány, co která funkce dělá.

Kód pro Arduino s komentářem:

int inByte = 0;         // příchozí data
#include <Adafruit_NeoPixel.h> //knihovna pro Neopixel
#ifdef __AVR__         // ověření co provádí knihovna
#include <avr/power.h>
#endif
int pixelcolor[16][3]; // pole pro číslo LED a její barvu v RGB
int i,o,kontakt; // klopné proměnné
#define PIN            6 // DIN pin od pásku
#define NUMPIXELS      16 // počet LED na pásku
// (počet diod, DIN pin, typ barevného schématu + rychlost sběrnice)
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
void setup()
{
  // kontrola v knihovně
  #if defined (__AVR_ATtiny85__)
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  Serial.begin(9600); // start sériového portu s rychlostí 9600
   pixels.begin(); // inicializace pásku
  pixels.setBrightness(150); // nastavení svítivosti pásku 0 až 255 je max
  establishContact(); // makro pro navázání sériového spojení
}
void loop()
{
  if (Serial.available() > 45) { // pokud jsou přijatá data rovná počtu 45 hodnot
    if(Serial.read()==11) // pokud je první hodnota 11 začni ukládat do pole (kontrolní 11 co jsme si poslali z processingu)
    {
   pixelcolor[0][0]=Serial.read();
   pixelcolor[0][1]=Serial.read();
   pixelcolor[0][2]=Serial.read();
   pixelcolor[1][0]=Serial.read();
   pixelcolor[1][1]=Serial.read();
   pixelcolor[1][2]=Serial.read();
   pixelcolor[2][0]=Serial.read();
   pixelcolor[2][1]=Serial.read();
   pixelcolor[2][2]=Serial.read();
   pixelcolor[3][0]=Serial.read();
   pixelcolor[3][1]=Serial.read();
   pixelcolor[3][2]=Serial.read();
   pixelcolor[4][0]=Serial.read();
   pixelcolor[4][1]=Serial.read();
   pixelcolor[4][2]=Serial.read();
   pixelcolor[5][0]=Serial.read();
   pixelcolor[5][1]=Serial.read();
   pixelcolor[5][2]=Serial.read();
   pixelcolor[6][0]=Serial.read();
   pixelcolor[6][1]=Serial.read();
   pixelcolor[6][2]=Serial.read();
   pixelcolor[7][0]=Serial.read();
   pixelcolor[7][1]=Serial.read();
   pixelcolor[7][2]=Serial.read();
   pixelcolor[8][0]=Serial.read();
   pixelcolor[8][1]=Serial.read();
   pixelcolor[8][2]=Serial.read();
   pixelcolor[9][0]=Serial.read();
   pixelcolor[9][1]=Serial.read();
   pixelcolor[9][2]=Serial.read();
   pixelcolor[10][0]=Serial.read();
   pixelcolor[10][1]=Serial.read();
   pixelcolor[10][2]=Serial.read();
   pixelcolor[11][0]=Serial.read();
   pixelcolor[11][1]=Serial.read();
   pixelcolor[11][2]=Serial.read();
   pixelcolor[12][0]=Serial.read();
   pixelcolor[12][1]=Serial.read();
   pixelcolor[12][2]=Serial.read();
   pixelcolor[13][0]=Serial.read();
   pixelcolor[13][1]=Serial.read();
   pixelcolor[13][2]=Serial.read();
   pixelcolor[14][0]=Serial.read();
   pixelcolor[14][1]=Serial.read();
   pixelcolor[14][2]=Serial.read();
   }
    Serial.write( pixelcolor[0][0]);
    Serial.write( pixelcolor[0][1]);
    Serial.write( pixelcolor[0][2]);               
for(int e=0;e<16;e++) // for cyklus pro nastavení čísel diod a hodnotu barvy
    {// pixels.setPixelColor(číslo diody,červená,zelená,modrá)
    pixels.setPixelColor(e, pixels.Color(pixelcolor[e][0],pixelcolor[e][1],pixelcolor[e][2])); 
    }
    pixels.show(); // odeslání do pásku
  }
}
void establishContact() {   // makro pro navázání kontaktu
 while (Serial.available() <= 0) { //když nejsou přijatá žádná data
      Serial.write('A');   // pošli po sériové lince A
  }
}

Kód pro Processing3

   import java.awt.*;
    import processing.serial.*;   // nainportování knihoven
Serial port;  // iniciazizace proměné pro sériovou linku
PImage screenshot; // proměnná pro screenshot
int R, G,B; // proměnné pro ověření spojení ukládá se hodnota prvního okýnka
int[] serialInArray = new int[3];  // proměnná pro načtení COM portů
int r,g,b,index,pozicex=0;   // proměnné pro vypočet průměrné barvy okýnek
int pixelcolor[][]= new int[16][3]; // [počet diod][RGB] pro uložení RGB hodnot Arduinu
boolean firstContact = false; // pro ověrění spojení
int serialCount = 0; // pro ověrění spojení
void setup() {
    size(640,320); // nastaví okno programu na size(výška, šířka)
    printArray(Serial.list());  // zobrazí dostupné com porty
    String portName = Serial.list()[0];    // nastaví COM port, který se bude používat
    port = new Serial(this, portName, 9600); // nastavení rychlosti komunikace
}
void draw() {
    screenshot();           // makro pro vyfocení obrazovky
    if (screenshot != null) image(screenshot, 0, 0, width, height); //zobrazení vyfocené obrazovky v pozadí
loadPixels();  // načtení pixelů pozadí a jejich barvi
    for (int o=0;o<16;o++) // for cyklus pro vypočítání průměrné hodnoty 16ti okýnek to odpovídá počtu diod na pásku
    { 
    for(int i=0;i<height;i++)
    {
    for(int e=pozicex;e<pozicex+width/16;e++)
    {
    r+=(int(red(pixels[i*width+e]))); // uložení průměrné hodnoty barev v jedné diodě
    g+=(int(green(pixels[i*width+e])));
    b+=(int(blue(pixels[i*width+e])));
    index++;
     }
     pixelcolor[o][0]=r/index; // uložení barvy okýnka/diody pro odeslání po sériové lince
     pixelcolor[o][1]=g/index;
     pixelcolor[o][2]=b/index;
}
pozicex+=width/16;  // posunutí výpočtu o další okýnko
index=0;
r=0; // vynulování dočasné proměnné pro barvy
g=0;
b=0;
}
pozicex=0;
   for(int i=0;i<16;i++)     // zobrazení vypočítaných barev na pozadí programu 16 okýnek 50x50 pixelů
   {
   fill(  pixelcolor[i][0], pixelcolor[i][1], pixelcolor[i][2]);
   rect(pozicex,0,width/16,50);
   pozicex+=width/16;
   }
pozicex=0; // vynulování počátečního bodu
}
  void screenshot() {       // makro pro zachycení obrázku plochy
    try {
     screenshot = new PImage(new Robot().createScreenCapture(new Rectangle(0, 0, displayWidth,200)));
    } catch (AWTException e) { }
}
   void serialEvent(Serial myPort) {        // makro pro sériovou komunikaci
     int inByte = myPort.read();       // načtení kontaktního symbolu používáme 'A' 
      if (firstContact == false) 
      {
       if (inByte == 'A') { 
       println("kontakt");
       myPort.clear();          // vyčištění bufferu portu 
       firstContact = true;     // první kontakt proběhl
       myPort.write('A');       // dotaz na další
      } 
      } 
        else {             // Přidá nejnovější bajt ze sériového portu do pole:
         serialInArray[serialCount] = inByte;
         serialCount++;
         //když máme 3 bytes:
     if (serialCount > 2 ) {      // Arduino posílá nazpět hodnotu v RGB o prvním okýnku jako ověrění že se přenos povedl
      R = serialInArray[0];
      G = serialInArray[1];
      B = serialInArray[2];
      // vypíše hodnotu v RGB o prvním okýnku načtenou zpětně z Arduina (pouze ověření spojení);
      println(R + "   \t" +G+ "\t  " +B);
    myPort.write(11); // pošleme číslo 11 aby arduino vědělo, že má začít ukládat proměnné pro pásek
     for(int i=0;i<15;i++) // for cyklus odesílající 16 hodnot pole, které má 3 podpole R=0 G=1 B=2 
     {
      myPort.write(pixelcolor[i][0]); // pošli R
      myPort.write(pixelcolor[i][1]); // pošli G
      myPort.write(pixelcolor[i][2]); // pošli B
     }
      serialCount = 0; // vynulovaní poroměnné pro další příjem dat
     }
     }
}

RGB led ovládané ze smartphonu

A nyní si ukážeme slíbené ovládání LED pásku ze smartphonu. Teď už je potřeba připojit Bluetooth přijímač HC-06 nebo HC-05 dle výše uvedeného schématu. Stáhněte si aplikaci „Color Led Controller“, nainstalujte a spárujte se svým Bluetooth přijímačem. Zkopírujte si kód pod videem, vložte do Arduino IDE a nahrajte. Pozor na správné zapojení RX a TX pinů. Je to tak že TX z BT jde na RX Arduina a naopak RX z BT jde na TX Arduina. A tady je výsledek. Teď si můžete nastavit barvy podle svých představ.

Kód pro Arduino programování

#include <Adafruit_NeoPixel.h> // naimportování knihoven
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 6
#include <SoftwareSerial.h>            // softwareserial knihovna
                                        // (počet diod, DIN pin, pořadí barev, kmitočet)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
SoftwareSerial BT(2,3);  // port softwareserial na pinech (2RX 3TX)
String RGB = ""; //řetězec příjímající data z Bluetooth 
String RGB_Previous = "255.255.255)"; //řetězec předposledních dat z BT
String ON = "ON"; // zapni  
String OFF = "OFF"; //vypni
boolean RGB_Completed = false;// ověření přijímaných dat
#define PIN            6 // DIN pin
int svetlost=100;     // světlost pásku 0-255;
void setup() {
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
strip.begin(); // start pásku
strip.setBrightness(svetlost);
  BT.begin(9600);  // start portu pro BT na 9600
  RGB.reserve(30);
 Serial.begin(9600); // start sériového portu na 9600
}
void loop() {
  while(BT.available()){   //pokud je BT přijal data
    char ReadChar = (char)BT.read();   // uloží se do ReadChar
    if(ReadChar == ')'){ // když řetězec obsahuje ")"
      RGB_Completed = true; // byl přenos dat uspěšný
    }else{                  // pokud ne načte se zpět poslední hodnota  
       RGB += ReadChar;
    }
  }
  if(RGB_Completed){              //vypíše hodnotu RGB
      Serial.print("RGB:");
      Serial.print(RGB);
      Serial.print("     PreRGB:");
      Serial.println(RGB_Previous);
  if(RGB==ON){                          // zapni
          digitalWrite(13,HIGH); 
          RGB = RGB_Previous; 
          Light_RGB_LED();          
      }else if(RGB==OFF){                 //vypni
          digitalWrite(13,LOW);
          RGB = "0.0.0)"; 
          Light_RGB_LED();
      }else{
          Light_RGB_LED();   
          RGB_Previous = RGB;     
      }
      RGB = "";           // reset proměnné pro příjem dat
      RGB_Completed = false;    
  }     
  }  //konec loopu
void Light_RGB_LED(){         // dekódování přijatých dat
 if(RGB.length()>4 && RGB.length()<11) // omezení čtení v rozsahu min a max délky správně načtených dat
 { 
  RGB_Previous=RGB; 
  int SP1 = RGB.indexOf('.');          //uložení délky indexu pro hodnotu
  int SP2 = RGB.indexOf('.', SP1+1);               //(SP1).(SP2).(SP3)  
  int SP3 = RGB.indexOf('.', SP2+1);   // když je RGB 255.  45 . 3  tak SP1=3 SP2=2 a SP3=1
  String R = RGB.substring(0, SP1);          // převedení na jednotlivé hodnoty RGB
  String G = RGB.substring(SP1+1, SP2);      
  String B = RGB.substring(SP2+1, SP3);
  Serial.print("R=");                // vypíše samostatné hodnoty v  RGB
  Serial.println( constrain(R.toInt(),0,255));
  Serial.print("G=");
  Serial.println(constrain(G.toInt(),0,255));
  Serial.print("B=");
  Serial.println( constrain(B.toInt(),0,255));
 for(int i=0;i<16;i++)              // for cyklus pro poslání dat do pásku 
 {                                    // máme 16 diod takže i=16
strip.setPixelColor(i,R.toInt(),G.toInt(),B.toInt());
 }
strip.show();// inicializace pásku po které začne svítit
 }
}

A to je z dnešního hraní s NeoPixel LED pásky vše. Doufám, že se vám podařilo uvedené příklady zrealizovat a už blikáte. Pokud ne, pište do komentářů a podíváme se na to.

Zbyněk Daněk

Napsat komentář