Displays text on a WS2812 (NeoPixel) matrix display

Dependencies:   mbed miniFont wsDrive

Displays text on an array of WS2812 LEDs (NeoPixels)

Text is 5 rows tall so any grid larger than that can be used. The font supports A-Z (capitals only, any lowercase input will be capitalised) numbers and some basic punctuation. Letters are 5 LEDs wide, some numbers and punctuation are smaller but generally you need 6 pixels wide per character you wish to fit. If displaying a string a 1 row space is left between characters, for other spacings either edit the code or print one letter at a time and adjust the offset for the next letter.

LEDs must be connected in horizontal rows, top row first. Rows can be either direction or alternating directions.

NOTE: The testing on this has been fairly minimal. It works with my one physical configuration, I think the logic for other configurations is correct but haven't tested it. If you find a problem please let me know.

Revision:
1:2014f027ed6f
Parent:
0:bada179a0b70
--- a/main.cpp	Thu Nov 06 13:55:51 2014 +0000
+++ b/main.cpp	Thu Nov 06 17:32:12 2014 +0000
@@ -33,10 +33,12 @@
 
 // LED config options:
 
-//#define cascadeZigZag
+// uncomment if the direction of connections reverse each row.
+const bool cascadeZigZag = false;
+const bool topRowL2R = true;
 
-#define chainLen 35
-#define chainCount 5
+const uint16_t chainLen = 35;
+const uint16_t chainCount = 5;
 
 // IO setup - currently set for mbuino.
 
@@ -57,22 +59,41 @@
 pixelInfo *livePixels;
 pixelInfo *nextPixels;
 
-
+// could be optimised more but most of this is constants so the compiler should
+// do that for us. This is confusing enough as it is.
+inline bool reverseRow(uint16_t row)
+{
+    if (cascadeZigZag) {
+        if (topRowL2R) {         // left to right we reverse odd rows
+            if (row%2) // odd row
+                return true;
+            else
+                return false;
+        } else {                   // right to left reverse even rows.
+            if (row%2) // odd row
+                return false;
+            else
+                return true;
+        }
+    } else {
+        if (topRowL2R)         // left to right reverse none
+            return false;
+        else                   // right to left reverse all.
+            return true;
+    }
+}
 
 inline uint16_t xy2index(uint16_t x, uint16_t y)
 {
     if (x >= chainLen)
         x = 0;
     if (y >= chainCount)
-        y =0;
-#ifdef cascadeZigZag
-    if (y%2)
+        y = 0;
+
+    if (reverseRow(y))
         return (y+1)*chainLen - x - 1;
     else
         return y*chainLen + x;
-#else
-    return y*chainLen + x;
-#endif
 }
 
 
@@ -91,6 +112,24 @@
     }
 }
 
+void initGradient(pixelInfo *startColour, pixelInfo *endColour)
+{
+    uint16_t thisPixIndex;
+    float redDelta = ((float)(endColour->R) - (float)(startColour->R)) / chainLen;
+    float greenDelta = ((float)(endColour->G) - (float)(startColour->G)) / chainLen;
+    float blueDelta = ((float)(endColour->B) - (float)(startColour->B)) / chainLen;
+
+    for (int i = 0; i<(chainLen); i++) {
+        for (uint8_t row = 0; row < chainCount; row++) {
+
+            thisPixIndex = xy2index(i,row);
+
+            nextPixels[thisPixIndex].R = redDelta*i + startColour->R;
+            nextPixels[thisPixIndex].G = greenDelta*i + startColour->G;
+            nextPixels[thisPixIndex].B = blueDelta*i + startColour->B;
+        }
+    }
+}
 
 uint16_t initText(const char *text, pixelInfo colour, int16_t startPixel = 0, int16_t startRow = 0)
 {
@@ -152,29 +191,45 @@
 void initChain ()
 {
     pixelInfo textColour;
+    pixelInfo bgColour1;
+    pixelInfo bgColour2;
 
     // optionally use initColour to set a background colour
+    bgColour1.R = 0x00;
+    bgColour1.G = 0x08;
+    bgColour1.B = 0x00;
+    
+    bgColour2.R = 0x08;
+    bgColour2.G = 0x00;
+    bgColour2.B = 0x00;
+
+    initGradient(&bgColour1,&bgColour2);
 
     // set text colour
-    textColour.R = 0x30;
-    textColour.G = 0x30;
+    textColour.R = 0x40;
+    textColour.G = 0x00;
     textColour.B = 0x00;
 
     // add text keeping the index for the next character.
     uint16_t nextChar = initText("H", textColour);
 
-
     // change the colour
     textColour.R = 0x10;
     textColour.G = 0x10;
     textColour.B = 0x30;
     // add more text.
-    nextChar = initText("ell", textColour, nextChar);
+    nextChar = initText("el", textColour, nextChar);
 
+    // change the colour
+    textColour.R = 0x30;
+    textColour.G = 0x30;
+    textColour.B = 0x00;
+    // add more text.
+    nextChar = initText("l", textColour, nextChar);
 
     // one more colour
-    textColour.R = 0x40;
-    textColour.G = 0x00;
+    textColour.R = 0x00;
+    textColour.G = 0x40;
     textColour.B = 0x00;
     // and a final letter.
     initText("0", textColour, nextChar);
@@ -203,34 +258,40 @@
     for (uint16_t col = 0; col<chainLen; col++) {
         for (uint8_t row = 0; row < chainCount; row++) {
 
-#ifdef cascadeZigZag
-            if (row % 2) {
-                thisPixIndex = chainLen - col - 1 + row*chainLen;
-                redPixIndex = chainLen - redStep - 1 + row*chainLen;
-                greenPixIndex = chainLen - greenStep - 1 + row*chainLen;
-                bluePixIndex = chainLen - blueStep - 1 + row*chainLen;
-            } else
-#endif
-            {
-                thisPixIndex = col + row*chainLen;
-                redPixIndex = redStep + row*chainLen;
-                greenPixIndex = greenStep + row*chainLen;
-                bluePixIndex = blueStep + row*chainLen;
-            }
+            thisPixIndex = xy2index(col,row);
+
+            redPixIndex   = xy2index((col+redStep)%chainLen,  row);
+            bluePixIndex  = xy2index((col+blueStep)%chainLen, row);
+            greenPixIndex = xy2index((col+greenStep)%chainLen,row);
 
             nextPixels[thisPixIndex].R = livePixels[redPixIndex].R;
             nextPixels[thisPixIndex].G = livePixels[greenPixIndex].G;
             nextPixels[thisPixIndex].B = livePixels[bluePixIndex].B;
         }
-        redStep = (redStep+1) % chainLen;
-        greenStep = (greenStep+1) % chainLen;
-        blueStep = (blueStep+1) % chainLen;
     }
 }
 
+
 void rotateChain (int stepsLeft)
 {
-    rotateChain(stepsLeft,stepsLeft,stepsLeft);
+    while (stepsLeft < 0)
+        stepsLeft += chainLen;
+
+    uint16_t thisPixIndex;
+    uint16_t sourcePixIndex;
+
+    for (uint16_t col = 0; col<chainLen; col++) {
+        for (uint8_t row = 0; row < chainCount; row++) {
+
+            thisPixIndex = xy2index(col,row);
+
+            sourcePixIndex   = xy2index((col+stepsLeft)%chainLen,  row);
+
+            nextPixels[thisPixIndex].R = livePixels[sourcePixIndex].R;
+            nextPixels[thisPixIndex].G = livePixels[sourcePixIndex].G;
+            nextPixels[thisPixIndex].B = livePixels[sourcePixIndex].B;
+        }
+    }
 }