Home
Up
Mechanically Scanned LED display
Points Calculator
Pic Prgrammer
Simple DC motor
Induction motor
Variable Reluctance Motor
Dual Polarity power supply
AM Radio Receiver
Bar Code Reader
Simple IR detector
2 channel mixer
Motor controller
DC to AC power converter
RS232 level shifter
EEPROM module
Power Supply
Audio Module
op-amp module
Temperature and Humidity Sensor
R2R DAC
32Khz IR module
Real Time Clock Module
Bottle Rocket

 

 

Mechanically Scanned LED display

 

In case its not clear, it says" GO COUGS   WSU"

 P0003597.JPG (380041 bytes) Still picture of the entire device

P0003598.JPG (408535 bytes) Side view of the device

P0003599.JPG (434933 bytes) Slip ring contacts, delivers 5 volts to the display board

P0003601.JPG (569672 bytes) 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. 

P0003602.JPG (525049 bytes) here is a picture of the infrared emitter and phototransistor which makes up the revolution trigger.

P0003593.JPG (284844 bytes) A photo of the display with all green LED's

P0003607.JPG (437926 bytes) A mid-run shot.  The flash triggered the revolution sensor.

wpeD.jpg (94271 bytes) 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.

Timer 1 this is a 24 bit timer.  It will be used to determine the amount of time it takes for the display to make one complete revolution.  It will also be used to determine when and for how long each frame should be displayed.  Timer 1 is the clock by which all operations of the display are timed.  Every time a revolution trigger occurs, the value of timer 1 is divided by 256 (shifted right by 8) and stored into CPF.
CPF Counts Per Frame.  This is the amount of time each frame is to be displayed.  If each frame is displayed for this amount of time, and the speed of the display remains relatively constant, then it will appear that the circle has been broken up into 256 frames.
tmr1compare This is a 24 bit variable.  It will contain the value that the 24 bit timer1 SHOULD be when the next frame is to be displayed.  The current value of tmr1compare is taken, CPF is added to it, and the result is stored back into tmer1compare.  Whenever a timer 1 compare interrupt occurs (the lower 16 bits of timer 1 match) the upper 8 bits of timer 1 are compared to tmr1compare.  If they do not match, the interrupt exits, and waits for the next compare interrupt.  If the entire 24 bits match, then we load and display the next frame, add CPF to timer1compare and exit the interrupt.

..... To be continued

Notes on writing the software

POVdispNotes.pdf

Here is the source code

main.asm

added 5-28-06

Hit Counter