'******************************************************************* '**************** PICfocus telescope focuser V4.09 ***************** '******************************************************************* '* * '* A fine-control electronic telescope focuser capable of * '* stand-alone (local) and remote PC control. * '* Features: * '* - 10 preset locations stored in non-volatile memory * '* - fast, slow, and single-step movement controls * '* - autofocus capable with an astrocam and AstroSnap software * '* - high-resolution, normal resolution, and hi-torque step modes * '* - power conservation option to power down motor coils after * '* 3 seconds of inactivity * '* - firmware upgradable with in-circuit serial programmer & PC * '* software * '* - "aux" function via PC to control 3 output lines directly * '* or 2 hobby servos (for control of other accessories * '* on PB5|PB6|PB7) * '* * '******************************************************************* ' 'based on a computer controlled stepper motor focuser by Mike Gray 'PIC programming by Steve Arnold 'Special thanks to Mike Gray for his patience and contributions on 'operation and interfacing to AstroSnap. Without his help this project 'wouldn't have made it past the idea stage. ' ' 'Written for PIC 16F88-4MHz internal clock 'Designed for 5 momentary pushbutton inputs (4 hand controller +1 limit switch) 'and a 4-coil unipolar stepper motor ' ' 'The gear ratio is assumed to be between 3:1 and 5:1 from the telescope 'focus knob gear TO the stepper motor shaft. ' 'Switches are assigned to PIC port A as follows: 'A4: full-in limit switch 'A3: PRESET button 'A2: MODE button 'A1: OUT button 'A0: IN button 'note that the presence of the limit switch IS required for operation, as without 'it, there is no reference for either the outer safety limit or the preset. All 'switch input pins of the PIC have a 10k pulldown resistor. Switches are 'active high. ' 'Port B controls the stepper coils and LED 'B0: coil1 (via darlington driver) 'B1: coil2 (via darlington driver) 'B2: coil3 (via darlington driver) 'B3: coil4 (via darlington driver) 'B4: LED (through 220 ohm resistor in series with a variable resistor) 'B5-B7 are unused (B6/B7 can be used for in-circuit programming) ' 'The stepper coils are connected and gearing is oriented so that sequencing 'coil 1-2-3-4 steps the focuser in the OUTWARDS direction. ' 'The hand controller has 4 buttons, and using different combinations gives 'different functions. In addition, all inputs from the hand controller can 'be diode-OR'd with Parallel port inputs from a PC, using Mike Gray's PICFOCUS 'program and AstroSnap for remote PC and autofocus control respectively. ' 'A1=AstroSnap OUT control 'A0=AstroSnap IN control ' ' '********************************************************** '************* Functions are as follows: ****************** '********************************************************** ' 'focusIN at 10 steps per second (astrosnap rate) - press IN button ' 'focusOUT at 10 steps per second (astrosnap rate) - press OUT button ' 'focusIN single step per press - hold MODE while single-pressing IN button ' 'focusOUT single step per press - hold MODE while single-pressing OUT button ' 'focusIN fast at 50 steps per second - hold MODE and press IN for >1 second ' 'focusOUT fast at 50 sps - hold MODE and press OUT for >1 second ' 'cycle mode (1-6) - press and hold MODE for 10 seconds to cycle to the next ' LED will flash (n) times to indicate mode 1-6 ' Modes are as follows: ' 1:half-step constant-power mode (high resolution) ' 2:single-step constant-power mode (normal resolution) ' 3:dual-coil constant-power mode (normal resolutin, hi-torque) ' 4:half-step power-saver mode (high resolution) ' 5:single-step power-saver mode (normal resolution) ' 6:dual-coil power-saver mode (normal resolution, hi-torque) ' 'Store Preset ' press and hold PRESET button, wait for LED to flash times & release ' press and release IN button - LED will turn on steady as an "are you sure?" ' press and hold IN button for 2 seconds to store (LED stays on for this time) ' LED will turn off to confirm stored ' release IN button ' 'Goto Preset ' press and hold PRESET button, wait for LED to flash times ' press OUT and hold BRIEFLY (until LED starts to flash) ' LED will flash times to confirm it's moving to preset ' Stepper will move to the preset location ' LED will flash times AGAIN, to indicate arrival ' 'Reset - press and hold IN and OUT at the same time for 3 seconds ' Stepper will move focuser IN until limit switch is activated ' And then return to PRESET 1 ' 'Reboot - press and hold PRESET and MODE at the same time for 3 seconds ' Erases all presets, resets to half-step constant-power mode ' LED will turn on to prompt user to move focus to desired MAXOUT point ' Once there, press PRESET to continue ' Stepper will move focuser IN until limit switch is activated ' '------------------------------------------------------------------- ' 'From PC control, you can also set output bits PB5, PB6, and PB7 'to control other accessories via the parallel port. This could be 'used for bit control of a 74LS138 1-of-8 decoder, or simply 3 independent 'control lines for simultaneous use. An alternate mode for these is 'servo control, where 1 or 2 servos can be controlled by the PIC. 'PB5 and/or PB6 are used for 'servo outputs in this case, leaving PB7 (and either of PB5/PB6 if unused) 'still available for bit control mode. 'On power-up or reset, these 3 bits are all set to 0. ' ' 'To use these modes, send data nibbles out the 4 parallel lines as follows: ' 'for BIT OUTPUT control mode, 'DDDD '3210 '---- '1111 - enter port output mode (decimal 15) '0000 - bit output mode (decimal 0) 'X765 - bits to be output to PB7, PB6, PB5 ' 'for SERVO control mode, 'DDDD '3210 '---- '1111 - enter port output mode (decimal 15) '001X - servo output mode, servo select bit (decimal 2=PB5, decimal 3=PB6) 'XXXX - most significant nibble of servo control byte 'XXXX - least significant nibble of servo control byte ' 'Note that there is NO "end" signal nibble to terminate serial nibble comm. '***IMPORTANT:*** sending any subsequent command data or pressing a button on 'the handbox will automatically halt an active servo (i.e. - changing the status 'of PB7 via a port output mode command will turn off any servos). ' 'Servo status byte format is as follows (designed around futaba S148 hobby servo): '0-255 = pulsewidth between 600uS and 2.4mS to give full servo motion range. Note 'that a servo modified for continuous rotation will associate this with speed 'control where 0-127 is fast-to-slow in the counterclockwise direction and '129-255 is slow to fast in the clockwise direction. The value of the "center zero" 'point around 128 will depend on the servo and its modification. ' 'The timing for this "serial nibble exchange" is 30mS per nibble. ' '------------------------------------------------------------------- ' 'Upon first time power-up, 'the PIC Is set For half-STEP, constant-power mode, AND the LED lights steadily 'to indicate that the user must manually move the focuser to the "maximum out" 'position that they want accessible by the stepper (before the focus tube falls 'out and causes you grief). Once the focuser is manually moved to this point, 'press the PRESET Button. The motor will proceed to step inwards until it reaches 'the ZERO point limit switch. It then memorizes these positions as maxpoints, and 'stores the reference so presets can be stored in EEPROM. Following this (once 'it reaches the zero point), it will await keypad/computer commands. ' 'After the first time powering up, there is no need to move the focuser out to 'the maxpoint, as it is stored in EEPROM. Subsequent power-ups will move the 'focuser in until the ZERO limit switch is activated, then will proceed to 'preset#1 and await further commands. After 3 seconds of no commands, the 'PIC will automatically power-down the stepper coils to preserve power, 'if the pic is in mode 4,5,or 6 (modes 1,2,and 3 are constant power). ' ' '************************************ '******* BEGIN PICBASIC CODE ******** '************************************ ' 'ASSIGN VARIABLES swstat VAR BYTE 'switch status oldstat VAR BYTE 'previous switch status for comparison offset VAR WORD 'stepper motor coil pattern offset for the ZERO position myst VAR WORD 'stepper coil pattern # incr VAR BYTE 'increment marker decr VAR BYTE 'decrement marker mydelay VAR BYTE 'delay between checks of switch status or steps nadahold VAR WORD 'timer counter for powering down coils if no switches pressed hold VAR BYTE 'timer counter for seeing how long keys are pressed coils VAR BYTE(8) 'coil patterns loaded from EEPROM temp VAR BYTE 'misc variable temp1 VAR BYTE 'ditto preset VAR WORD 'preset location (stored to/retrieved from EEPROM) maxout VAR WORD 'maximum out location (stored to/retrieved from EEPROM) posn VAR WORD 'current position stpmd VAR BYTE 'mode 0,1,or 2 poff VAR BIT 'preset released flag pcount VAR BYTE 'tracks # of times PRESET button pressed ssel VAR BYTE 'temporary variable sdir VAR BYTE 'servo direct byte offignore VAR BIT 'constant coilpower mode mybits VAR BYTE 'user-defined bits status for PB5,6,7 'DEFINE DATA IN EEPROM Data 1,3,2,6,4,12,8,9 'half step sequence (EEPROM 0-7) Data 1,1,2,2,4,4,8,8 'single step sequence (EEPROM 8-15) Data 3,3,6,6,12,12,9,9 'dual coil sequence (EEPROM 16-23) Data 0,0 'maxout (EEPROM 24,25) Data 0,0,0,0,0,0,0,0,0,0'preset1,2,3,4,5 (EEPROM 26,27|28,29|30,31|32,33|34,35) Data 0,0,0,0,0,0,0,0,0,0'preset 6,7,8,9,10 (EEPROM 36,37|38,39|40,41|42,43|44,45) Data 0 'mode (EEPROM 46) '********PROGRAM START******* powerup: 'powerup sequence 'first assign port pins for I/O TRISA=31 'PortA all input TRISB=0 'PortB all output PORTB=0 Clear PORTB.4=1 Pause 1000 PORTB.4=0 Pause 1000 ' Read 24,maxout.BYTE0:Read 25,maxout.BYTE1:Read 46,stpmd GoSub stpmdload IF maxout=0 Then 'first run - prompt the user to twiddle the focuser out PORTB.4=1 'turn on LED userwait: IF (PORTA & 15) <> 8 Then GoTo userwait 'and wait until PRESET is pressed PORTB.4=0 'turn off the LED and proceed EndIF GoSub seek0 'go find the zero point IF maxout=0 Then maxout=10000-posn Write 24, maxout.byte0:Write 25, maxout.byte1 EndIF posn=0 'we're at the zero point so let's set the posn to 0 Pause 250 pcount=1 Read 26, preset.BYTE0 'get default preset (#1) Read 27, preset.BYTE1 GoTo recheck 'and move the focuser to that point ' ' ' stpmdload: 'data loading subroutine for stepper coil sequences Write 46, stpmd 'store for future reference IF stpmd>2 Then 'set the constant power flag and revise the mode offignore=1 stpmd=stpmd-3 Else offignore=0 EndIF For temp=0 TO 7 Read (stpmd*8+temp), coils(temp) Next temp Return ' ' ' seek0: 'subroutine to step inward until you find the zero point (limit switch) IF stpmd>0 Then 'if single step or dual coil, count down by 2's decr=2 Else decr=1 EndIF posn=10000 'arbitrary value to start at find0: 'beginning of loop myst=posn.byte0 & 7 'neat way to figure out the stepper sequence pointer PORTB=coils(myst) 'output the coils Pause 20 'look for the limit switch being pressed IF PORTA.4=1 Then GoTo found0 'we've found it posn=posn-decr 'not found yet, decrement position GoTo find0 'loop around until you get it found0: 'limit switch activated - now carry on offset=myst 'coil pattern table offset for 0 position Return ' ' ' incheck: 'get switch status swstat=PORTA IF PORTA.4=1 Then 'limit switch activated - define 0 point posn=0 offset=myst EndIF swstat=swstat & 15 'now look at the rest of the bits IF swstat>0 Then nadahold=0 IF oldstat<>swstat Then hold=0 'clear hold status if it's a new combo oldstat=swstat 'store for next time reference Branch swstat,[nil,swain,swaout,gorst,cmode,smodin,smodout,nil,kpreset,nil,nil,nil,rbt,nil,nil,myser] GoTo incheck ' ' ' nil: 'no switches pressed '1000x3ms=3seconds IF nadahold=1000 Then IF offignore=1 Then PORTB=0 | mybits 'turn off coils after timeout pcount=0 'clear PRESET press counter, too long of a delay Else nadahold=nadahold+1 EndIF Pause 3:poff=1:hold=0 'clear tracking variables GoTo incheck ' ' ' swain: 'astrosnap "IN" command & manual slow in mode & preset STORE IF pcount>0 Then GoTo pstr 'go do the preset store routine incr=0:mydelay=100 '10 steps per second GoSub mover 'go on now, git, scram GoTo incheck ' ' ' swaout: 'astrosnap "OUT" command & manual slow out mode & preset RECALL IF pcount>0 Then GoTo prec 'go do the preset recall routine incr=1:mydelay=100 '10 steps per second GoSub mover GoTo incheck ' ' ' gorst: 'check if IN & OUT both held down 3 seconds for reset hold=hold+1 pcount=0 Pause 250 IF hold<12 Then GoTo incheck 'it's not been 3 seconds yet hold=0 GoTo powerup ' ' ' cmode:'cycle through modes - halfstep,singlestep,dualcoil hold=hold+1 pcount=0 Pause 50 IF hold<200 Then GoTo incheck 'hold 10 seconds to change modes Read 46, stpmd stpmd=stpmd+1 'increment mode IF stpmd=6 Then stpmd=0 Write 46, stpmd 'store in EEPROM for later 'now flash the LED to indicate the mode (1-6) For temp=1 TO stpmd+1 GoSub flashb Pause 200 Next temp Pause 500 GoSub stpmdload 'get new sequence table for coil patterns GoTo incheck ' ' ' smodin: 'modified IN command - single step for single press, fast for 2s hold incr=0 GoTo samehere ' ' smodout: 'modified OUT command - single step for single press, fast for 2s hold incr=1 'continues on through ' ' samehere: 'common for modified in and modified out mydelay=250 pcount=0 IF hold<4 Then hold=hold+1 Else mydelay=20 EndIF GoSub mover GoTo incheck ' ' ' rbt: 'hold for 3 seconds for a complete erase and reboot IF hold<12 Then hold=hold+1 Pause 250 GoTo incheck Else 'restore defaults and reboot the sucker For temp=24 TO 46 Write temp, 0 Next temp EndIF GoTo powerup ' ' ' kpreset:'preset button pressed advances every 700mS that it's held IF hold<20 Then '25ms pauses x20=500ms hold=hold+1 Pause 25 GoTo incheck EndIF '500ms has elapsed - increment pcount and flash LED IF pcount<10 Then pcount=pcount+1 GoSub flashb 'flash LED (total time=700ms) hold=0 'reset for next time GoTo incheck ' ' ' pstr: 'preset store PORTB.4=1 'now turn on steady for confirmation and await the IN press&hold Pause 300 'period to allow switch to be released stillwait: 'wait till it's pressed AGAIN temp=PORTA IF temp=0 Then GoTo stillwait 'not pressed yet IF temp <>1 Then 'another button was pressed so exit PORTB.4=0 'turn off LED pcount=0 'reset presses GoTo incheck EndIF 'IN was pressed again, so check to see if it's being HELD long enough Pause 250 'debounce time to eliminate false releases temp=0 timepress: 'loop check 2 seconds temp1=PORTA & 15 IF temp1<>1 Then 'it's another key or no key so EXIT pcount=0:PORTB.4=0 GoTo incheck EndIF temp=temp+1 Pause 250 IF temp<7 Then GoTo timepress 'the IN key was held long enough, so proceed to write into proper memory locn Write (24+2*pcount), posn.BYTE0 Write (25+2*pcount), posn.BYTE1 PORTB.4=0 'turn off prompt LED pcount=0 Pause 1000 'allow user to remove finger without starting MOVE IN sequence GoTo incheck 'done! ' ' ' pflash: 'flash preset number (subroutine) Pause 500 For temp=1 TO pcount PORTB.4=1:Pause 125:PORTB.4=0:Pause 125 Next temp Return ' ' ' flashb: PORTB.4=1:Pause 200:PORTB.4=0 Return ' ' ' prec: 'preset recall GoSub pflash 'flash the LED to say you're on your way IF pcount=0 Then pcount=1 Read (24+2*pcount), preset.BYTE0 Read (25+2*pcount), preset.BYTE1 recheck: IF preset=posn+1 Then GoTo mchek 'check to see if it's halfstep or not IF preset=posn-1 Then GoTo mchek 'ditto chkeq: IF preset=posn Then 'we've arrived - throw a party and invite the neighbors GoSub pflash 'or maybe just flash the preset # pcount=0 GoTo incheck EndIF IF presetposn Then 'set step direction outwards incr=1 EndIF mydelay=20 GoSub mover 'act on the step direction setting, then come back here GoTo recheck 'are we there yet, are we there yet, are we there yet? ' ' ' mchek: 'checks the mode to see if it's double-stepping in or out IF stpmd>0 Then 'we've arrived so do the flashy thing and exit GoSub pflash pcount=0 GoTo incheck Else GoTo chkeq 'go finish checking and comparing and moving EndIF ' ' ' myser: Pause 42 '(already has nibble 0) temp=PORTA & 15 'nibble 1 Pause 30 'for next nibble temp1=PORTA & 15 'nibble 2 - bit status or MSNibble of servoctrl IF temp = 0 Then 'it's a bit set function mybits=temp1<<5 'shift into position PORTB=PORTB | mybits Pause 50 'safety waiting period so it doesn't think it's a button GoTo incheck Else 'it's a servo function Pause 30 'for nibble 3 temp1=temp1 << 4 'shift MSNibble over 4 bits to make room swstat=PORTA & 15 'get LSNibble temp1=temp1 | swstat 'combine nibbles into a byte sdir=temp1*180/255+60 'calculate timing pulse Pause 50 'safety waiting period so data doesn't cause an abort servo: IF temp=2 Then 'servo on PB5 gets the signal (tempB0=select, tempB1=servomode) PulsOut PORTB.5, sdir Else 'servo on PB6 gets the signal PulsOut PORTB.6, sdir EndIF For temp1=1 TO 5 Pause 3 swstat=PORTA & 15 IF swstat>0 Then GoTo incheck Next temp1 GoTo servo EndIF ' ' ' mover: 'sends the update out depending on incr, decr, and mydelay decr=incr ^ 1 IF stpmd>0 Then 'double-step through the table incr=incr*2 decr=decr*2 EndIF IF decr>posn Then GoTo incheck 'will pass the zero point so don't move IF posn+incr > maxout Then GoTo incheck posn=posn+incr-decr 'new position myst=(posn+offset) & 7 'stepper table position PORTB=coils(myst.BYTE0) | mybits Pause mydelay Return 'Version History '4.04 - added version history and version number ' - added "serial nibbles" to define port output functions for PB5,6,7 ' '4.05 - compressed and optimized code ' - added modified servo output control for PB5, PB6 ' - corrected port control output routine for PB5,6,7 ' - changed incr and decr from words to bytes ' - added clear statement at beginning of program ' '4.06 -fixed port control output routine for P5,6,7 (again) ' -changed servo mode to FULL positional control (or speed and direction ' control for modified servos) ' '4.07 -fixed 2 errors in servo output routine ' '4.08 -fixed a problem with the "in full" limit switch disabling ALL movement ' -added more presets for a total of 10 ' '4.09 -changed 100sps to 50sps max speed to reduce "slipping" problem ' -changed time period for changing mode to 10 seconds to eliminate ' accidental mode changes during multiple single-step movements