Tuesday, February 15, 2011

TwinklePIC, part 2

Wait. Part 2? Was there even a part 1? Only the most devoted readers, endowed with prodigious memory, will remember that, oh, about a year ago, I started writing about a little electronics project I was cooking: a device that would have a number of LEDs in a constellation, each of which would twinkle - randomly fade in an out. The project has, throughout its entire 3-year existence, moved in fits and starts. As I have just about finished it, it is clear that documenting it has faired even worse than the actual doing of it. I hope to get it all out to you, dear readers, in the next few days.

To adjust the brightness of an LED is a straightforward task in electronics: just turn it on and off very fast. By varying the ratio of On time to Off time (also called the duty cycle), you can adjust the apparent brightness (your eyes and brain blur it together). This is a technique called pulse width modulation (PWM) and, as I said, is a straightforward task to do with a microcontroller.

What's a microcontroller? Think of it like a really small, very limited computer. Microcontrollers run small computer programs that are burned into the device itself (no hard drives here). There's a general-purpose microcontroller in your TV remote control, and one in your microwave. Is the brain of your cellphone a microcontroller? Or the latest screamer from Intel residing in your laptop? That is largely a matter of semantics and degree.

Microcontrollers are made by lots of different chip manufacturers, with feature sets and price points that run from the very mundane to "holy shit." For this twinkling lights project, there are hundreds of models that would do the job in the range of $1-15. At the time that I started tinkering (Dec 2009), I was already using some products from Microchip in my job. So, I went with what I was then familiar with and chose a member of the PIC16 family. Nowadays I am using some snazzy chips from Texas Instruments, and were I to do this overagain I might consider using a low-end member of the MSP430 family.

I also considered using an Arduino. For those that do not know, the Arduino is an open-source platform that is very popular in the Maker community. The Arduino is, essentially, just another microcontroller (made by Atmel), but it is very user-friendly and has a shallow learning curve. It is made to be accessible to novices - much of the nitty gritty is glossed over and made easy for you. A complete board (not just the bare chip) can be had for $30 - all the other tools (including a vast library of community-developed example code) are free. I decided against it in part because, in the goal of making it user friendly, they add a layer between the user and the silicon. That is handy if you know nothing about it, but I specifically wanted to run close to the silicon.

There are three timing tasks involved in getting an LED to twinkle. The first I have already mentioned: using PWM to set the brightness. The next is to vary the brightness by changing the duty cycle. This causes the brightness to change in time: fade in and fade out. The final task is to change the speed of that fading in and out over time, so that one minute the LED will fade slowly, and the next minute quickly. Figure this out for one channel, and you can scale it up to any number of channels. Put enough channels together, and I'd have a constellation of twinkling stars.

If anyone is interested in the details of the code, let me know. I might, at some point, find a place to put the entire design: circuit, PCB, and code listing. For now, let me summarize how I do each of those three tasks.

1) PWM. Many microcontrollers have special circuits that make this almost auto-pilot. Not many low-end microcontrollers can do this for, say, 8 channels at once. So, I brute forced it in software. I have one variable that counts up and up. When that timer value, T, reaches some maximum (65,000, or 2^16, if you care), it rolls over to zero. An LED channel has a number associated with it, which I'll call D. Since I have multiple LED channels, I'll call them D1, D2, etc. When the timer T rolls over to zero, I turn all the LEDs on. When the timer has counted up to D1, I turn that LED off. If D1 happened to be, say, 30,000, then that LED will end up spending about half of the time turned on, for a duty cycle of 50%. To make it appear convincing, the amount of time I spend on or off must be very short, otherwise the eye will catch it. So, I turn the LEDs on and off about 120 times per second.

2) Fading. If at some point I decide to change the value of D, I will change the duty cycle of that LED. If D becomes 10,000, the duty cycle will drop to about 15%, and the LED will appear dim. If I change it to, say, 43,000, the duty cycle will be closer to 75%. To make a convincing fading effect, I need to adjust D gradually and smoothly. So, about 10 times per second, I add or subtract a small amount, call it F. I'll increase D, in increments of F, all the way up to the max brightness. When I hit that ceiling, I'll turn around and start subtracting F from D. I keep decreasing D all the way back down to zero, then start increasing it again.

3) Change the Fading. Steps 1 and 2 are enough to make an LED smoothly get brighter or dimmer at a regular pace. If you've ever seen an Apple computer sleeping in the last 10 years, you'll see the power light doing this. The third element is to change the pace of that fading - make it happen faster or slower. To accomplish that, I need to make F change over time. This I do by, unsurprisingly, adding or subtracting a small, random, amount to F a few times per minute.

Scale this up so that I'm doing steps 1-3 on eight independent channels at once, and I get a pretty constellation of stars. Each channel fades in and out with its own speed, which is different than that of all the others, and which itself changes over the course of minutes. The resulting effect is, I would say, pretty nice.

Believe it or not, this is a very long winded explanation of what, in reality, only takes about 50 lines of computer code. This gets translated into a stream of about a thousand 1s and 0s, which gets imprinted onto the PIC16F684 microcontroller. This chip has 14 pins, costs less than $2, and can be used to drive 8 LED channels. Here's a prototype circuit I put together in early Jan 2010:

To the center-right there is a small pushbutton. This can be used to switch the display mode. The default is for each LED to twinkle randomly. Other modes set all the LEDs to a steady brightness (100%, 50%, etc.). The last mode is a sleep mode where everything is off, and the circuit draws next to no power. This is handy for battery-powered applications.

Coming up in part 3: how I take this prototype circuit and fancify it!

1 comment:

Candace said...

I do remember your previous post, but tell me again why you're making this??