Step 13Program the PIC
The PIC can be programmed either in C++ or assembly language. I chose C++, to mostly to save time, but also because I didn't necessarily want to commit to this architecture, and admittedly, assembly languages are no fun! For simplicity, I developed the board using the DIP PIC12F509, which is pin compatible with the 508. It is also larger and easier to manipulate for testing purposes, and I found that it had more memory than I needed, so I was able to downgrade the chip for the final product.
How the POV Card works
_______________________________________________________________________
The card is off until the momentary on switch is held down. On power up, the program simulates a little rolling ball with a binary counter that rolls in and out with the tilt of the card. After roughly four tilts back and forth, it then switches to Persistence Of Vision mode and cycles through a series of programmed patterns. Currently, it says my name, followed by a neat square wave pattern that acts as a separator, and then my phone number. When the tilt switch closes, the program recognizes that as the start of a wave, and plays the current pattern one time through, then waits until another wave starts. As long as the wave does not double back too soon, and the pattern is not too long, there will be no overlap as the pattern will be blank until it resets.
The Patterns
_______________________________________________________________________
Each pattern is an array of bytes, each byte a column in the sequence. The time that each column (frame) in the pattern is left on and the time between frames determines the speed of the display, and how close the frames are spaced when the card is waved. Basically, it changes the width of the characters and the pattern as a whole. Furthermore, the speed at which you wave the card also plays a part in the spacing, but not enough to make it illegible; since it changes frames at a constant rate, the variation is not enough to matter, but is enough to make it look dynamic. Neat, huh?
To create the patterns, I modified a script I found written by Andrew Mason. My version is customized to allow for alternate byte formatting and number of LEDS, but the LED placement is fixed, for the time being. You can make any pattern you want, provided it is small enough to fit in the PICs memory. The rate that the pattern plays back at can be changed in the code, as well.
The Program
_______________________________________________________________________
The code is very simple. Without PWM or interrupts, there were not very many tricky things I could do, even if I wanted to. Conserving space and optimizing made it a little more interesting, though, given the tweaking necessary to make the code fit in the PICs tiny memory.
To play a pattern, the PIC simply checks for the tilt switch to be activated, then loops through a pattern. It sets the GPIO outputs to the current byte in the array, which represents a frame, waits a set period, then increments the array. Once the pattern has played all the way through, it blanks the display and waits until the tilt switch has been activated. This indicates another wave has started, and it goes through the pattern once more.
The frame code looks like this, without quotes : "0b00000000,". The 0b delineates a byte and the comma separates each byte from the next. This is all placed inside an array of constants, since it won't be changing during the playback and that will save RAM. Five of the bits in the array indicate an LED output, while one is unused and one is a read-only bit used for the input pin. The bits used are: 0bXX12X543, where the number indicates the pin.
The Code
_______________________________________________________________________
#include <htc.h>
#include <stdlib.h>
__CONFIG(MCLRE_OFF & WDT_OFF & CP_OFF & OSC_IntRC);
const char waveform[] = { /* 0bXX12X543 - sets pin at number, to output high, e.g.:
0b00100111, complete array code omitted for space; see attached .c file for complete code */ };
const char binary[] = { /* code omitted */ };
const char name[] = {/* code omitted */};
void init(void) {
OPTION = 0b01000111;
//sets pin 2,3,5,6,7 output, pin 4 input
TRIS = 0b00001000;
}
void display_roll (const char p[], const char pattern_length) {
char i = 0;
for (unsigned int j = 0; j < 350; j++) {
//plays pattern forwards or backwards depending on tilt
if (GP3 == 0 && i < pattern_length) { i++; } else if (GP3 == 1 && i > 0) { i--; }
GPIO = p[i]; //sets LED outputs to current frame in current pattern
_delay(16000); //frame delay in number of cpu cycles
}
}
void display_pattern (const char p[], const char pattern_length, const char loops, const char speed) {
for (char i = 0; i < loops; i++) {
//exits display either at swing restart
for (char j = 0; j < pattern_length && GP3 == 1; j++) {
GPIO = p[j];
//frame delay in multiples of 10 microseconds :)
for (char k = 0; k < speed; k++) { _delay(40); }
}
GPIO = 0b00000000; //blank output so pattern doesn't overlap while swinging back to start
while (GP3 == 1); //if still waving, wait until swing restarts and switch contacts
_delay(5000); //lazy debounce
}
}
void main(void) {
init();
display_roll(binary, 31);
while (1) {
/* function variables are: pattern name, length of pattern (in bytes/frames),
number of loops, speed of display/framerate */
display_pattern(name, 69, 110, 25);
display_pattern(waveform, 71, 100, 25);
display_pattern(number, 61, 110, 25);
}
}
_______________________________________________________________________
All code was written in Notepad++, an excellent free multi-language editor. You will also need the MPLAB IDE with a copy of the HI-TECH C Compiler. Both are available in free versions.
You will need a copy of Microchip's PICKit 2 programming software. With the chip connected and the iCP01 plugged in, set the device family to "Baseline" and select PIC12F508 from the device dropdown. Then load the hex file and press the write button.
- PIC12F508/509/16F505 Datasheet
- Hi-Tech C 9.81 Compiler User Guide
- POVgen online LED Pattern Generator
- Hi-Tech C Compliler
- MPLAB Integrated Development Environment
Tools & Supplies
- PIC12F508 I/SN SOIC or PIC12F508 I/P DIP microcontroller
- USB In-Circuit Serial Programmer (iCP01)
- Breadboard
- 8-pin SMD IC breakout board, or extra unpopulated PCB
| « Previous Step | Download PDFView All Steps | Next Step » |


























































"volatile control unsigned char TRIS @ 0x006;"
Thanks for the instructable. Great Idea!!
RealCoolDude
the only thing missing is a video of the card in action. ;)
Peace, thanks for sharing
Would be one of the best instructables with the final touch of a video of it in action.
The writeup was detailed but very understandable.
Now I want to redo my etching lab. =)
And thanks!