A few months ago, I made a simple PIC-based POV toy for my daughter. Here are some building notes, photos and code of course.
I wanted to build a very minimal toy, in true KISS-style: some suitable PIC microcontroller, battery, red leds, as few external components as possible and all in a small case which can be whirled around in a circle to show some text (I called the thing the WhirlyWord).
A bit of digging in the piclist archives and elsewhere showed that others use 7x5 character cells for general text displays (LCD modules do this also), so I needed to control 7 leds. The tiny 12Fxxx PICs have only 5 output lines, thus won't do directly. I could have used time-multiplexing with a 74138 or similar, but decided to use a "larger" PIC 16F628 instead, for the sake of simplicity and also to maximize the time the leds are on (to make the WhirlyWord work with higher ambient light levels). As to user interface, there's an on-off switch and a push-button to cycle through the messages to display.
For the case I used an old DAT tape case: soft plastic, light, easy to drill and also easy to open, and sufficiently sturdy. First I drilled holes for the 7 leds and the switches. The PIC was supposed to run on an old motherboard battery (3V) but that proved to be dead, so I quickly built a battery holder of sorts to run the WhirlyWord off 3 button cells (3x1.5V). This was overkill as 3V would have worked for PIC and red leds just as well, but I had some programming trouble initially which seemed to indicate too little voltage available. The leds got a limiting resistor each, and were soldered to the PICs right-side outputs (well, to its socket). The pushbutton is connected to the MCLR pin, which triggers a reset that I trap to cycle messages. High-precision timing isn't really necessary, so the internal 4MHz oscillator is good enough: thus the only external component I needed (besides PIC, leds and their resistors) was a pull-up resistor for the reset button. Here's the simple schematic.
Construction was trivial, but making the thing whirlable wasn't: with a single bit of string it wouldn't stay oriented properly, nor would two strings do the job properly. Somehow there was too much oscillation to keep it lined up nicely. In the end I made a handle-and-hub out of some old screws and nuts, and attached the WhirlyWord with two 60cm pieces of 1mm wire. This works great.
The software part was meant to be simple, too, but I had to go through a lot of debugging to find out just which of the myriard features of the 16F628 I would have to disable to get things going.
I decided to ignore the EEPROM and store font and message info in an add-to-PCL-and-RETLW table. To keep things trivially simple, I also didn't store the whole font character table but just the uppercase characters and a few punctuation marks.
The code is very simple: startup, check if we've been reset? if so, switch to the next message. then display the current message character-by-character and column-by-column, wait a tad, repeat. Here is the source and the auxiliary delay library.
Because I chose to wire the leds as simply as possible, the pin assignments don't correspond conveniently with the output bits to toggle. This is what the rotation and bit twiddling in the show routine does. The font/character table came from the piclist here, which says it's 8x6 but is not: it is only 5x7 (the first byte is zero, and the 8th bit is never set either). Unfortunately, it's inverted: the most-significant bit is the bottom led, while I use the MSB for the top led. A few lines of perl took care of that minor inconvenience, resulting in this charset table.
I inserted a part of the charset table (plus a quick homegrown heart symbol) into the program space (at 0x100, note bank switching on PICs), and made a second small table called sequence that carries the info about what is to be displayed: the sequence returns the offset of the message's character in the charset table, or one of two end-markers. End-of-message is indicated by 0xff, and end-of-last-messages is indicated by 0x80.
The workhorse routines (startmsg/nextcol and trynext) simply count columns into chars (1 to 5) and message indices into the sequence table, call sequence and charset to get the correct column led settings and switch on the leds. I played around a bit until I found working timing parameters; in the end I used these: each column is lit up for 2ms (which makes a char 10ms "wide"), there is an inter-character space of 4ms and after each message I pause another 10ms.
That's all there is to this: cheap, simple, easy to build and modify, works. Have fun making your own!