Successfully reported this slideshow.

The propeller


Published on

ieee projecs

Published in: Education, Business, Technology
  • Be the first to comment

The propeller

  1. 1. 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(motorone has its shaft fixed to a base, and motor two spins the body ofmotor one, generating electricity), making a rotary transformer, orusing slip rings.I decided to do it another way, taking power from the spinningarmature of a plain DC motor. In order to run the wires out of themotor, I removed the bearing from one end of the motor, leaving abig hole.There are three terminals inside most small DC motors, and it actsa lot like three-phase alternating current, so it must be rectifiedback to DC. A nice side effect of this is that the position of themotor can be detected by taking one of the phases straight into themicroprocessor.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 numberRMOTV1007GEZZ. Take it apart without mangling the brushes(there arelittle holes to slip a paperclip into to move the brushes out of theway), 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 theother end of the motor, as an extension of the ball bearing. The shaftof the motor will have to be repositioned slightly to get the rightheight, press it in a vise with a hollow spacer on one end. Take aBerg connector with three wires and solder them to the three terminalson the motors armature. Glue a short threaded spacer to the shaft atthe end that will stick out the hole, and reassemble the motor(becareful with the brushes). You can glue the motor to a VCR head as aweighted base.Step Two: Build the circuit.I used perfboard(Vectorboard) and handwired the circuit together. Usean 18-pin socket for the 16C84 because it needs to be programmedbeforeputting it in the circuit. For the 7 current-limit resistors I used aDIP resistor array, because it made it easy to experiment with LEDbrightness. I settled on 120 ohms. You can use seven regularresistors,because 120 ohms works fine, though it puts the peak current right atthe limit for the 16C84. Think about balance while you build thiscircuit, and reference my pictures, so you dont have to add a lot ofbalancing weight later. Substitute for any part values you like. Notethat I used a 47000uf supercap, it is to keep the clock running afterturning it off, so you can set the time. The LEDs get power separatefrom this. Dont substitute a ceramic resonator for the 4MHz crystal,
  2. 2. this is a clock and should be accurate.Step Three: Program the 16C84.Youll need a programmer that will program a PIC16C84. If you foundthis file/web page, you can find plans to build a 16C84 programmer.Program it using the hex file accompanying this document. I haveincluded the source code(.asm) just for your amusement. Whenprogramming 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 wireconnectorin. Apply power to the motor. The preferred voltage is 6.2 volts, butit will run from 5 volts to about 7.5 volts. Note that 5 volts gets tothe circuit when 6.2 volts is applied to the motor, because of diodelosses. The clock may be working at this point, displaying 12:00. Ifitisnt. there was probably some voltage on the supercap when youpluggedin the chip. Turn off the power and momentarily short pins 5 and 4together(ground and /mclr) to reset the chip. Now when you apply powerthe clock should work, and you can set it by turning off the power andpushing the buttons(hours, 10 minutes, minutes) the right number oftimes. If the numbers appear backwards, reverse the polarity to themotor to make it spin the other way. You might experiment withbalancingthe clock, and the use of foam under the base to reduce vibration.Step Five: Modifications.If you look closely at the source code, youll see that the "dot rate"is adjusted to the speed of the motor to make the display a consistentwidth regardless of the motors speed. The motor I used has brushesset90 degrees apart, and gives two indexes each revolution. The clockdisplays on two sides, 180 degrees apart. If you use a motor with thebrushes 180 apart, the clock will only display on one side, and thenumbers will be too wide. Youll want to modify the program, in thesection marked D_lookup_3. The value in the W register when Delay getscalled effects the width of the digits. You might try sending half ofthe period_calc value to Delay, perhaps by rotating period_calc rightinto W(remember to clear the carry flag first). Like this:bcf STATUS,Crrf period_calc,wcall DelayJanuary 25, 1997 Bob Blickwww.bobblick.comcopyright 1997 Bob Blick, all rights reserved
  3. 3. updated notes November 2, 2006Note: PIC16C84 is now obsolete. You may use either a PIC16F84 orPIC16F84A with no changes.Note: Sharp VCR motor is now obsolete. Use any DC motor, preferablymeant for 12 volts so the speed will not be too great when operatedat approximately 6.2 volts.The Propeller Clock Parts ListCapacitors: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 rectifiersResistors:R1 - 120 ohm DIP array or seven 120 ohm resistorsR2-R6 - 10k ohmMisc:J1 - three terminal Berg connectorSW1-SW3 - normally open pushbutton switchesU1 - PIC16C84, PIC16F84 or PIC16F84AXTAL1 - 4MHz crystalMOTOR - Sharp RMOTV1007GEZZNote: 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,; No warranties expredded or implied; Bob Blick February 18, 2002;-------- list p=16C84 radix hex
  4. 4. include "";--------; 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 Ill look.;--------w equ 0f equ 1;--------; Start of available RAM.;-------- cblock 0x0C safe_w ;not really temp, used by interrupt svc safe_s ;not really temp, used by interrupt svc period_count ;incremented each interrupt period_dup ;copy of period_count safe from interrupt period_calc ;stable period after hysteresis calc. flags ;b2=int b1=minute b4=edge dot_index ;which column is being displayed digit_index ;which digit is being displayed hours ;in display format, not hex(01-12) minutes ;00 to 59 bigtick_dbl ;incremented each interrupt bigtick_hi bigtick_lo keys ;key value scratch ;scratch value tick ;used by delay endc;--------; Start of ROM;-------- org 0x00 ;Start of code space goto Start;--------; INTERRUPT SERVICE ROUTINE;-------- org 0x04 ;interrupt vectorIntsvc movwf safe_w ;save w swapf STATUS,w ;swap status, w movwf 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,f btfsc STATUS,Z ;zero set means overflow decf period_count,f; 234375 interrupts every minute. Increment the bigtick each time. incf bigtick_lo,f btfsc STATUS,Z incf bigtick_hi,f btfsc STATUS,Z
  5. 5. incfsz bigtick_dbl,f goto 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 = 0x039387 movwf bigtick_dbl ;0 - 0x039387 = 0xFC6C79 movlw 0x6C movwf bigtick_hi movlw 0x79 movwf bigtick_lo bsf flags,1 ;notify Keep_timeBigtick_out;--------; done working, start restoring;-------- swapf safe_s,w ;fetch status, reswap nibbles movwf STATUS ;restore status swapf safe_w,f ;swap nibbles in preparation swapf safe_w,w ;for the swap restoration of w bcf INTCON,2 ;clear interrupt flag before return retfie ;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,f dt 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 keys movlw 0x12 ;why do clocks always start movwf hours ;at 12:00 ? clrf minutes clrf dot_index clrf digit_index movlw 0xFC movwf bigtick_dbl retlw 0;--------
  6. 6. ; unused pins I am setting to be outputs;--------Port_init movlw 0x00 ;all output, b7=unused tris PORTB ;on port b attached to LEDs movlw b00010111 ;port a has 5 pins. I need 4 inputs ;b0=minutes, b1=10mins, b2=hours ;b3=unused, b4=rotation index tris PORTA ;on port a retlw 0;--------; get timer-based interrupts going;--------Timer_init bcf INTCON,2 ;clear TMR0 int flag bsf INTCON,7 ;enable global interrupts bsf INTCON,5 ;enable TMR0 int clrf TMR0 ;clear timer clrwdt ;why is this needed? just do it.. movlw b11011000 ;set up timer. prescaler(bit3)bypassed option ;send w to option. generate warning. clrf TMR0 ;start timer retlw 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 state andlw b00010000 ;only interested in bit 4 btfsc STATUS,Z ;test for edge retlw 0 ;not an edge, same as last xorwf flags,f ;save for next time btfsc flags,4 ;test for falling edge retlw 0 ;must have been a rising edge movf period_count,w ;make a working copy movwf period_dup ;called period dup clrf period_count ;a fresh start for next rotation clrf digit_index ;set to first digit clrf 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,w subwf period_dup,w ;find difference btfss STATUS,C ;carry flag set means no borrow goto Calc_period_neg ;must be other way sublw 2 ;allowable deviation = 3 btfss STATUS,C ;borrow wont skip incf period_calc ;new value much larger than calc retlw 0Calc_period_neg addlw 2 ;allowable deviation = 3 btfss STATUS,C ;carry will skip decf period_calc ;no carry means it must be changed retlw 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 digit movlw 0xFF ;pattern for blank column
  7. 7. btfsc STATUS,Z goto D_lookup_3 ;it needs a blank bcf STATUS,C ;clear carry before a rotate rlf digit_index,w ;double the index because each addwf PCL,f ;takes two instructionsD_10hr swapf hours,w goto D_lookup ;what a great rush of powerD_1hr movf hours,w ;I feel when modifying goto D_lookup ;the program counterD_colon movlw 0x0A goto D_lookupD_10min swapf minutes,w goto D_lookupD_1min movf minutes,w goto D_lookupD_nothing retlw 0D_lookup andlw b00001111 ;strip off hi bits movwf scratch ;multiply this by 5 for lookup addwf scratch,f ;table base position addwf 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 zero goto D_lookup_2 ;not a zero movf digit_index,f ;this is just to test/set flag movlw 0xFF ;this makes a blank LED pattern btfsc STATUS,Z ;test if it is 10 hrs digit goto D_lookup_3 ;its a leading zeroD_lookup_2 movf dot_index,w ;get column addwf scratch,w ;add it to digit base call Char_tbl ;get the dot pattern for this columnD_lookup_3 movwf PORTB ;send it to the LEDs movlw 0x0C ;overhead value sub from period subwf period_calc,w ;compensate for overhead and set call Delay ;width of digits with this delay incf dot_index,f ;increment to the next column movlw 0x06 ;6 columns is a digit plus space xorwf dot_index,w ;next digit test btfss STATUS,Z retlw 0 ;not a new digit clrf dot_index ;new digit time incf digit_index,f retlw 0 ;Display_now done.;--------; a short delay routine;--------Delay movwf tickDelay_loop decfsz tick,f goto Delay_loop ;w is not damaged, so Delay can return ;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 previous andlw b00000111 ;only care about button pins btfsc STATUS,Z ;zero set=no buttons
  8. 8. retlw 0 ;return xorwf keys,f ;store key value movlw 0x64 ;a fairly long delay will movwf scratch ;prevent key bouncesKey_delay movlw 0xFF call Delay decfsz scratch goto Key_delay btfss keys,2 ;test "minutes" button goto Inc_mins btfss keys,1 ;test "tens" button goto Inc_tens btfss keys,0 ;test "hours" button goto Inc_hours retlw 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 scratch goto Inc_tens_loop ;another minute added retlw 0;--------; increment one hour;--------Inc_hours movlw 0x12 xorwf hours,w btfsc STATUS,Z goto Inc_hours_12 movlw 0x07 ;this part gets a little sloppy addwf hours,w movlw 0x07 btfss STATUS,DC movlw 1 addwf hours,f retlw 0Inc_hours_12 movlw 0x01 movwf hours retlw 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 time bcf flags,1 ;clear the minutes flagInc_mins movlw 0x07 ;start incrementing time addwf minutes,w ;add 7 minutes into w btfsc STATUS,DC ;did adding 7 cause digit carry? goto Sixty_mins ;then test for an hour change incf minutes ;otherwise add 1 for real retlw 0 ;and go backSixty_mins movwf minutes ;save the minutes movlw 0x60 ;test for 60 xorwf minutes,w ;are minutes at 60?
  9. 9. btfss STATUS,Z retlw 0 ;no? go back clrf minutes ;otherwise zero minutes goto 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 directions call 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, thats 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
  10. 10. :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