Build a giant live scrolling tickertape display from WS2812B Neopixels and an Arduino Uno

Display live scrolling sports scores, crypto prices, or hot tweets on the side of your favorite newspaper building. All you need are some cheap pixel strips, an Uno, and a 5 volt power supply (I used a USB charger with the connector cut off).

Demo video and easy instructions below!


What started out as a proof of concept for parallel processing on a microcontroller has become a 20-foot tall Angry Birds game, Star Wars Mouse Droid, EDC Music Festival Message Flag, a (student-built!) School Info Center, and so many more!

This ultimate update adds the #1 most requested feature – the ability to update the display in real time with live data over either USB or Bluetooth. That’s right – you can now have a Python program running on a Raspberry Pi that pulls bitcoin prices from the internet and displays them on the sign in real time. Happy now?

The code has also been completely reworked to be as simple and reliable as possible. Almost anyone should be able to understand and modify it.

Perfunctory Video


  • Uses cheap and easy to buy pixel strips, and a ubiquitous Arduino Uno.
  • Display can be very long (100’s of feet) because it generates the pixel signals on the fly rather than using a frame buffer.
  • Easily fed with live data using the Arduino’s built-in serial port which shows up on whatever computer it is plugged into.
  • Can also be fed by any bluetooth device using a cheap and easy to buy HC-05 adapter (or anything else that has a 5 volt serial TX pin).
  • Includes 6 premade fonts and it is easy to edit those or make your own.
  • Easily editable code.

Hardware Setup Looks Like This

You do not need to use a breadboard to connect the ground wires – you can just twist them together.

You can connect the power supply to the same end of the strips that the Arduino is connected to if that is easier. In this case, the ground from the power supply is connected to both the Arduino and the strips.

Code drop

Full code here…


1. Get 7 strips of pixels.

  • These can be Neopixels, WS2812B, WS2813, or SK6812. (All these use compatible protocol and timing)
  • You can get them from Amazon or Aliexpress or Adafruit or anyplace else.
  • I used the 60 LED per meter kind because they are cheap and text looks nice, but other kinds can be nice too depending on how you lay it out.
  • Strips can be as long as you want, basically limited by your ability to power them.
  • Code is written for RGB style pixels, but you can make it use RGBW by uncommenting a single line.
  • You can use either 5-volt or 12-volt pixel strings, just make sure your power supply matches (below).
  • You can use fewer strips if you want, but then you will have to edit the font to make it shorter.

2. Connect all of the “ground” pins from the strips to one or more of the ground pins on the Arduino.

  • It doesn’t matter which ground pin on the Arduino you use (there are 3).
  • If your strips have loose power wires coming out the end, you can twist all the black ones together and then connect those into the ground pin. Or you can use a grounding strip.
  • I used breadboard jumper wires because then I could plug them into a breadboard strip which was easy.

3. Connect each one of the “data in” pins from the strips to the corresponding digital pin on the Arduino, starting at Arduino pin 1 and going to Arduino pin 7.

  • The strip connected to Arduino pin 1 will be at the bottom of your display. The text flows away from the Arduino.
  • Again, I used some breadboard jumper wire, which is handy because you can stick it into the plugs from the strips and then stick it into the socket on the Arduino.
  • You can ignore the power pin on this end of the strip, and you can also ignore the “BI” pins if your strips have them like the WS2813 does).

4. Connect the strips to a DC power source.

  • Most strips use 5 volts, but some use 12 volts, you should know which kind you bought. They also will usually have either “5V” or “12V” printed on the strip. If you really have no idea, try one strip with a 5 volt supply first and see if it works.
  • Connect the power supply “positive” or “+” side to the red wires from the strips and the “negative” or “-” side to the black wires.
  • Do not connect the power wires backwards! This is the one way you can really break stuff and make smoke!
  • You can twist all the wires together, or use terminal bars to make connections if you are fancy.
  • You can use any power source that gives you enough amps to keep the strips lit up.
  • Strips use more power when the pixels are on brightly. If you only use less bright colors then you can get by with much smaller power supplies.
  • A 2 amp USB charger can power seven 1 meter long strips at the default color brightness.
  • If you are going to use really long strips, you can get a big power supply like this which can power a couple of thousand pixels, or you can use lots of smaller supplies connected at different points along the length of the strips (see video here). There is plenty of info on the internet about powering long strips of pixels!
  • For short strips running with very dim colors, you can even get away with powering the strips from the Arduino’s 5V pin, but people will get mad at you for doing this.
  • Lots more info on powering pixels over at AdaFruit.

5. Load up the SimpleTickertape.ino sketch into your Arduino.

  • You can do this by plugging the Arduino into a computer, running the Arduino IDE, and then copying/pasting the code from here, and clicking the run arrow () in the IDE. (It might be easier to copy the code if you click on the “Raw” button on the webpage.)
  • You should see a sample message scroll across your LED strips!
  • To maximize your chances of success, the program only drives the first 60 pixels and uses a not-so-bright red color. We can change these later once everything is working.
  • If you are using RGBW strips then you must make the edit below for them to work right.

6. Try typing your own text directly onto the tickertape from your computer!

  1. Pick “Tools->Serial Monitor” from the Arduino IDE top menus.
  2. Pick “No line ending” and “9600 baud” from the pickers on the bottom of the serial monitor window.
  3. Type “Hello me!” in the input bar at the top of the window and press enter. You should see your message scroll onto the tickertape!

7. Edit the code for your own use.

  • Update the PIXEL_COUNT define at the top of the program to match how long each of your strings are.
  • Update the FRAME_DELAY define if you want to scroll faster (lower number) or slower (bigger number).
  • Update the COLOR_X defines to make a color you like. R,G, and B stand for red, green, and blue and each of these numbers can be 0-255. The bigger the number, the brighter the color. Start with low numbers since these pixels can be bright and setting bright colors can overtax your power supplies.
  • If you are using RGBW strips (these have an extra white LED in each pixel besides the red, green, and blue ones) then uncomment the COLOR_W line by deleting the two back slashes in front of it.
  • You can also change the font by turning 0‘s into 1‘s and vice versa. You can also make the font wider or skinnier if you want by changing the value of FONT_WIDTH and adding or removing lines from each character to match the new width. LMK if you make a cool new font or need help converting an existing font to this format (there are some hacked-up programs to help here).
  • Change the code to do whatever you want! Except for the part that actually sends out the pixels (which has to be really fast), the program should be pretty easy to understand and modify.

Bluetooth control

You can control your new ticker from your phone over bluetooth! You will need a bluetooth adapter like the HC-05, which you can get from Amazon for less than $10.

UPDATE: HC-05 will not work with iPhones, you need something like AT-09 which is about $5 on Amazon.

Connect it to the Arduino like this…

Then pair the HC-05 to your phone by pressing the button on it and then doing whatever you need to do on your phone to pair (lots of better instructions on how to do this on google).

Next you can test by getting a Bluetooth terminal program for your phone. I used Serial Bluetooth Terminal for Android, but you can use any program that sends serial data out the Bluetooth connection.

Sending SMS messages to the sign

To send incoming SMS messages to the sign from my Android, I used Tasker and Tasker Bluetooth Plugin which works amazingly well and can let you send pretty much anything you can imagine to the sign based off of apps running on the phone.

Write your own no-code app to control the sign

You can also very easily write your own phone apps to drive this sign with MIT’s App Inventor. Use the SendText action of the “Bluetooth Client” component to send whatever text you want to the sign. It work great and it is amazing how easy it is to make an app like this!

Driving the display from a computer

You can plug the Arduino into the USB port of almost any computer (Windows, OSX, Raspberry Pi) and it will appear as a serial port on that computer. Any text you send to that serial port will scroll onto the display.

Live typing

To make the display work like a giant typewriter, run an serial terminal program, set it to the correct serial port, and then set the speed to 9600 baud. Now start typing and it will instantly scroll onto the display! I used the free Kitty terminal program in the video.

Sending messages from a batch file/shell script/python program

You can easily send messages directly to the display from any batch file or shell script by just sending the text directly to the serial port that the UNO creates when it is plugged into the computer. You can then have the computer get data from websites and then put it on the screen, has it post messages whenever anything triggers an event on the computer.

Bitcoin Block Clock

To create the Bitcoin Block Clock in the video, I used the fact that the bitcoin-core program can be configured to call a batch file whenever something interesting happens. I had it call the following batch file to look up the height of the new block and send it to the display via the serial port…

echo bitcoin >com4
choice /D Y /T 1
echo block >com4
choice /D Y /T 2
echo height >com4
choice /D Y /T 2
D:DocumentsProgramsbitcoinbitcoin-0.20.1binbitcoin-cli.exe -datadir="D:DocumentsProgramsbitcoindata" getblockcount >com4
choice /D Y /T 3

This is for Windows, but you you are using Linux then you are enough of a geek to be able to figure out how to do the same thing with s BASH script on your own. Note that at some point after each boot you need to set the serial port baud rate suing something like mode com4:9600,n,8,1 (or stty -F /dev/ttyUSB0 9600 in Linux).

Note that you could do the same thing with walletnotify to have a message scroll anytime someone sends you some of that sweeet juicy crypto.

The tricky parts

The hardest part about this program is keeping up with the pixels. For old-skool WS2812B pixels you only have about 5 microseconds (us) between bits. If you wait any longer than that, the pixels will reset. It is hard enough to compute a new column of pixels every 5us, be we also have to be constantly checking and reading in any new data from the serial port. If we go too long without checking, some data will get lost and the display will get messed up. So how do we do all this?

  1. A tiny bit of assembly code. This code actually sends the most timing sensitive parts of the WS2812B signal, and writing in assembly makes sure we can control exactly how long everything will take. Don’t worry, this code is *very* simple with only two instructions. The out instruction sends a byte out to the pins and the nop instruction just pauses for 62.5 nanoseconds. That’s it! Check it out here.
  2. All interrupts off, all of the time. An interrupt literally interrupts the program and then goes and does something else for a bit and then goes back to what it was doing. This is normally very handy, but it is no good when you are trying to do timing sensitive stuff since when get interrupted, the code that was running gets stopped while the interrupt code runs. So for reliability and simplicity, here we just turn them off always and then never have to worry about them. The command that does ths is called cli() which stands for “clear interrupt flag”. The two main things that normally generate interrupts are the timer and the serial port. We are careful to never use the timer (stuff like millis()) because it will never update without interrupts. To get serial to work without interrupts, we need to use…
  3. Polling mode serial receive. Polling means we keep obsessively checking to the if any new serial bytes have arrived. Normally a new byte would trigger an interrupt to read the new byte, but since we have no interrupts it is all on us to check. This seems wasteful and it does use up many more cycles than doing nothing until you get an interrupt, but with polling we get to pick *when* we check (and we pick moments when we have some free time) whereas with an interrupt it can happen almost any time. There is also additional overhead to calling an interrupt since it must remember what it was doing when the interrupt happened and then return back everything to the way it was afterwards.


Q: How long can I make my ticker tape?!
A: The technical limit with the current 6 column wide font is [1000 characters in buffer] * [6 pixels per char] = 6,000 pixels. That’s 325 feet long with standard strips. In practice you will not want to make one this long because it will get too slow. It takes about 36 microseconds to transmit 1 pixel, so if you want to update at 20 steps per second (a brisk reading pace), that limits you to a maximum length of about 1,300 pixels, which is still about 75 feet long with standard 60 pixel/meter strips! If you need to go longer, it probably makes sense to put one or more additional Arduinos in the middle to speed things up. If you have a good reason to make such a humongous ticker then I’ll help you.

Q: Can I send text to the ticker from my phone over bluetooth!?
A: For sure! I picked 9600 baud as the default serial port speed because this is what the cheap (<$5 on Amazon!) and plentiful HC-05 bluetooth adapters run at out of the box. To use one, connect the HC-05 power pins to the 5V and GND pins on the Arduino and then connect the TX pin on the HC-05 to pin 0 on the Arduino. Next push the button to pair with your phone. Finally get a bluetooth serial app and start typing and it should end up on the tickertape!

Q: Can I send live info from the internet to my tickertape?
A: For sure! That’s the whole point! You just need to get the data you want and then send it as text out the serial port. With the Arduino attached to my windows computer via USB, I can make a batch file that send the text to the correct COM port (COM3 on my computer but you can check which on yours in the Arduino IDE) and prints it using a command like echo "This is the remix." >COM3. You can do similar things on a raspberry pi or OSX, check out the .

Q: How can I use this code on my [ANYTHING BUT AN ARDUINO UNO]?
A: Really the whole point of this project is that it uses an Uno. You can get it to run on some very closely related AVR-based Arduinos like the Micro and the Nano, but after that you should probably give up and find something meant for the board you have.

Q: Why is this better than just using a TEENSY?
A: The TEENSY is amazingly good at driving lots of pixels and if you have one and you know how to use it then you should use it! Otherwise, the UNO is nice for many people because (1) it is cheap and widely available around the world, (2) millions of people have experience with it, (3) it directly generates the 5V signals that all these pixels need so no buffers or converters are ever needed.

Q: Why does the bottom row of pixels go nuts when I download the sketch?
A: The Arduino digital pin 1 that we use to drive the bottom row of pixels also happens to be the UNO’s serial transmit pin. This is normally not a problem since our sketch never transmits anything, but when we download a new sketch the Arduino and the IDE do talk to each other over the serial port and this data is what makes the LEDs go nuts.

Q: Why do I see all kinds of garbage in serial monitor while I have it up?
A: We are using the RX pin (Pin 1) on the Arduino to drive a row of pixels, but the computer is also connected to the pin so it sees the WS2812B signals as very garbled serial data. It is OK no one will get hurt.

Q: My text is there but looks all janky. What gives?
A: The pixels can get messed up easy – especially WS2813 pixels and especially when the Arduino resets after a download since it turns off the pins connected to the pixels. The best thing to do is press and hold the reset button on the Arduino, turn off power to the pixels for maybe 10 seconds and then turn it back on, and finally release the reset button. This helps make sure the pixels don’t get confused by seeing noise from the the Arduino pins before they have turned on.

Q: Can I make it scroll in the opposite direction?
A: It is significantly harder since you have to send the data in order to the pixel strings, so you would have to compute ahead of time where to start sending. Not that much harder, but the current direction is easier and avoids needing a buffer.

Q: Is it possible to change the color of the text in real time – like even individual words?
A: Yes, I had a whole system where you could stick a #RRGGBB anywhere in the text to set the color. Unfortunately it was just a smidge too slow for some of the older, finicker pixels around. Worked great with all WS2813 pixel though since these have much longer timeouts. If you have the new pixels and really need this and can’t figure out how to do it yourself, LMK and I’ll give you some code.

Q: Can I pay you to build one for my yacht club’s big race event this Sunday?
A: the whole point of this project is to build it rather than buy it! I bet there is some bored 13 year old kid in your town who would love to build this for you if you buy all the parts for him.

Q: What if I only have 5 strings of pixels?
A: Check out this tiny little whiff of a font. Paste it into the Arduino sketch where indicated. Connect the strings to pins 2-6.

Q: I really want to be able to have bidirectional serial communication with my Arduino while it is scrolling.
A: You can do it! Use the above little font above to free up the Arduino’s TX pin, then use this command…
#define SERIAL_TX(c) do {while (!(UCSR0A&(1<<UDRE0))); SERIAL_TX_BLIND(c);} while (0)
…to write a char out the serial port.

Q: Can I change the baud rate of the serial port?
A: Yes, you can use any valid baud rate in the Serial.begin() line in the setup() function. Do not pick a baud rate that is too fast or you will start losing serial bytes, but really there is no reason to go any faster because 9600bd is much faster than anyone can read anyway. Slower is nice – set the baud rate to a speed you can comfortably read if you want to make sure the buffer never overflows.

Q: Can I edit the font or make my own font?
A: Yes! The font is defined where it says fontData and is designed to be very easy to edit directly in the program. You’ll see one section for each letter in the font, and then inside each letter there is one line like 0b00110000 for each column in that letter. If you look at them sideways and squint you should be able to see the letters pointing downwards. Here is the letter E, see it?…

Note that every letter must have the same number of columns, and that number is defined as FONT_WIDTH in the program. You should also leave the rightmost row as 0‘s if you are going to use the serial port since this bottom row of pixels would be connected to the same pin and the serial port. Please share any nice new fonts you make in the comments below!

There are also several nice fonts in the fonts directory that you can directly copy and paste into your program. Note that it is easier to copy them if you push the “raw” button on the github page for each font and then do “select all” + “copy” from your browser.

Q: Can I make my font 8 rows tall rather than 7 like all of yours?
A: Yes, but then you will need to use digital pin 0, which also happens to be the serial receive pin, so you will need to disable the serial port from using that pin by commenting out the Serial.begin() lin in the setup() function. Note that with no serial port, you will need to either generate all your text locally on the Arduino, or use a different kind or port like I2C or SPI to get your text into the Arduino.

Q: Can I make my font even taller than 8 rows?
A: Yes, you could in theory use all of the pins to drive LED strings and make a very tall font, but that would mean more complication. If you can live with just, say, 12 rows of pixels then everything works kind of nicely since digital pins 1-13 are all in a nice row on the side of the Arduino. If you really need to do this LMK and I’ll give some code.

Q: Why use an Uno? This would be so much easier with a TEENSY or something like that.
A: The Uno is cheap, well-known, and easily available almost everywhere. It is a scientifically proven fact that every person on Earth has at least three UNOs in a drawer somewhere.

Q: Where is the video of the giant Angry Birds game?!?
A: I want to see it again too! It was glorious! Sadly I’ve lost the link. If you’ve seen this project anywhere please LMK!

Q: How do I get interactive backspace to work like in the video?
A: Replace the appendToBuffer() function with this one…

void inline appendToBuffer( const byte b ) {

  if (b=='b') {  // backspace
    if (buffer_len) {
  } else  if ( buffer_len < BUFFER_SIZE ) {
    buffer[ buffer_len++ ] = b;

Q: Should I use WS2812B, WS2813, or SK6812 pixels?
A: WS2812B are the originals so are usually the cheapest and easiest to get, and have a wide selection of different form factors. WS2813 and SK6812 are newer versions that have a longer reset time, which gives you more time to do work on the Arduino between transmitting pixels. If you are going to use my code unchanged then it doesn’t really matter, but if you want to experiment with adding new features like changing color in the middle of a message or being able to make letters blink, then the WS2813 will make that much easier. (There are other differences that do not really matter for this project)

Q: Should I use 5V or 12V pixels?
A: The 5V pixels are more common and easier and usually cheaper to get. If you want to make a really long display, then the 12V pixels can better better since there is less voltage drop for a given length, so you can have longer connects to the power supply and use potentially thinner wires. 12V is also handy if you are going to be powering from a car or a car battery.

Q: Would it be possible to use a variable width font?
A: Yes. Probably the easiest way would be put leading zeros in the font data at the beginning of any characters that are narrower than the font width, and then skip any leading zeros when sending columns to the pixels. The timing would be very tight on older WS2812B pixels, but no problem on newer pixels with longer reset times.

Q: Can I power the Arduino from the same power supply I use for the pixel strips?
A: Yes. If you have a 5V power supply then you can connect the “+” side directly to the “5V” pin and the “ground” side to any of the “GND” pins of the Arduino. If you are using a 12V power supply, then you can connect that to the barrel jack on the Arduino. If you don’t have a barrel connector, then you can also connect the +12V to the “vin” pin and the “ground” side to any of the “GND” pins on the Arduino.

Q: How do I make it scroll vertically like in the Block Clock demo?
A: Check out

Related Articles

Back to top button