' ========================================================================= ' ' File...... ' Purpose... ' Author.... Duncan McRee ' Copyright (c) 2009 Tam Valley Depot ' All Rights Reserved ' E-mail.... dmcree@san.rr.com ' Started... 12/8/2008 ' Updated... ' ' ========================================================================= ' ------------------------------------------------------------------------- ' Program Description ' ------------------------------------------------------------------------- ' Circuit for for controlling 4 turnouts driven by servos and controlled from 4 SPST switches. ' The servos are ordinary R/C plane type. It will work well as is for Futaba and HiTec and ' related brands. ' Inputs: Can be powered from DCC or any AC or DC power supply above 6.5 volts ' SPDT buttons on fascia for manual control ' 3 jumpers for programming ' PRG1 - Center the servos for ease of installation ' PRG2 - range 1 ' PRG3 - range 2 - Set the range of the servos - 4 possible ranges ' 0 0 - smallest - approximately +/- 5 degrees ' 1 1 - full ' Outputs: 4 Servo PWM signal .9 ms - 1.5 ms at a 20ms frame rate ' 4 SPDT relay - Switched track power for points (may be left off if not needed) ' 4 TTL logic signals for panel lights or for using in control systems ' A status LED that flashes to give indications of program status ' LED flashes ' Startup - 1 flash ' Address sucessfully decoded - 1 flash ' New address accepted - 3 flashes ' reverse points - 2 flashes ' ' ------------------------------------------------------------------------- ' End Points Table - To override program defaults, edit these values and change UseTable to 1 ' ------------------------------------------------------------------------- UseTable CON 0 ServoCenter CON 144 ' 144 * .0104 ms = 1.50 ms Servo1Thrown CON ServoCenter - 9 ' edit these lines replace the 9 with the desired value Servo1Closed CON ServoCenter + 9 ' to reverse endpoints sense swap the + and - Servo2Thrown CON ServoCenter - 9 Servo2Closed CON ServoCenter + 9 Servo3Thrown CON ServoCenter - 9 Servo3Closed CON ServoCenter + 9 Servo4Thrown CON ServoCenter - 9 Servo4Closed CON ServoCenter + 9 Servo5Thrown CON ServoCenter - 9 Servo5Closed CON ServoCenter + 9 Servo6Thrown CON ServoCenter - 9 Servo6Closed CON ServoCenter + 9 Servo7Thrown CON ServoCenter - 9 Servo7Closed CON ServoCenter + 9 Servo8Thrown CON ServoCenter - 30 Servo8Closed CON ServoCenter + 30 ' stop! ' ------------------------------------------------------------------------- ' Device Settings ' ------------------------------------------------------------------------- ID "8SvDrvr1" DEVICE SX28, OSCXT2, TURBO, STACKX, OPTIONX, BOR26 FREQ 20_000_000 ' ------------------------------------------------------------------------- ' I/O Pins ' ------------------------------------------------------------------------- UnusedRA PIN RA INPUT PULLUP UnusedRB PIN RB INPUT PULLUP UnusedRC PIN RC INPUT PULLUP ' Jumper low to program CenterSet PIN RA.0 INPUT PULLUP ' pull low to program Range0Jmp PIN RA.1 INPUT PULLUP ' To reverse servo endpoints up pull low while switching servo w/ button Range1Jmp PIN RA.2 INPUT PULLUP ' Sets the range the servo traverses from normal to full Range2Jmp PIN RA.3 INPUT PULLUP ' Sets the range the servo traverses from normal to full ' Status LED for verifying operation 'ledStatus PIN RA.3 OUTPUT ' To indicate status to user ' PWM Servo outputs SwServo1 PIN RB.0 OUTPUT ' Points movement SwServo2 PIN RB.1 OUTPUT ' Points movement SwServo3 PIN RB.2 OUTPUT ' Points movement SwServo4 PIN RB.3 OUTPUT ' Points movement SwServo5 PIN RB.4 OUTPUT ' Points movement SwServo6 PIN RB.5 OUTPUT ' Points movement SwServo7 PIN RB.6 OUTPUT ' Points movement SwServo8 PIN RB.7 OUTPUT ' Points movement ' Manual overrides Toggle1 PIN RC.0 INPUT PULLUP ' hi, pull low to change state of servo1 Toggle2 PIN RC.1 INPUT PULLUP ' hi, pull low to change state of 2 Toggle3 PIN RC.2 INPUT PULLUP ' hi, pull low to change state of 3 Toggle4 PIN RC.3 INPUT PULLUP ' hi, pull low to change state of 4 Toggle5 PIN RC.4 INPUT PULLUP ' hi, pull low to change state of 5 Toggle6 PIN RC.5 INPUT PULLUP ' hi, pull low to change state of 6 Toggle7 PIN RC.6 INPUT PULLUP ' hi, pull low to change state of 7 Toggle8 PIN RC.7 INPUT PULLUP ' hi, pull low to change state of 8 ' ------------------------------------------------------------------------- ' Constants ' ------------------------------------------------------------------------- VersionNo CON $10 ' servo timers ------------------- TimerHi CON 10 ' 10 * 192 * .0104ms = 19.97 ms TimerLo CON 192 ' Servo frame rate 'ServoCenter CON 144 ' 144 * .0104 ms = 1.50 ms ServoMax CON 86 ' .9 ms ServoMin CON 202 ' 2.1 ms Sw000Right CON ServoCenter + 4 Sw000Left CON ServoCenter - 4 Sw001Right CON ServoCenter + 6 Sw001Left CON ServoCenter - 6 Sw010Right CON ServoCenter + 9 Sw010Left CON ServoCenter - 9 Sw011Right CON ServoCenter + 14 Sw011Left CON ServoCenter - 14 Sw100Right CON ServoCenter + 20 Sw100Left CON ServoCenter - 20 Sw101Right CON ServoCenter + 36 Sw101Left CON ServoCenter - 36 Sw110Right CON ServoCenter + 47 Sw110Left CON ServoCenter - 47 Sw111Right CON ServoMin Sw111Left CON ServoMax ' true or false ----------------- SumErr CON 0 NoErr CON 1 M_Run CON 1 M_Program CON 0 ShortRange CON 0 FullRange CON 1 Pressed CON 0 NotPressed CON 1 Armed CON 1 NotArmed CON 0 Closed CON 1 Thrown CON 0 ' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- idx1 VAR Byte ' loop control tmpB1 VAR Byte ' subroutine work vars tmpB2 VAR Byte tmpB3 VAR Byte tmpW1 VAR Word flags VAR BYTE ackNak VAR flags.0 ' for I2C routines servosOn VAR flags.1 ' used to suppress ervo opreation until system ready range0On VAR flags.2 range1On VAR flags.3 centerOn VAR flags.4 servoMove VAR flags.5 ' used to indicate servos ready for next move range2On VAR flags.6 servoState VAR Byte S1State VAR servoState.0 S2State VAR servoState.1 S3State VAR servoState.2 S4State VAR servoState.3 S5State VAR servoState.4 S6State VAR servoState.5 S7State VAR servoState.6 S8State VAR servoState.7 servoConfig VAR Byte (16) servo1Pulse VAR servoConfig (0) servo2Pulse VAR servoConfig (1) servo3Pulse VAR servoConfig (2) servo4Pulse VAR servoConfig (3) servo5Pulse VAR servoConfig (4) servo6Pulse VAR servoConfig (5) servo7Pulse VAR servoConfig (6) servo8Pulse VAR servoConfig (7) sPos1 VAR servoConfig (8) sPos2 VAR servoConfig (9) sPos3 VAR servoConfig (10) sPos4 VAR servoConfig (11) sPos5 VAR servoConfig (12) sPos6 VAR servoConfig (13) sPos7 VAR servoConfig (14) sPos8 VAR servoConfig (15) servoEndPoints VAR Byte (16) servoThrown VAR servoEndPoints (0) ' values of servo timer closed and thrown servoClosed VAR servoEndPoints (1) timerData VAR Byte (16) Timer20L VAR timerData (0) Timer20H VAR timerData (1) range0Timer VAR timerData (2) centerTimer VAR timerData (3) range1Timer VAR timerData (4) sTimer1 VAR timerData (5) sTimer2 VAR timerData (6) sTimer3 VAR timerData (7) sTimer4 VAR timerData (8) sTimer5 VAR timerData (9) sTimer6 VAR timerData (10) sTimer7 VAR timerData (11) sTimer8 VAR timerData (12) range2Timer VAR timerData (13) ' ========================================================================= INTERRUPT 96_000 ' 10.4 useconds ' ========================================================================= ISR_Start: GOTO Interrupt_Handler ' ========================================================================= ' Subroutine / Function Declarations ' ========================================================================= DELAY SUB 1, 2 ' delay in milliseconds CHECK_BUTTONS SUB 0 SET_SERVOS SUB 0 GET_SERVO FUNC 1,2 MOVE_SERVOS SUB 0 MOVE_SERVOS_NOW SUB 0 READ_TABLE SUB 0 GET_BIT SUB 2 ' ========================================================================= PROGRAM Start ' ========================================================================= Start: timer20L = TimerLo timer20H = TimerHi READ_TABLE CHECK_BUTTONS SET_SERVOS MOVE_SERVOS_NOW servosOn = 1 Main: CHECK_BUTTONS IF servoMove = 1 THEN MOVE_SERVOS servoMove = 0 ENDIF GOTO Main ' ------------------------------------------------------------------------- ' Subroutine / Function Code ' ------------------------------------------------------------------------- ' Usage: svalue = GET_SERVO switch_state, reverseflag FUNC GET_SERVO IF __PARAM1 = Thrown THEN IF __PARAM2 = 0 THEN tmpB1 = servoThrown ELSE tmpB1 = servoClosed ENDIF ELSE IF __PARAM2 = 0 THEN tmpB1 = servoClosed ELSE tmpB1 = servoThrown ENDIF ENDIF RETURN tmpB1 ENDFUNC ' ------------------------------------------ ' ' Checks to switches - a pulse toggles state SUB CHECK_BUTTONS IF centerTimer > 9 THEN centerOn = 1 ELSE centerOn = 0 ENDIF IF range0Timer > 9 THEN Range0On = 1 ELSE Range0On = 0 ENDIF IF range1Timer > 9 THEN range1On = 1 ELSE range1On = 0 ENDIF IF range2Timer > 9 THEN range2On = 1 ELSE range2On = 0 ENDIF IF centerOn = 1 THEN servo1Pulse = ServoCenter servo2Pulse = ServoCenter servo3Pulse = ServoCenter servo4Pulse = ServoCenter servo5Pulse = ServoCenter servo6Pulse = ServoCenter servo7Pulse = ServoCenter servo8Pulse = ServoCenter ELSE servoState = RC SET_SERVOS ENDIF ENDSUB GOTO Main ' ----------------------------------------------- ' ' Sets servos according to servoState ' SUB SET_SERVOS tmpB1 = UseTable IF tmpB1 = 0 THEN tmpB2 = range2On tmpB2 = tmpB2 * 4 tmpB1 = range1On tmpB1 = tmpB1 * 2 tmpB1 = tmpB1 + tmpB2 tmpB1 = tmpB1 + range0On ' i.e. 4*range2on + 2* range1On + range0On BRANCH tmpB1, R000, R001, R010, R011, R100, R101, R110, R111 R000: servoThrown = Sw000Left servoClosed = Sw000Right GOTO Set_Pulse R001: servoThrown = Sw001Left servoClosed = Sw001Right GOTO Set_Pulse R010: servoThrown = Sw010Left servoClosed = Sw010Right GOTO Set_Pulse R011: servoThrown = Sw011Left servoClosed = Sw011Right R100: servoThrown = Sw100Left servoClosed = Sw100Right GOTO Set_Pulse R101: servoThrown = Sw101Left servoClosed = Sw101Right GOTO Set_Pulse R110: servoThrown = Sw110Left servoClosed = Sw110Right GOTO Set_Pulse R111: servoThrown = Sw111Left servoClosed = Sw111Right Set_Pulse: servo1Pulse = GET_SERVO s1State, 0 servo2Pulse = GET_SERVO s2State, 0 servo3Pulse = GET_SERVO s3State, 0 servo4Pulse = GET_SERVO s4State, 0 servo5Pulse = GET_SERVO s5State, 0 servo6Pulse = GET_SERVO s6State, 0 servo7Pulse = GET_SERVO s7State, 0 servo8Pulse = GET_SERVO s8State, 0 ELSE ' use the values from the servoEndPoints table previously set in the include file FOR idx1 = 0 TO 7 tmpB2 = idx1 * 2 BRANCH idx1, GetBit0, GetBit1, GetBit2, GetBit3, GetBit4, GetBit5, GetBit6, GetBit7 GetBit0: tmpB1 = s1State GOTO GetBitDone GetBit1: tmpB1 = s2State GOTO GetBitDone GetBit2: tmpB1 = s3State GOTO GetBitDone GetBit3: tmpB1 = s4State GOTO GetBitDone GetBit4: tmpB1 = s5State GOTO GetBitDone GetBit5: tmpB1 = s6State GOTO GetBitDone GetBit6: tmpB1 = s7State GOTO GetBitDone GetBit7: tmpB1 = s8State GetBitDOne: IF tmpB1 <> Thrown THEN ' if thrown use the idx1*2 else use idx1*2+1 position in table INC tmpB2 ENDIF servoConfig(idx1) = servoEndPoints(tmpB2) NEXT ENDIF ENDSUB GOTO Main SUB GET_BIT ENDSUB ' MOVE_SERVOS - moves the towards their target according to ' sPosx - where servo x is now ' servoxPulse - where servo is going to ' reoutie compares the 2 and inc/dec the servo as needed SUB MOVE_SERVOS IF sPos1 < servo1Pulse THEN INC sPos1 ELSEIF sPos1 > servo1Pulse THEN DEC sPos1 ENDIF IF sPos2 < servo2Pulse THEN INC sPos2 ELSEIF sPos2 > servo2Pulse THEN DEC sPos2 ENDIF IF sPos3 < servo3Pulse THEN INC sPos3 ELSEIF sPos3 > servo3Pulse THEN DEC sPos3 ENDIF IF sPos4 < servo4Pulse THEN INC sPos4 ELSEIF sPos4 > servo4Pulse THEN DEC sPos4 ENDIF IF sPos5 < servo5Pulse THEN INC sPos5 ELSEIF sPos5 > servo5Pulse THEN DEC sPos5 ENDIF IF sPos6 < servo6Pulse THEN INC sPos6 ELSEIF sPos6 > servo6Pulse THEN DEC sPos6 ENDIF IF sPos7 < servo7Pulse THEN INC sPos7 ELSEIF sPos7 > servo7Pulse THEN DEC sPos7 ENDIF IF sPos8 < servo8Pulse THEN INC sPos8 ELSEIF sPos8 > servo8Pulse THEN DEC sPos8 ENDIF ENDSUB ' MOVE_SERVOS_NOW - moves the servo to the target with no intermediate steps ' sPosx - where servo x is now ' servoxPulse - where servo is going to ' reoutie compares the 2 and inc/dec the servo as needed SUB MOVE_SERVOS_NOW sPos1 = servo1Pulse sPos2 = servo2Pulse sPos3 = servo3Pulse sPos4 = servo4Pulse sPos5 = servo5Pulse sPos6 = servo6Pulse sPos7 = servo7Pulse sPos8 = servo8Pulse ENDSUB SUB READ_TABLE ServoEndPoints(0) = Servo1Thrown ServoEndPoints(1) = Servo1Closed ServoEndPoints(2) = Servo2Thrown ServoEndPoints(3) = Servo2Closed ServoEndPoints(4) = Servo3Thrown ServoEndPoints(5) = Servo3Closed ServoEndPoints(6) = Servo4Thrown ServoEndPoints(7) = Servo4Closed ServoEndPoints(8) = Servo5Thrown ServoEndPoints(9) = Servo5Closed ServoEndPoints(10) = Servo6Thrown ServoEndPoints(11) = Servo6Closed ServoEndPoints(12) = Servo7Thrown ServoEndPoints(13) = Servo7Closed ServoEndPoints(14) = Servo8Thrown ServoEndPoints(15) = Servo8Closed ENDSUB GOTO Main ' ------------------------------------------------------------------------- ' Use: DELAY in 26 ms increments ' -- delay x ticks ' -- small codewise but very inaccurate ' -- DON'T USE IF TIMING CRITICAL SUB DELAY IF __PARAMCNT = 1 THEN tmpW1 = __PARAM1 ' save byte value ELSE tmpW1 = __WPARAM12 ' save word value ENDIF PAUSE tmpW1 ENDSUB GOTO Main ' ------------------------------------------------------------------------- ASM ORG $06E0 ENDASM Interrupt_Handler: Servo: ASM sb servosOn ' check to see if servos active jmp ExitServo BANK timerData sb swServo1 jmp :Done1 dec sTimer1 sz jmp :Done1 clrb swServo1 MOV FSR,#sPos1 ; sTimer1 = sPos1 MOV __PARAM2,IND MOV FSR,#sTimer1 MOV IND,__PARAM2 :Done1 BANK timerData sb swServo2 jmp :Done2 dec sTimer2 sz jmp :Done2 clrb swServo2 MOV FSR,#sPos2 ; sTimer2 = sPos2 MOV __PARAM2,IND MOV FSR,#sTimer2 MOV IND,__PARAM2 :Done2 BANK timerData sb swServo3 jmp :Done3 dec sTimer3 sz jmp :Done3 clrb swServo3 MOV FSR,#sPos3 ; sTimer3 = sPos3 MOV __PARAM2,IND MOV FSR,#sTimer3 MOV IND,__PARAM2 :Done3 BANK timerData sb swServo4 jmp :Done4 dec sTimer4 sz jmp :Done4 clrb swServo4 MOV FSR,#sPos4 ; sTimer4 = sPos4 MOV __PARAM2,IND MOV FSR,#sTimer4 MOV IND,__PARAM2 :Done4 BANK timerData sb swServo5 jmp :Done5 dec sTimer5 sz jmp :Done5 clrb swServo5 MOV FSR,#sPos5 MOV __PARAM2,IND MOV FSR,#sTimer5 MOV IND,__PARAM2 :Done5 BANK timerData sb swServo6 jmp :Done6 dec sTimer6 sz jmp :Done6 clrb swServo6 MOV FSR,#sPos6 MOV __PARAM2,IND MOV FSR,#sTimer6 MOV IND,__PARAM2 :Done6 BANK timerData sb swServo7 jmp :Done7 dec sTimer7 sz jmp :Done7 clrb swServo7 MOV FSR,#sPos7 MOV __PARAM2,IND MOV FSR,#sTimer7 MOV IND,__PARAM2 :Done7 BANK timerData sb swServo8 jmp :Done8 dec sTimer8 sz jmp :Done8 clrb swServo8 MOV FSR,#sPos8 MOV __PARAM2,IND MOV FSR,#sTimer8 MOV IND,__PARAM2 :Done8 :Timer20 BANK timerData dec Timer20L sz jmp ExitServo mov Timer20L, #TimerLo dec Timer20H sz jmp ExitServo mov Timer20H, #TimerHi setb swServo1 setb swServo2 setb swServo3 setb swServo4 setb swServo5 setb swServo6 setb swServo7 setb swServo8 ENDASM BANK 0 servoMove = 1 GOTO ISR_Exit ' only run jumper code if servo code not run ExitServo: Jumpers: IF CenterSet = 0 THEN IF centerTimer < 10 THEN INC centerTimer ENDIF ELSE centerTimer = 0 ENDIF IF Range0Jmp = 0 THEN IF range0Timer < 10 THEN INC range0Timer ENDIF ELSE range0Timer = 0 ENDIF IF Range1Jmp = 0 THEN IF range1Timer < 10 THEN INC range1Timer ENDIF ELSE range1Timer = 0 ENDIF IF Range2Jmp = 0 THEN IF range2Timer < 10 THEN INC range2Timer ENDIF ELSE range2Timer = 0 ENDIF ISR_Exit: BANK 0 RETURNINT ' ========================================================================= ' User Data ' =========================================================================