Introduction: USB NeoPixel Deco Lights (via Digispark / ATtiny85)
For this Instructable we need a WS2812 LED strip, also known as NeoPixel, and any MCU that could be programmed via Arduino. I use Digispark, it is a very nice tiny MCU based on ATtiny85. It has a special bootloader called Micronucleus which provides the ability to upload a program directly trough USB. This means that if you have Digispark board you may start using it without any other hardware, just follow the instructions at http://digistump.com/wiki/digispark
List of Components:
- Digispark (any Arduino will do)
- WS2812 LED strip (NeoPixel)
Please note that NeoPixel library needs enough memory to hold color data for all pixels. You need 3 bytes for each LED in your WS2812 strip (and some more for other variables). For example, ATtiny85 has only 512 bytes of memory and I was able to control up to 100 LEDs. If you want to do longer strips, you need more powerful MCU (ATmega328 is a decent choice).
Step 1: Wiring
Most WS2812 strips comes with three-wire connectors. I removed the plastic casing of the connector and connect wires to pins directly (they fit well). White is GND, red is +5V and green is data input.
Most LED strips have additional power lines on both ends. This wires are usually naked, so make sure to isolate it (otherwise you may accidentally short-circuit it).
Please note that LEDs require a lot of power. If you have a strip of 30 LEDs, you can run it on full brightness directly from any PC or USB power supply (it will consume less that 500mA). About 100 LEDs will work as well on low brightness, but if you want more, you'd better off with a separate power. For long strips it is recommended to apply power from both ends, for extra-long strips, connect additional power lines each 100-200 LEDs.
WS2812 receives color data serially, so you can control virtually any number of LEDs with just one data pin. You can use any digital output pin (do not forget to put correct number in the code).
Once we connected a strip, let's get to the coding part.
Step 2: Coding
The code is available at my github repository – you can download code as a single file here: https://goo.gl/abFfxz
To quick start, find the #define PIN 0 and replace 0 with number of pin which you connected to data input of NeoPixel strip.
You probably would also like to adjust other settings, which are explained in code comments:
- #define NUMPIXELS 30 – sets number of pixels to control
- #define RNDPIN 2 – set to any pin with analog input (it is used only once to initialize random number generator)
- #define BRIGHTNESS 64 – maximum LED brightness (1 to 255). Please note that high brightness requires lots of power, so start with low values
- #define FOCUS 65 – shape of color spots (increase to get narrow spots, decrease to get wider spots)
- #define DELAY 4000 – set the speed of animation: decrease to speed up, increase to slow down (it's not a delay actually)
- #define DEBUG 0 – set to 1 to display FPS rate
Upload the code using you usual approach. Enjoy!
Step 3: Troubleshooting
If you do not see anything at all, check your connections, polarity and data pin.
If some LEDs are blinking or stuck – it is likely a power issue. Try lowering the #define BRIGHTNESS setting and make sure you have enough power.
If you see any bugs in code or would like to improve – you are welcome!
Step 4: How It Works
For this project we have three "color spots" which runs back and forth along the strip with different speeds. When spots run across each other, superposition of red, green and blue results in various colors. We keep position and speed of each spot in variables and we need to recalculate a color for every LED on each redraw. While we can do it many times per second, the animation will look smooth.
Each color component of a pixel is proportional to exp(-d*d), where d is distance between the pixel and the center of spot of corresponding color. In other words, pixel colors represent a normal (Gaussian) distribution – it is exactly the same as using "Gaussian blur" filter in graphic editor.
The exponent function included in Arduino library appeared to be very slow, so I made an approximation using only two multiplications and one division: 1.0/(1.0-(0.634-1.344*x)*x). Please note that this approximation is suitable only for x < 0.
We calculate color of each pixel in loop and send it to a memory buffer by calling strip.setPixelColor(). When we looped over each pixel we call strip.show() and NeoPixel library synchronously sends all data to specified pin – all pixels, one by one, 24 bits of color data for each pixel. First NeoPixel reads first 24 bits of data, stores it locally in a register and passes all other data through to next pixels. Second "pixel" takes its data and sends remainder to the next one – and so on and so forth until every pixel gets it's data. You can safely send less data than number LEDs you have in a strip – only first NUMPIXELS will work then.
The code is well documented (I hope!), and please ask questions in comments here!
Step 5: Tweaking
Of course, there are lots of ways to modify this idea and create other projects.
For example, I made a metal ring for one of my projects and glued one of the strips to it. Now it is a nice decoration light you can put on a wall or a ceiling. Putting a strip near a window pane results in a nice reflection (as you could see on a photo).
In technical aspects, the code may be improved a lot by rewriting math in fixed-point calculations. I am using float to keep things descriptive and easy to understand, but it is very slow. I would probably publish an optimized version later – or, if someone would like to do – you are welcome!
One of other ideas I have is to use a microphone to adjust animation to sound. It would probably require something more powerful than ATtiny.
Finally, you can plug Digispark into any powerbank and enjoy your gadget in portable mode. Glue the strip to a handbag, a garment, or a bicycle and use it as a unique personal accessory .)
Participated in the
Arduino All The Things! Contest
5 People Made This Project!
- bumsfallera39 made it!
- surveyranger made it!
- DarioM15 made it!
- Challon made it!
See 1 More
Question 1 year ago on Step 5
This is a great Instructable and beautiful neopixel display. Your code is very well documented, so I apologize for this naive question: Where in the code is the timing between animation "frames"? I know you're not using delay (); but, I can't see where that was replaced with another function. Thanks for any help!
Answer 1 year ago
Thank you for kind feedback and for your question.
In this project we always keep this code running at maximum FPS ("frames" or redraws per second) possible – there's no need to give attiny some rest. So instead of pausing to achieve desired animation speed, we keep track of current time and adjust animation offsets by using DELAY coefficient. This happens in lines 64-66 of the code https://github.com/smartynov/iotfun/blob/instructa...
It means that the program will try to animate as smooth as possible all the time. The real FPS rate depends on number of pixels, my experiments showed good results for up to 100-200 pixels. There's even a code to "output" current FPS under DEBUG mode (see lines 93-104).
Reply 1 year ago
Thank-you so much for your very prompt response, and especially for your through explanation. It makes sense to me now! I appreciate your help!
Tip 2 years ago
Some WS2812B LEDs sink up to 50mA at max brightness How Much Current Do WS2812 / NeoPixel LEDs Really Use? (pjrc.com) That means 10 LEDs would be the most you could power off of a USB1 port (500mA)
To work around this, I'm powering my LEDs with a second micro-USB port, Amazon.com: 10pcs Micro USB to DIP Adapter 5pin Female Connector B Type PCB Converter pinboard: Home Audio & Theater (connected to LED 5V and GND) Powered by a high current power supply Amazon.com: NorthPada Raspberry Pi 3 Model B B+ A+ Plus Power Supply Charger AC Adapter 5V 3A PSU Micro USB 5 Feet with Power On/Off Switch (1 X Power Supply): Home Audio & Theater
While my digispark is connected to the LEDs only with GND and Data. The Digispark will be powered by my PC USB port while coding.
Once I'm done with coding, I'll power my digispark from the DIP adaptor, and tape off the digispark USB (since I can't plug it into my PC if the LEDs are connected to the digispark 5V)
4 years ago on Step 3
Hi, thanks for your post. when I program attiny85 with arduino for neopixel LEDs , I just see solid white color . programming simple codes like blink works fine but when it comes to neopixel leds , it's not working . can you please help?
Reply 2 years ago
I have the same issue running pop so and programming it with an Arduino Uno.
Question 2 years ago
Mine only works till the 60th pixel. I have 72 pixels on my LED strip. How do I fix this?
Answer 2 years ago
Add an external power supply
6 years ago
Thank you for sharing your learning with the digispark. Neopixels are fun, but can be confusing to learn about. I just made my first instructable, about fitting my neopixel project into an ATtiny85. Lots of clues in the sketch, since comments do not count against your project size during the upload! I love the new brightness command in the library!
6 years ago
Thanks for this wonderfull project really nice
6 years ago
i did this with a 50 string of 12mm WS2811 led's, worked a treat! could hug you for how simple you made this! :D
7 years ago
I love it!!
I made a fountain-light for my sister by encapsulating ten discrete Neopixels in resin, and sanding it to look like a quartz-crystal. then with the digistump, and a cellphone charger, (along with this awesome code) her magic-fountain is REALLY magical now!!
Reply 7 years ago
Thanks Dan! I'm going to experiment with NeoPixels in plastic (or even stone) as well. Here is my brief sketch (just put a tiny stone turtle over a WS2812 strip). Could you share what sort of resin you were using?
Reply 7 years ago
It's a two-part table-top epoxy. I chose that because there isn't a lot of heat generated during curing like there is with some other casting resins.
7 years ago
Great looking lighting system.
Reply 7 years ago
Thanks Jason! Feel free to vote for me in the Arduino contest ,)