14
The Propeller, a mechanically scanned LED clock by Bob Blick. The clock is on a spinning piece of perfboard, but it must get power. I thought of many ways to do this, including using two motors(motor one has its shaft fixed to a base, and motor two spins the body of motor one, generating electricity), making a rotary transformer, or using slip rings. I decided to do it another way, taking power from the spinning armature of a plain DC motor. In order to run the wires out of the motor, I removed the bearing from one end of the motor, leaving a big hole. There are three terminals inside most small DC motors, and it acts a lot like three-phase alternating current, so it must be rectified back to DC. A nice side effect of this is that the position of the motor can be detected by taking one of the phases straight into the microprocessor. Step One: Mangle a Motor. Find a VCR, perhaps a Sharp or a Samsung, with a flat reel motor. The motor I have is marked JPA1B01, but Sharp knows it by the number RMOTV1007GEZZ. Take it apart without mangling the brushes(there are little holes to slip a paperclip into to move the brushes out of the way), and notice that it has one ball bearing and one sleeve bearing. Knock the sleeve bearing out of the case and glue or solder it to the other end of the motor, as an extension of the ball bearing. The shaft of the motor will have to be repositioned slightly to get the right height, press it in a vise with a hollow spacer on one end. Take a Berg connector with three wires and solder them to the three terminals on the motor's armature. Glue a short threaded spacer to the shaft at the end that will stick out the hole, and reassemble the motor(be careful with the brushes). You can glue the motor to a VCR head as a weighted base. Step Two: Build the circuit. I used perfboard(Vectorboard) and handwired the circuit together. Use an 18-pin socket for the 16C84 because it needs to be programmed before putting it in the circuit. For the 7 current-limit resistors I used a DIP resistor array, because it made it easy to experiment with LED

The propeller

Embed Size (px)

DESCRIPTION

ieee projecs

Citation preview

Page 1: The propeller

The Propeller, a mechanically scanned LED clock by Bob Blick.

The clock is on a spinning piece of perfboard, but it must get power. I thought of many ways to do this, including using two motors(motor one has its shaft fixed to a base, and motor two spins the body of motor one, generating electricity), making a rotary transformer, or using slip rings.

I decided to do it another way, taking power from the spinning armature of a plain DC motor. In order to run the wires out of the motor, I removed the bearing from one end of the motor, leaving a big hole.

There are three terminals inside most small DC motors, and it acts a lot like three-phase alternating current, so it must be rectified back to DC. A nice side effect of this is that the position of the motor can be detected by taking one of the phases straight into the microprocessor.

Step One: Mangle a Motor.

Find a VCR, perhaps a Sharp or a Samsung, with a flat reel motor. The motor I have is marked JPA1B01, but Sharp knows it by the number RMOTV1007GEZZ. Take it apart without mangling the brushes(there are little holes to slip a paperclip into to move the brushes out of the way), and notice that it has one ball bearing and one sleeve bearing. Knock the sleeve bearing out of the case and glue or solder it to the other end of the motor, as an extension of the ball bearing. The shaft of the motor will have to be repositioned slightly to get the right height, press it in a vise with a hollow spacer on one end. Take a Berg connector with three wires and solder them to the three terminals on the motor's armature. Glue a short threaded spacer to the shaft at the end that will stick out the hole, and reassemble the motor(be careful with the brushes). You can glue the motor to a VCR head as a weighted base.

Step Two: Build the circuit.

I used perfboard(Vectorboard) and handwired the circuit together. Use an 18-pin socket for the 16C84 because it needs to be programmed before putting it in the circuit. For the 7 current-limit resistors I used a DIP resistor array, because it made it easy to experiment with LED brightness. I settled on 120 ohms. You can use seven regular resistors, because 120 ohms works fine, though it puts the peak current right at the limit for the 16C84. Think about balance while you build this circuit, and reference my pictures, so you don't have to add a lot of balancing weight later. Substitute for any part values you like. Note that I used a 47000uf supercap, it is to keep the clock running after turning it off, so you can set the time. The LEDs get power separate from this. Don't substitute a ceramic resonator for the 4MHz crystal,

Page 2: The propeller

this is a clock and should be accurate.

Step Three: Program the 16C84.

You'll need a programmer that will program a PIC16C84. If you found this file/web page, you can find plans to build a 16C84 programmer. Program it using the hex file accompanying this document. I have included the source code(.asm) just for your amusement. When programming the chip, set the chip options to: watchdog timer(WDT) OFF and oscillator to normal XT crystal.

Step Four: Throw it together and Keep Time.

Screw the circuit board to the motor, and plug the three wire connector in. Apply power to the motor. The preferred voltage is 6.2 volts, but it will run from 5 volts to about 7.5 volts. Note that 5 volts gets to the circuit when 6.2 volts is applied to the motor, because of diode losses. The clock may be working at this point, displaying 12:00. If it isn't. there was probably some voltage on the supercap when you plugged in the chip. Turn off the power and momentarily short pins 5 and 4 together(ground and /mclr) to reset the chip. Now when you apply power the clock should work, and you can set it by turning off the power and pushing the buttons(hours, 10 minutes, minutes) the right number of times. If the numbers appear backwards, reverse the polarity to the motor to make it spin the other way. You might experiment with balancing the clock, and the use of foam under the base to reduce vibration.

Step Five: Modifications.

If you look closely at the source code, you'll see that the "dot rate" is adjusted to the speed of the motor to make the display a consistent width regardless of the motor's speed. The motor I used has brushes set 90 degrees apart, and gives two indexes each revolution. The clock displays on two sides, 180 degrees apart. If you use a motor with the brushes 180 apart, the clock will only display on one side, and the numbers will be too wide. You'll want to modify the program, in the section marked D_lookup_3. The value in the W register when Delay gets called effects the width of the digits. You might try sending half of the period_calc value to Delay, perhaps by rotating period_calc right into W(remember to clear the carry flag first). Like this: bcf STATUS,Crrf period_calc,wcall Delay

January 25, 1997 Bob Blick www.bobblick.comcopyright 1997 Bob Blick, all rights reserved

Page 3: The propeller

updated notes November 2, 2006Note: PIC16C84 is now obsolete. You may use either a PIC16F84 or PIC16F84A with no changes.Note: Sharp VCR motor is now obsolete. Use any DC motor, preferably meant for 12 volts so the speed will not be too great when operated at approximately 6.2 volts.

The Propeller Clock Parts List

Capacitors:C1, C2 - 33pf ceramicC3, C6 - 0.1uf ceramicC4 - 47uf electrolyticC5 - 47,000uf supercap(memory cap)

Diodes:D1-D7 - light emitting diodesD8-16 - 1N4001 general purpose 1amp rectifiers

Resistors:R1 - 120 ohm DIP array or seven 120 ohm resistorsR2-R6 - 10k ohm

Misc:J1 - three terminal Berg connectorSW1-SW3 - normally open pushbutton switchesU1 - PIC16C84, PIC16F84 or PIC16F84AXTAL1 - 4MHz crystalMOTOR - Sharp RMOTV1007GEZZ

Note: U1 to be programmed with mclock hex file

Code

;--------; mclock8.asm; "The Propeller" mechanically scanned LED clock; some changes since last version -; modified table etc for compatiblility with 8th LED; watchdog timer used to ensure startup; Bob Blick February 12, 1997; Licensed under the terms of the GNU General Public License, www.gnu.org; No warranties expredded or implied; Bob Blick February 18, 2002;--------

list p=16C84radix hex

Page 4: The propeller

include "p16c84.inc";--------; remember to set blast-time options: OSC=regular xtal, WDT=ON; timings all based on 4 MHz crystal;--------; are these equates already in the include file? someday I'll look.;--------w equ 0f equ 1;--------; Start of available RAM.;--------

cblock 0x0Csafe_w ;not really temp, used by interrupt svcsafe_s ;not really temp, used by interrupt svcperiod_count ;incremented each interruptperiod_dup ;copy of period_count safe from interruptperiod_calc ;stable period after hysteresis calc.flags ;b2=int b1=minute b4=edgedot_index ;which column is being displayeddigit_index ;which digit is being displayedhours ;in display format, not hex(01-12)minutes ;00 to 59bigtick_dbl ;incremented each interruptbigtick_hibigtick_lokeys ;key valuescratch ;scratch valuetick ;used by delay

endc;--------; Start of ROM;--------

org 0x00 ;Start of code spacegoto Start

;--------; INTERRUPT SERVICE ROUTINE;--------

org 0x04 ;interrupt vectorIntsvc movwf safe_w ;save w

swapf STATUS,w ;swap status, wmovwf safe_s ;save status(nibble swap, remember)

;--------; done saving, now start working;--------; clear watchdog timer to ensure startup

clrwdt;; increment period count

incf period_count,fbtfsc STATUS,Z ;zero set means overflowdecf period_count,f

; 234375 interrupts every minute. Increment the bigtick each time.incf bigtick_lo,fbtfsc STATUS,Zincf bigtick_hi,fbtfsc STATUS,Z

Page 5: The propeller

incfsz bigtick_dbl,fgoto Bigtick_out

;--------; here? bigtick has rolled over to zero and one minute has passed.; reload bigtick and set a flag for the main counter;--------

movlw 0xFC ;234375 = 0x039387movwf bigtick_dbl ;0 - 0x039387 = 0xFC6C79movlw 0x6Cmovwf bigtick_himovlw 0x79movwf bigtick_lobsf flags,1 ;notify Keep_time

Bigtick_out;--------; done working, start restoring;--------

swapf safe_s,w ;fetch status, reswap nibblesmovwf STATUS ;restore statusswapf safe_w,f ;swap nibbles in preparationswapf safe_w,w ;for the swap restoration of wbcf INTCON,2 ;clear interrupt flag before returnretfie ;return from interrupt

;--------; CHARACTER LOOKUP TABLE; ignore high bit. set=LED off, clear=LED on, bit0=bottom LED, bit6=top LED;--------Char_tbl

addwf PCL,fdt 0xC1,0xBE,0xBE,0xBE,0xC1 ;"O"dt 0xFF,0xDE,0x80,0xFE,0xFF ;"1"dt 0xDE,0xBC,0xBA,0xB6,0xCE ;"2"dt 0xBD,0xBE,0xAE,0x96,0xB9 ;"3"dt 0xF3,0xEB,0xDB,0x80,0xFB ;"4"dt 0x8D,0xAE,0xAE,0xAE,0xB1 ;"5"dt 0xE1,0xD6,0xB6,0xB6,0xF9 ;"6"dt 0xBF,0xB8,0xB7,0xAF,0x9F ;"7"dt 0xC9,0xB6,0xB6,0xB6,0xC9 ;"8"dt 0xCF,0xB6,0xB6,0xB5,0xC3 ;"9"dt 0xFF,0xC9,0xC9,0xFF,0xFF ;":"

Char_tbl_end;--------; SUBROUTINES STARTING HERE;--------; clear important bits of ram;--------Ram_init movlw 0x07

movwf keysmovlw 0x12 ;why do clocks always startmovwf hours ;at 12:00 ?clrf minutesclrf dot_indexclrf digit_indexmovlw 0xFCmovwf bigtick_dblretlw 0

;--------

Page 6: The propeller

; unused pins I am setting to be outputs;--------Port_init movlw 0x00 ;all output, b7=unused

tris PORTB ;on port b attached to LEDsmovlw b'00010111' ;port a has 5 pins. I need 4 inputs

;b0=minutes, b1=10mins, b2=hours;b3=unused, b4=rotation index

tris PORTA ;on port aretlw 0

;--------; get timer-based interrupts going;--------Timer_init bcf INTCON,2 ;clear TMR0 int flag

bsf INTCON,7 ;enable global interruptsbsf INTCON,5 ;enable TMR0 intclrf TMR0 ;clear timerclrwdt ;why is this needed? just do it..movlw b'11011000' ;set up timer. prescaler(bit3)bypassed option ;send w to option. generate warning.clrf TMR0 ;start timerretlw 0

;--------; test for index in rotation and store period in period_dup;--------Check_index movf PORTA,w ;get the state of port a

xorwf flags,w ;compare with saved stateandlw b'00010000' ;only interested in bit 4btfsc STATUS,Z ;test for edgeretlw 0 ;not an edge, same as lastxorwf flags,f ;save for next timebtfsc flags,4 ;test for falling edgeretlw 0 ;must have been a rising edgemovf period_count,w ;make a working copymovwf period_dup ;called period dupclrf period_count ;a fresh start for next rotationclrf digit_index ;set to first digitclrf dot_index ;first column

; calculate a period that does not dither or jitter; period will not be changed unless new period is really different

movf period_calc,wsubwf period_dup,w ;find differencebtfss STATUS,C ;carry flag set means no borrowgoto Calc_period_neg;must be other waysublw 2 ;allowable deviation = 3btfss STATUS,C ;borrow won't skipincf period_calc ;new value much larger than calcretlw 0

Calc_period_negaddlw 2 ;allowable deviation = 3btfss STATUS,C ;carry will skipdecf period_calc ;no carry means it must be changedretlw 0

;--------; change LED pattern based on state of digit_index and dot_index;--------Display_now movlw 0x05

xorwf dot_index,w ;test for end of digitmovlw 0xFF ;pattern for blank column

Page 7: The propeller

btfsc STATUS,Zgoto D_lookup_3 ;it needs a blankbcf STATUS,C ;clear carry before a rotaterlf digit_index,w ;double the index because eachaddwf PCL,f ;takes two instructions

D_10hr swapf hours,wgoto D_lookup ;what a great rush of power

D_1hr movf hours,w ;I feel when modifyinggoto D_lookup ;the program counter

D_colon movlw 0x0Agoto D_lookup

D_10min swapf minutes,wgoto D_lookup

D_1min movf minutes,wgoto D_lookup

D_nothing retlw 0D_lookup andlw b'00001111' ;strip off hi bits

movwf scratch ;multiply this by 5 for lookupaddwf scratch,f ;table base positionaddwf scratch,f ;is this cheating?addwf scratch,f ;I think not.addwf scratch,f ;I think it is conserving energy!btfss STATUS,Z ;test for zerogoto D_lookup_2 ;not a zeromovf digit_index,f ;this is just to test/set flagmovlw 0xFF ;this makes a blank LED patternbtfsc STATUS,Z ;test if it is 10 hrs digitgoto D_lookup_3 ;it's a leading zero

D_lookup_2 movf dot_index,w ;get columnaddwf scratch,w ;add it to digit basecall Char_tbl ;get the dot pattern for this column

D_lookup_3 movwf PORTB ;send it to the LEDsmovlw 0x0C ;overhead value sub from periodsubwf period_calc,w ;compensate for overhead and setcall Delay ;width of digits with this delayincf dot_index,f ;increment to the next columnmovlw 0x06 ;6 columns is a digit plus spacexorwf dot_index,w ;next digit testbtfss STATUS,Zretlw 0 ;not a new digitclrf dot_index ;new digit timeincf digit_index,fretlw 0 ;Display_now done.

;--------; a short delay routine;--------Delay movwf tickDelay_loop decfsz tick,f

goto Delay_loop ;w is not damaged, so Delay canreturn ;be recalled without reloading

;--------; test for keypress and call time adjust if needed;--------Check_keys movf PORTA,w ;get port "a"

xorwf keys,w ;compare with previousandlw b'00000111' ;only care about button pinsbtfsc STATUS,Z ;zero set=no buttons

Page 8: The propeller

retlw 0 ;returnxorwf keys,f ;store key valuemovlw 0x64 ;a fairly long delay willmovwf scratch ;prevent key bounces

Key_delay movlw 0xFFcall Delaydecfsz scratchgoto Key_delaybtfss keys,2 ;test "minutes" buttongoto Inc_minsbtfss keys,1 ;test "tens" buttongoto Inc_tensbtfss keys,0 ;test "hours" buttongoto Inc_hoursretlw 0 ;must be a glitch. yeah, right!

;--------; increment ten minutes;--------Inc_tens movlw 0x0A

movwf scratch ;scratch has tenInc_tens_loop call Inc_mins

decfsz scratchgoto Inc_tens_loop ;another minute addedretlw 0

;--------; increment one hour;--------Inc_hours movlw 0x12

xorwf hours,wbtfsc STATUS,Zgoto Inc_hours_12movlw 0x07 ;this part gets a little sloppyaddwf hours,wmovlw 0x07btfss STATUS,DCmovlw 1addwf hours,fretlw 0

Inc_hours_12 movlw 0x01movwf hoursretlw 0

;--------; increment the time based on flags,1 as sent by interrupt routine; Inc_mins loop also used by time-setting routine;--------Keep_time btfss flags,1 ;the minutes flag

retlw 0 ;not this timebcf flags,1 ;clear the minutes flag

Inc_mins movlw 0x07 ;start incrementing timeaddwf minutes,w ;add 7 minutes into wbtfsc STATUS,DC ;did adding 7 cause digit carry?goto Sixty_mins ;then test for an hour changeincf minutes ;otherwise add 1 for realretlw 0 ;and go back

Sixty_mins movwf minutes ;save the minutesmovlw 0x60 ;test for 60xorwf minutes,w ;are minutes at 60?

Page 9: The propeller

btfss STATUS,Zretlw 0 ;no? go backclrf minutes ;otherwise zero minutesgoto Inc_hours ;and increment hours

;--------; End of subroutines; Program starts here;--------Start call Ram_init ;set variables to nice values

call Port_init ;set port directionscall Timer_init ;start timer based interrupt

;--------; Done initializing, start the endless loop.;--------;Circle ;begin the big loop;;--------; detect falling edge on PORTA,4 to determine rotary index; calculate rotation period and store in period_dup; compare with working period(period_calc) and adjust if way different;--------

call Check_index;--------; check display state and change if needed;--------

call Display_now;--------; check keyboard and adjust time;--------

call Check_keys;--------; check minute flag and increment time if a minute has passed;--------

call Keep_time;--------; gentlemen, that's a clock, keep it rolling;--------

goto Circle ;you heard the man, get going!end

;--------; end of file;--------

Hex:020000040000FA:10000000F028FF3FFF3FFF3F8C00030E8D00640090:100010008E0A03198E03980A0319970A0319960F7B:100020001828FC3096006C309700793098009114B5:100030000D0E83008C0E0C0E0B1109008207C134CB:10004000BE34BE34BE34C134FF34DE348034FE34BA:10005000FF34DE34BC34BA34B634CE34BD34BE34AE:10006000AE349634B934F334EB34DB348034FB34BF

Page 10: The propeller

:100070008D34AE34AE34AE34B134E134D634B6342B:10008000B634F934BF34B834B734AF349F34C934DC:10009000B634B634B634C934CF34B634B634B534E5:1000A000C334FF34C934C934FF34FF3407309900F6:1000B00012309400950192019301FC3096000034B7:1000C000003066001730650000340B118B178B165B:1000D00081016400D83062008101003405081106F6:1000E0001039031900349106111A00340E088F00DC:1000F0008E019301920110080F02031C8328023C19:10010000031C900A0034023E031C900300340530A7:100110001206FF300319A9280310130D8207140ECD:100120009A2814089A280A309A28150E9A28150831:100130009A2800340F399A009A079A079A079A0763:10014000031DA6289308FF300319A92812081A07CF:100150001E2086000C301002B520920A06301206CE:10016000031D00349201930A00349B009B0BB628B8:100170000800050819060739031900349906643088:100180009A00FF30B5209A0BC128191DE328991C4D:10019000CC28191CD22800340A309A00E3209A0B8C:1001A000CE280034123014060319DD280730140756:1001B0000730831C01309407003401309400003470:1001C000911C00349110073015078318E928950A0F:1001D0000034950060301506031D00349501D228C7:1001E0005620602065206E208720B920E020F3286B:0201F000FF3FCF:02400E00F53F7C:00000001FF

Page 11: The propeller
Page 12: The propeller