Murrayman
Published © GPL3+

Excel for WS2812 RGB LED Array Animations

An Excel Application generates text code for copy/paste into a purpose built sketch to create various forms of animation.

IntermediateFull instructions provided6,058
Excel for WS2812 RGB LED Array Animations

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
ws2812 8x8 RGB LED matrix
×1
Male/Female Jumper Wires
Male/Female Jumper Wires
My three are Black-Gnd, Red-5v and Green-Data
×3
9V battery (generic)
9V battery (generic)
×1
9V to Barrel Jack Connector
9V to Barrel Jack Connector
×1
Male-Header 5 Position- 1 Row- Long (0.1")
Male-Header 5 Position- 1 Row- Long (0.1")
Only three pins are required
×1

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Code

LED_Arduino

C/C++
This sketch forms the foundation of the project. On saving it should be set to Read-Only and further usage to be as 'Save As' for archiving to prevent overwriting and allow easy reedit.
//VARIABLES AND DEFINES HERE - NEEDED BY THE WS2812 DRIVER CODE
#define WS2812_pin 8 // only digital pin 8 works right now
#define numberOfLEDs 64// total number of RGB LEDs [256]
byte RGB[192];//take your number of LEDs and multiply by 3 [768]

// FUNCTIONS HERE
void RGB_update(int LED, byte RED, byte GREEN, byte BLUE);//function to drive LEDs

void mapLEDXY(int x, int y, byte RED, byte  GREEN, byte BLUE) {
  int RGBlocation = 0;

  //if (y % 2 == 0) { //even column [Uncomment]
    
 RGBlocation = x + y * 8; //[16]
 // } else { //odd column  [Uncomment]
    
   //RGBlocation = 7 - x + y * 8;  //[15] and [16]
 // }  [Uncomment]

  RGB[RGBlocation * 3] = BLUE;
  RGB[RGBlocation * 3 + 1] = RED;
  RGB[RGBlocation * 3 + 2] = GREEN;
}
void clearLEDs() {
  memset(RGB, 0, sizeof(RGB));
}


void setup() {
  pinMode(WS2812_pin, OUTPUT);
  clearLEDs();
  RGB_update(-1, 0, 0, 0);

}//setup0


void loop() {
//Paste mapLEDXY line(s) directly above the RGB_update below.

RGB_update(-1, 0, 0, 0);
  delay(1000);
  clearLEDs();
  RGB_update(-1, 0, 0, 0);
  delay(1000);

}//loop


//WS2812 Driver Function
void RGB_update(int LED, byte RED, byte GREEN, byte BLUE) {
  // LED is the LED number starting with 0
  // RED, GREEN, BLUE is the brightness 0..255 setpoint for that LED
  byte ExistingPort, WS2812pinHIGH;//local variables here to speed up pinWrites

  if (LED >= 0) { //map the REG GREEN BLUE Values into the RGB[] array
    RGB[LED * 3] = GREEN;
    RGB[LED * 3 + 1] = RED;
    RGB[LED * 3 + 2] = BLUE;
  }

  noInterrupts();//kill the interrupts while we send the bit stream out...
  ExistingPort = PORTB; // save the status of the entire PORT B - let's us write to the entire port without messing up the other pins on that port
  WS2812pinHIGH = PORTB | 1; //this gives us a byte we can use to set the whole PORTB with the WS2812 pin HIGH
  int bitStream = numberOfLEDs * 3;//total bytes in the LED string

  //This for loop runs through all of the bits (8 at a time) to set the WS2812 pin ON/OFF times
  for (int i = bitStream - 1; i >= 0; i--) {

    PORTB = WS2812pinHIGH;//bit 7  first, set the pin HIGH - it always goes high regardless of a 0/1

    //here's the tricky part, check if the bit in the byte is high/low then right that status to the pin
    // (RGB[i] & B10000000) will strip away the other bits in RGB[i], so here we'll be left with B10000000 or B00000000
    // then it's easy to check if the bit is high or low by AND'ing that with the bit mask ""&& B10000000)"" this gives 1 or 0
    // if it's a 1, we'll OR that with the Existing port, thus keeping the pin HIGH, if 0 the pin is written LOW
    PORTB = ((RGB[i] & B10000000) && B10000000) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//these are NOPS - these let us delay clock cycles for more precise timing
    PORTB = ExistingPort;//okay, here we know we have to be LOW regardless of the 0/1 bit state
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//minimum LOW time for pin regardless of 0/1 bit state

    // then do it again for the next bit and so on... see the last bit though for a slight change

    PORTB = WS2812pinHIGH;//bit 6
    PORTB = ((RGB[i] & B01000000) && B01000000) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 5
    PORTB = ((RGB[i] & B00100000) && B00100000) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 4
    PORTB = ((RGB[i] & B00010000) && B00010000) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 3
    PORTB = ((RGB[i] & B00001000) && B00001000) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 2
    PORTB = ((RGB[i] & B00000100) && B00000100) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 1
    PORTB = ((RGB[i] & B00000010) && B00000010) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");

    PORTB = WS2812pinHIGH;//bit 0
    __asm__("nop\n\t");//on this last bit, the check is much faster, so had to add a NOP here
    PORTB = ((RGB[i] & B00000001) && B00000001) | ExistingPort;
    __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
    PORTB = ExistingPort;//note there are no NOPs after writing the pin LOW, this is because the FOR Loop uses clock cycles that we can use instead of the NOPS
  }//for loop


  interrupts();//enable the interrupts

  // all done!
}//void RGB_update

Led_Utility.xlsm

This application generates the various text for copy/paste into the sketch.

Sketches.zip

These are some of or more sketches used during development. They are available as 'support'.

Credits

Murrayman
1 project • 0 followers

Comments