Step 13: Program the PIC

The board now complete, we have only to give it a program to run, and we will be ready to set our creation free into the wild!

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>

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) {
	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);
Programming the Board

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.

  1. PIC12F508/509/16F505 Datasheet
  2. Hi-Tech C 9.81 Compiler User Guide
  3. POVgen online LED Pattern Generator
  4. Hi-Tech C Compliler
  5. MPLAB Integrated Development Environment

Tools & Supplies
<p>It's been 4 years. I wonder if your solvent welded tank is still leakproof? And can I ask why you suggest silicone must not be used in direct contact with CuCl2?</p>
<p>Thanks for your sharing. It must be take care of safe in Making.</p><p>And this way may is good for simple circuit board. And there is no sold mask on it.</p><p>It is also a good way to choose a PCB fab to make it.</p><p>You can have a try with <a href="http://www.pcbway.com/e" rel="nofollow">www.pcbway.com</a>. Hope it would be useful for some people.</p>
Here's mine
I have a typo in the code, the second command in Iter2 should be movwf 13h
One more thing, if you add or subtract values from the Tables for your own version, don't forget to modify the jump values accordingly
<p>I rewrote the code from scratch in Assembly. I don't know how to properly share it, so if this is incorrect, I sincerely apologize. It didn't keep the format for the comments</p><p>If you keep the schematic in the same order, the hex values for output are as follows:</p><p>GP2 [ ] (Top LED) 04h</p><p>GP1 [ ] (Second Down) 02h</p><p>GP0 [ ] (Middle) 01h</p><p>GP4 [ ] (Fourth Down) 10h</p><p>GP5 [ ] (Bottom LED) 20h</p><p>Simply add them together to get your pattern :-)</p><p>; Code for POV Business Card<br>; Set up for the PIC12F508<br>; ASM source line config statements<br>; This SetUp works for both the '508 and 16F84A<br><br> __config 3FFAh ;_CP_OFF &amp; _PWRTE_OFF &amp; _WDT_OFF &amp; _RC_OSC<br><br> org 0<br> movlw 08h ; Put 0000 1000 into W<br> movwf 06 ; Load Tris file. Make GP3 input. Others output<br><br>Table1 addwf 02,1 ; Create jump for Table1<br> retlw 08h ; End of Table in Reverse, Doesn't output anything<br> retlw 30h ; going Forward<br> retlw 20h<br> retlw 37h ; J<br> retlw 00h ; Space<br> retlw 37h <br> retlw 25h<br> retlw 25h ; E<br> retlw 00h ; Space<br> retlw 37h<br> retlw 05h<br> retlw 27h ; R<br> retlw 00h ; Space<br> retlw 37h<br> retlw 25h<br> retlw 25h ; E<br> retlw 00h ; Space<br> retlw 37h<br> retlw 01h<br> retlw 37h ; M<br> retlw 00h ; Space<br> retlw 06h<br> retlw 01h<br> retlw 37h ; Y<br> retlw 00h ; Space<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw 0FFh ; End of Table<br><br>Table2 addwf 02,1 ; Create jump for Table<br> retlw 08h ; End of Table in Reverse, doesn't output anything<br> retlw __h ; going Forward<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw 24h<br> retlw 37h<br> retlw 20h ; 1<br> retlw 00h ; Space<br> retlw 37h<br> retlw 21h<br> retlw 31h ; 6<br> retlw 00h ; Space<br> retlw 25h<br> retlw 25h<br> retlw 37h ; 3<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw 37h<br> retlw 24h<br> retlw 37h ; 0<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw __h<br> retlw __h<br> retlw __h ; Omitted<br> retlw 00h ; Space<br> retlw 0FFh ; End of Table<br><br>Delay movlw 2Ah<br> movwf 0Dh<br>DelA decfsz 0Ch,1 ; Delay of 40,000 cycles<br> goto DelA ; Allows the entire name or phone number to be<br> decfsz 0Dh,1 ; displayed over a 2 sec wave. Play around with<br> goto DelA ; it for different timing<br> retlw 00h ; Adjusted in main part for different timing<br><br>Iter1 incf 10h,1 ; Increment table entry<br> movf 10h,0 ; Then put jump value into W<br> call Table1<br> xorlw 0FFh ; If end of table<br> btfss 03,2 ; Bit 2 of file 3 will be Set, won't output value<br> movwf 06h ; Output Table value to LEDs<br> btfsc 03,2 ; If bit 2 of file 3 set, with automatically return<br> retlw 00h<br> call Delay ; Pauses long enough to see it<br> decfsz 11h,1 ; Iteration, decrement file 11h<br> goto Iter1<br> decfsz 12h,1 ; Second part of iteration, decrement file 12h<br> goto Iter1 ; Not totally necessary but didn't want to mess<br> retlw 00h ; up file order lol<br><br>Iter2 movlw 32h ; Put last space jump value into W<br> movlw 13h<br>Sub2 movf 13h,0 ; Load value of file 13 into W for Table jump<br> call Table1<br> xorlw 08h ; If end of table<br> btfss 03,2 ; Bit 2 of file 3 will be Set, won't output value<br> movwf 06h ; Output Table value to LEDs<br> btfsc 03,2 ; Bit 2 of file 3 will be Set, will return<br> retlw 00h<br> decf 13h,1 ; Decrement down Table<br> call Delay ; Pauses long enough to see it<br> decfsz 14h,1 ; Iteration, decrement file 14h<br> goto Sub2<br> decfsz 15h,1 ; Second part of iteration, decrement file 15h<br> goto Sub2 ; Once again not totally necessary<br> retlw 00h<br><br>Iter3 incf 16h,1 ; Increment table entry<br> movf 16h,0 ; Put jump value into W<br> call Table2<br> xorlw 0FFh ; If end of table<br> btfss 03,2 ; Bit 2 of file 3 will be Set, won't output value<br> movwf 06h ; Output Table value to LEDs<br> btfsc 03,2 ; Bit 2 of file 3 will be Set, will return<br> retlw 00h<br> call Delay<br> decfsz 17h,1 ; Iteration, decrement file 17h<br> goto Iter3<br> decfsz 18h,1 ; Second part of iteration, decrement file 18h<br> goto Iter3<br> retlw 00h<br><br>Iter4 movlw 29h ; Put last space jump value into W<br> movwf 19h<br>Sub4 movf 19h,0 ; Load value of file 19h for Table jump<br> call Table2<br> xorlw 08h ; If end of table<br> btfss 03,2 ; Bit 2 of file 3 will be Set, won't output value<br> movwf 06h ; Output Table value to LEDs<br> btfsc 03,2 ; Bit 2 of file 3 will be Set, will return<br> retlw 00h<br> decf 19h,1 ; then decrement table entry<br> call Delay<br> decfsz 1Ah,1 ; Iteration, decrement file 1Ah<br> goto Sub4<br> decfsz 1Bh,1 ; Second part of iteration, decrement file 1Bh<br> goto Sub4<br> retlw 00h<br><br>Start bcf 03,2 ; Clear Bit 2 of file 3<br> btfss 06,4 ; If GP3 = 0<br> call Iter1 ; then call Iter1 for forward name<br> btfsc 06,4 ; If GP3 = 1<br> call Iter2 ; then call Iter2 for backward name<br> movlw 7Dh ; Load new timing value for delay<br> movwf 0Ch<br> call DelA<br> bcf 03,2 ; Clear Bit 2 of file 3<br> btfss 06,4 ; If GP3 = 0<br> call Iter3 ; then call Iter3 for forward number<br> btfsc 06,4 ; If GP3 = 1<br> call Iter4 ; then call Iter4 for backward number<br> movlw 7Dh ; Load new timing value for delay<br> movwf 0Ch<br> call DelA<br> goto Start<br> End</p>
<p>Most detailed instructable on POV. Thanks!</p>
<p>still no video?</p>
Plz upload the hex file for downloading it plz
There are controllers specially designed to transform domestic ovens into reflow ovens, you can find them in n_electronics (<a href="http://www.nelectronics.org" rel="nofollow">www.nelectronics.org</a>), adafruit (<a href="http://www.adafruit.com" rel="nofollow">www.adafruit.com</a>) or drotek (<a href="http://www.drotek.fr" rel="nofollow">www.drotek.fr</a>).
Saw those! Mine was an order of magnitude cheaper, though.
definitely the most comprehensive instructable ever
Really Cool! Complete end to end home based production! Well impressed. I think everyone have some that they can take away, even if they do not do home production. Well done!
Wow man, great instructable!!!
Hey, <br> <br>First of all, amazing -ible! <br> <br> Just curious as to where you sourced the bubbler wand; whether a standard pet shop aquarium wand will do or if you need something a bit more robust! Also, would there be anything stopping you from drilling a row of holes in a standard acrylic tube and chemically welding that in directly instead? <br> <br>again, great instructable! <br> <br>thanks! <br> <br>C.
Hey thanks!<br><br>I got that online, but I wouldn't recommend it. The acid embrittled the bubble wand I had pretty rapidly. Acrylic rod would would work great, certainly better. We just need aeration, so lots of fine holes drilled in a tube would be perfect. Good idea actually, I hadn't thought of that.
Hmm, I guess concentrated acid isn't a very popular substrate for aquarium fish ; -) <br> <br>I wonder if there is a non insidiously tedious way of drilling lots of tiny holes in acrylic round rod. Could it be done on a laser cuter with a small enough kerf somehow (I don't have much experience with them) ?
A drill press and a vice would do it better and faster.
May I suggest to use Liquid Tin instead of Tinnit.<br><br>I have found it much much easier to use, no mixing or heating needed.<br>Works faster too.<br>It is more expensive though, but has lasted me a while.<br><br>Great work, I am actually making a similar POV to teach others to make PCBs on their own.
That's a good tip. Tinnit has problems with oxidation, though it may be my neutralization procedure that is the problem, and not the plating composition itself.<br><br>Thanks and good luck!
I have been using an electric skillet set to 350-375 and just moving the boards off to a bit of wood as soon as the solder paste all melts. I think as long as your components sink heat at about the same rate that is an easier approach. I did have problems with some boards with large-ish surface mount caps. The LEDs might have melted before the caps were soldered. I solve that problem by using the hot plate in two passes.<br><br>Do you think there is a danger with my method of cooling too fast and having some ill effect? It sure is easier.
The ideal reflow lasts peaks only for a few seconds. Take a look at the reflow curve in step 11. Of course there's a danger; theoretically and practically, the lifetime of the components will be compromised. The question is, by how much, and is it worth your time?<br> <br> If you are making a thousand of something to tight tolerances, then the failure rate and inconsistency are unacceptable, and it's worth the time. If you are making 10 of a thing, and have the time to QA every one, then the skillet is probably easier. If it works, it works.<br> <br> My setup is probably overkill for most home SMD projects. I'd even say it was overkill for my projects. :) As it's been said before, overkill is a way of life.
That is just plain cool.
I find a zip top bag with a needle hole in the corner works great for applying solder paste. If you do big runs, a stencil probably saves time. For a few boards at a time I think I spent less total time and effort with the &quot;icing&quot; method. A suitably sized needle on a syringe is also said to work well.
<a href="http://www.instructables.com/id/Make-your-own-programmable-thermostat-with-Arduino/">http://www.instructables.com/id/Make-your-own-programmable-thermostat-with-Arduino/</a> You could also make your own PID controller. :)<br>
Hey vey nice project... just a question, why you set the Option Register to &quot;0b01000111&quot; ? <br>I took a look at the 12F508 Datasheet, but didn't get it. <br> <br>Thanks &amp; Congrats !
in the Pic12F508/509/16f505, you want page 24, section 4.5. The option register sets up the internal timer and &quot;wake up on pin change&quot; functions. They are useful functions, but not used in this application. In this case, these settings are mostly there just to disable those features.
all right then... thanks for your quick response !! <br> <br>Cheers,
p.s. thank you :)
I live in Ireland, and, for the most part, we don't have Toaster Ovens (Actually, when I saw the picture, I thought it was a Microwave, which could have ended badly). Could you recommend an equivalent appliance I could use? Cheers.
Hey, Argos do actually sell toaster ovens (search on their website), although they only go up to 230C (allegedly - the picture actually shows 400F as the max, so may not even be 230C). I am quite interested in picking up a cheap toaster oven for some SMT work, if you have found anything workable in Ireland please let me know!
That's a weird question! I have no idea what the equivalent is over there. Lots of things would work; it just needs a metal enclosure and some kind of heating element. The risk is always how safe you could make something that heats to up to 300 C. What we call a toaster oven is capable of that just as a matter of course, and so is very safe.<br><br>You might be able to take a regular vertical toaster with side heating elements and place it on it's side. I don't know how hot those can get, but it may be close. It would need to be sealed with a door somehow. And you'd need to find out what the regular operating temperature and wattage was so you didn't exceed that and start a fire.<br><br>Also, if you don't need your design in massive quantities, you can just go over the board with a hot air soldering gun and get similar results. Even a regular pen type soldering iron works, with practice. <br><br>Just don't do anything I wouldn't do!
that sounds like a &quot;oops - i kinda set the kitchen on fire making a business card,&quot; incident waiting to happen. <br><br>:)
I agree! This is kind of dangerous. :D
Thanks, you've been very helpful. I'll see what I can do with a regular toaster, and if not, like you said, just solder manually. Thanks!
Question:<br><br>How come you guys bake potatoes? make pizza, toast bread cheese and tomatoes, bake frozen chiken, pre-heat hotdog buns, broil a bunch of half garlic and olive oil, bake tomatoes, hot sandwich, etc?
You mean how do we? The magic of the oven grill. Same principle as the above, only attached to an oven and a hob, which would make the whole thing terribly awkward and expensive to use as a reflow solder oven. Basically, the Toaster Oven above is to the Double Oven, what the Hotplate is to the hob.
Interesting. Here in USA we can buy one oven toaster like that in hundreds of department stores, like WalMart, Target, etc. They ALL are manufactured in China and you can buy then from 10 to 40 US Dollars. If you have electric stove, probably you may have available to sell the heating elements. Here we use a coiled resistance, electrically isolated, that heat to a point (if you want) to get really red and heat the pan over it. The pan really sits over the element. There 3 or 4 sizes of those heating elements, the second size, the most common around, is for 900W, if I remember well. They feed on 220Vac. In the past I build a SMD reflow solder oven using a toaster, but I was thinking to build another from scratch, stainless steel box, thermal insulation another box inside, fans, a sliding tray for the SMD boards, may be even a metalic belt for automation. Using those stove elements is easy, just one on top, another on bottom, the PCB in middle, 20 to 30mm distant from the heaters. The oven I build 3 to 4 years ago, you may find it at http://www.ustr.net/smt/oven.htm and http://www.ustr.net/smt/ . My process is much simpler than the posted here, since I use a microcontroller already programmed with the temperature profiles and the temperature is captures from a real small circuit board inside the oven, so it is not &quot;air temperature&quot;, is an electronic circuit board temperature. Cost much less, since all the electronic control is made with less than $10. One day I need to publish that circuit and software.
cool cool now make mine to fit in my body so i wont lose it - but then again it the way it looks it would be a crime to set down.
I am working on my own card and encountered a problem with Hi-Tech C version 9.81. For some reason they do not have a declaration for &quot;TRIS&quot; in the header files. They will probably fix soon but in the meantime you just add this declaration before the main body of the code:<br><br>&quot;volatile control unsigned char TRIS @ 0x006;&quot;<br><br>Thanks for the instructable. Great Idea!!
There's always something... Yes, I forgot to mention that the default device specific header files are sometimes lacking. I also had some problems when they changed their formatting on legacy devices for the PIC12F508/509 in the latest version of MPLAB. Thanks for catching that!
This is very cool. You've got some serious creative skills thinking of and making a such a uniquely awesome business card.
That is INOVATION!<br>Really great idea for a vacuum pen!
Wow that is plain wicked!
Nice one on the laminator. Going to try that myself.<br>Been using water + iron for ages. Not exactly the safest method but gets the job done.
Out-friggin'-standing! This is the most detailed, best-written instructable I've read so far, and now my undisputed favorite. <br> <br>I've never done any surface mount work myself, but you've inspired me to rescue my electronics stuff from the yard sale pile and give it a shot. I'd maybe like to make a card that has a snap-off portion that will reveal a tinned connector that plugs into a USB port and has some digitally stored goodies, like a copy of my resume and some pics and videos of me doing my stuff. Probably too expensive and complicated to be practical, but it would sure be slick if I could pull it off. <br> <br>Honestly, this instructable could be a book if you wanted to flesh it out a little. Anyway, great job!
Thank you!<br><br>Adding USB capability is a feature many have recommended and I will certainly add in future variants of this thing; it would be so much more versatile if it could be programmed by anyone with a computer.<br><br>Alternately, your idea of what amounts to a flash drive on a board could be easily accomplished simply by buying up cheap 256 MB USB flash drives from five years ago. I bet you could get them for under a dollar if you found old stock. The work would all be done for you! Then just pull them out of their housing and cut out a slot for it to fit into out of card stock with your name and logo.
Beautiful sir!!
totally awesome. do you take orders? id buy a set quantity. like 200? if your price is right for me.

About This Instructable


623 favorites


More by sponges: Complete Circuit Board Lab & POV Business Card
Add instructable to: