
In case its not clear, it says" GO COUGS WSU"
Still picture of the entire device
Side view of the device
Slip ring contacts, delivers 5 volts to the display board
The slip rings. An copper clad board used for etching PCB's was
milled to make rings. These rings are pressed on by the spring
contacts in the picture above, and allow power to be transferred to the
rotating display.
here is a picture of the infrared emitter and phototransistor which
makes up the revolution trigger.
A photo of the display with all green LED's
A mid-run shot. The flash triggered the revolution sensor.
a multicolor display. High intensity LEDS are the ticket to a good
display.
Propeller clocks, persistence of vision displays,
mechanically scanned LED displays.
There are many names for them.
I saw them, I wanted to join the ranks of those who built them,
and so I did.
I began by selecting a PIC
device to operate the display. I
chose a pic 16F628 because it had a built in 4 mhz rc oscillator, a wide
range of useful peripherals and interrupt capabilities, and I did not
feel that it would be overkill for this project.
I knew that I wanted speed
and precision in the code, so had to rule out my basic compiler (Mbasic
Pro, I have a love hate relationship with that compiler / company) and
there are no completely free C compilers for the PIC.
This only leaves assembly as a language.
In many of the similar
projects given on the web, no one seems to go into detail about the
code. Sure they provide the
source, but they don’t explain the process of design, they don’t
explain their code, they just give it to you.
I would like to explain my process of designing to the code, so
that I may add something different to the plethora of websites that
describe these mechanically scanned LED displays.
I don’t know about you,
but I hate the idea of a delay loop that just wastes cpu cycles. I like the idea of interrupts, and I love it when I can get
an entire program to be interrupt driven.
It means that other things can be done in the off time between
interrupts, and we don’t waste cpu cycles just incrementing a counter
and checking its value. It
also means that changes to the program in the main loop have no effect
on the interrupt driven program. That
program always runs, when it needs to, and only when it needs to.
Less timing sensitive applications can be run on top of the
interrupt application transparently.
I know its not always that simple, but I really enjoy feeling
like I have not written something that is going to go to pieces if I
remove or change a single instruction.
That said, this design
philosophy is what I adopted for this project.
In my ideal program, the main assembly program would look like
this:
main:
Goto main
This would leave all the
extra time between interrupts for ANYTHING I wanted.
It could calculate new frames to be displayed, who knows!
But the idea is that the display program is transparent to the
main program. It doesn’t
even have to know that 200 times a second the display has to be updated,
and blah blah blah…
From looking at other
sites, I knew that displays most had some kind of sensor to indicate
when a full revolution had been completed.
From this point, I had two choices for making the display.
Choice 1: when the sensor
is triggered, begin a sequence, which steps through the frames after a
predetermined amount of time. The
upside to this approach is its simplicity.
The downside to this approach is that the display needs to be
spinning at the right speed in order to display all the information, and
also to utilize the full size of the display.
If the motor is spinning too slowly, then the display will appear
“squished”. Too fast
and the display may not get all the information displayed before the
trigger is tripped again. Ultimately,
I scrapped this idea.
Choice 2: determine the
amount of time it takes for a full revolution to be completed. Take that time, divide it into X chunks then X number of
frames will each be displayed for 1 chunk of time on the next spin
rotation of the display. The
advantage of this design is the flexibility of the display.
If all goes well, the display will be the same no matter how fast
or slow the motor is spinning. The
downside is it is more complicated.
However, I decided I really wanted a whiz-bang gadget, so I went
with this approach.
So I knew I would have
some kind of “trigger” that would fire when a complete revolution
was made. I decided that
this trigger needs to be tied to an interrupt so that things can happen
as soon as the trigger is fired. There
are a few choices I had available.
The B0 interrupt was first in my mind.
The second was the capture pin.
Using the capture pin would allow me to take a snapshot of the
timer1 value value when the triggered fired.
This seemed ideal. However, the capture pin (and the B0 interrupt pin) all used
port B. I wanted to use
port B for the display, so that displaying 8 bits of data was as
painless as:
Movf
data,w
Movwf
PORTB
This meant either
splitting up the data between two ports, or to find another way. Then it occurred to me, the comparator! A most excellent solution!
A comparator interrupt will be triggered whenever the state of
either comparator changes, and with an internal reference, I simply need
to feed it a trigger signal and viola!
I have an interrupt! It
will even allow for some signal conditioning.
The comparator will trigger an interrupt, which will set a whole
series of events in motion. First
the timer will be stopped. Then
its value will be captured and divided by X to determine the amount of
time that each “frame” will be displayed.
If I choose X to be something 2^n, then a divide will simply be a
shift right by log2(X). I
chose 256, because I (mistakenly) believed that a 16F628 has 256 bytes
of EEPROM space. This would
allow me to write into the EEPROM the things I wish to be displayed, and
then all I have to do is retrieve each frame (a byte from the EEPROM
representing which LEDs to turn on and which to turn off) from the
EEPROM and send it to port B.
The capture compare module on timer 1 would be used
to trigger a compare interrupt whenever the value in timer 1 matched a
the value determined for displaying a new frame. I thought I would
do a little math at this point to see what the limitations of using a 16
bit timer would be. 16 bits means that I can count from zero up to
2^16 - 1 or 65,535. a 1 mhz clock will result in a timer overflow
every (1e-6*2^16 =) 65.536 milliseconds. If I stick with a 16 bit
register, this is the longest period of time that the display will be
allowed to make one revolution. any time greater than ~64
milliseconds to make a complete revolution will result in an overflow,
and the display will not operate properly. For ha ha's lets
determine how fast the rotor would have to be spinning in order to have
things work properly. at 64 milliseconds per revolution, that is
~15 revolutions per second, multiplied by 60 seconds/min ~= 900
RPM. Not too slow, Not too fast, but I am not thrilled with the
idea of being REQUIRED to run it at that speed. so I decide to add
another 8 bits to the timer using software. this yields a 24 bit
timer. Going through the calculations gives me a minimum RPM of ~
3.75. Much better.
Adding 8 bits to the timer is not an extremely
difficult task. I will enable the timer 1 overflow interrupt, and
when timer 1 overflows, I will increment an 8 bit register. When a
compare interrupt occurs, I will check to see if the upper 8 bits of our
24 bit timer match an expected 24 bit timer value. If they do not,
wait for the next compare interrupt and try again. If they do
match, increment the frame counter, grab the next frame and display it.
Things are starting to get a little complicated
now, so I am going to lay out the variables, explain their purpose, and
hopefully this will help you get a good overall picture of what is going
to occur.