Simple scrolling LED Sign for NeoPixel (WS2811) or LPN8806

  • 2014/03/16 Update: The source code to this is now on GitHub. Check the Arduino link at the top of each page of this site.

Yesterday evening, I coded up a simple scrolling message sign that uses addressable LED strips like the Adafruit NeoPixels (WS2811) or LPN8806. The code I created is built for NeoPixels, since those were the ones I had access to, but it would be trivial to make it work with the Adafruit LPN8806 library. Future versions will make this simpler.

First, let’s talk about LED signs.

The BetaBrite is a commercially available scrolling message sign that’s been around for ages. I bought one at SAM’S CLUB back in the late 1990s. The BetaBrite that I have uses an 80×7 array of LEDs. This is what I will be trying to replicate.

If you shop around (ahem, e-Bay), you can find 1 meter long WS2811 LED strips with 60 RGB LEDs for around $8-$9. If you had seven of those, you could make a 60×7 LED sign. It wouldn’t be able to show as many characters at the same time as a BetaBrite does, but it would be good enough to experiment with. (There are strips with 144 pixels per meter, but they are very expensive. And, when you get past 500 or so LEDs, you start running out of memory on the Arduino. I plan to fix this with some updates to the LED library, eventually.)

Consider this wonderful drawing as I discuss a few possible ways to present a sign made out of LED strips:

LED Sign ideas

A. At the top is an example of one of these LED strips with LED number 0 to “n”. One end hooks to the Arduino and power, and the other end can be used to daisy chain multiple strips together. The first LED will be 0, and they count up to the end of the last strip. If you have three 60 LED strips, you have LEDs 0 to 179. The green arrow shows the direction of the data (the LEDs count up in that direction).

B. Next is an example of how you might arrange multiple strips so they could make up an LED sign. Each strip is shown running left-to-right, so at the end of the first strip the cables go all the way back to the left to connect to the start of the next strip. Wiring them like this makes it real easy to do things with. Notice that the green arrow runs left-to-right on each row.

C. However, it would be much much easier to just connect them like this, without all the extra wires running around. But, this causes every other row to run in the opposite direction (again, see the green arrows). This means the software has to be smart enough to know how to reverse drawing the pixels for every other row.

ALSO, based on where you decide to make LED 0, that changes everything. In these drawings, we are hooking the Arduino up at the top left. But, if it was easier to hook up at the bottom right, the entire numbering system would be backwards.

I decided to write a simple LED message program that could handle all of this. It’s not pretty, but it (maybe) works. I configure it with the number of LEDs in use, and how many are in each row, then I set where the start pixel is (TOPLEFT, TOPRIGHT, BOTTOMLEFT or BOTTOMRIGHT). I support running the rows STRAIGHT (A) or ZIGZAG (B). It can even do something fun…

D. This is the only thing I have actually done. I had two 1 meter strips, so I decided to spiral them with 20 LEDs in each spiral before the next row starts. These 120 LEDs can be split up in my program as six rows of 20 LEDs each, and then (with a small enough font), a message can rotate around it.

If you’d like to try out my code, I have posted it to GitHub:

I have only tested it in the D configuration, but I have done some debug prints that make me think it should be handling all the other variations. Until I have access to more LED strips, I won’t know for sure.

Anyone want to try it out and let me know how it works for you?

Poor documentation, and the code could be cleaned up and optimized quite a bit. Perhaps I will have that done when I reach version 1.0.

Here’s a video of my first working version:

37 thoughts on “Simple scrolling LED Sign for NeoPixel (WS2811) or LPN8806

        1. Allen Huffman Post author

          Sorry I missed this reply… Yes, my code should work with anything where you can say “set LED X to color Y”. That’s all it needs. The Adafruit libraries I use are the same calls for several types of LEDs they make the library for, so the changes are very minor to support them. If these LEDs use a different library, it will just require changing a few lines to call the library functions instead of the Adafruit functions. I’d be glad to help.

          1. Allen Huffman Post author

            If you aren’t using LEDs supported by the Neopixels library, you should be able to replace the light on/off code with whatever works with your panel, and configure it that way.

        1. Allen Huffman Post author

          Cool. As long as you have the library and it uses the same API as the WS2811, it should work as long as a few things are configured.v

          #define PIN 6

          That pin should match whatever the working demos use based on how you have it wired up.

          #define LEDBRIGHTNESS 2

          If this is too low, you might not see anything. I ran it very low because I was powering mine from the Arduino 5v directly so I was limited.

          The rest is making sure the API library calls match. Look for places that start with “strip.” in the code (only a few places). Most important is probably the thing that defines what it is using:

          Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDS, PIN, NEO_GRB + NEO_KHZ800);

          Those parameters at the end may have to be changed to match what you have, so compare that with the example code you have that works.


          strip.setPixelColor( xxxx , strip.Color(127,0,0) );



          Are those used in the examples you have that work?

          1. Allen Huffman Post author

            Ah… The pattern is probably a config thing, based on how many lights per row and such. The not moving could be because by default no ENTER is sent from the Arduino IDE when you type in the window so the input never gets processed. There is a toggle in the terminal/serial console that makes it send CR at the end. If you can’t find it, I will install it and take a quick look on the system I am using right now.

          2. Allen Huffman Post author

            Found it. Bottom right of the COMx window has “No line ending” in a pull down. Change that to “Carriage return” and that should get the input coming in. It will print out on the screen what is going on. You can also uncomment:

            //#define DEBUG

            And it will print the banner to the screen sideways as characters, representing which LEDs would be turned on.

    1. Allen Huffman Post author

      Comment out:

      Serial.print(“Enter message: “);
      msgLen = lineInput(message, MAXMSGLEN);

      And then add this (can be better, just for testing):

      strncpy(message, “This is your message”, MAXMSGLEN);
      msgLen = strlen(message);

      …that will make it just fire up and do that message over and over without stopping for input.

      1. herobattousai

        aparently i am just a hand full of issues today lol making things so easy for you arent I sorry if I am a bother.
        Arduino: 1.8.3 (Windows 10), Board: “Arduino/Genuino Uno”

        LEDSign:197: error: stray ‘\342’ in program

        strncpy(message, “This is your message�, MAXMSGLEN);


        LEDSign:197: error: stray ‘\200’ in program

        LEDSign:197: error: stray ‘\234’ in program

        LEDSign:197: error: stray ‘\342’ in program

        LEDSign:197: error: stray ‘\200’ in program

        LEDSign:197: error: stray ‘\235’ in program

        C:\Users\Herobattousai\Documents\Arduino\LEDSign-master\LEDSign\LEDSign.ino: In function ‘void loop()’:

        LEDSign:197: error: ‘This’ was not declared in this scope

        strncpy(message, “This is your message�, MAXMSGLEN);


        C:\Users\Herobattousai\Documents\Arduino\LEDSign-master\LEDSign\LineInput.ino: At global scope:
        LineInput:17: error: expected initializer before ‘byte’

        byte lineInput(char *buffer, size_t bufsize)

        exit status 1
        stray ‘\342’ in program

        This report would have more information with
        “Show verbose output during compilation”
        option enabled in File -> Preferences

        1. Allen Huffman Post author

          HTML copy/paste got that one. Let me see if this helps. Basically, instead of calling LineInput to read Serial input in to a buffer, we use string copy to copy a hard-coded string there, then set the length. The rest is the same.

          strncpy(message, “This is your message”, MAXMSGLEN);
          msgLen = strlen(message);

          1. herobattousai

            evidently it doesn’t like me here and you have been very helpful I thank you for the help It just doesnt want me to post the code here it gives me an error message…..

Leave a Reply