; This programme controls the driving of the servo motors used to switch the turn outs.
; It is intended to be a universal programme, suitable for any make of turn out. As
; such, it includes the capability to programme different limits for the length of
; travel, and then adjust the actual end stops manually once the assembly is in place.
; The servo can be mounted either on the PCB or remotely.
#PICAXE 14M2
; Define the PICAXE port directions.
LET dirsB = %00111111 ; [0] is the serial data output, routed to the PICAXE socket,
; [1] is unused and unconnected, set as an output,
; [2] is the PWM output to the servo,
; [3] is the active low yellow LED driver,
; [4] is the active low green LED driver,
; [5] is the control for the isolation switch.
LET dirsC = %00011000 ; [0] is the control input either from the P module or directly from the switch,
; [1] is the adjust decrease input,
; [2] is the adjust increase input,
; [3] is unused and tied to zero volts,
; [4] is unused and unconnected, set as an output,
; [5] is the serial data input, routed from the PICAXE socket.
; Symbol definitions for the ports.
SYMBOL ServoPin = B.2
SYMBOL OpMode = pinB.3 ; 0 = adjust (yellow LED on), 1 = normal operation (yellow LED off)
SYMBOL AdjustGo = pinB.4 ; 0 = adjustment may be made (green LED on), 1 = do not adjust (green LED off)
SYMBOL IsoDrvPin = pinB.5
SYMBOL ControlPin = pinC.0
SYMBOL AdjDecPin = pinC.1
SYMBOL AdjIncPin = pinC.2
; Symbol definitions for the variables.
SYMBOL ServoCtrl0End = b4
SYMBOL ServoCtrl1End = b5
SYMBOL ServoMidpoint = b6
SYMBOL ServoCount = b7
SYMBOL PortCAct = b8
SYMBOL PortCPrev = b9
SYMBOL CtrlSw = b10
SYMBOL AdjButtons = b11
SYMBOL Temp2 = b25
SYMBOL Temp1 = b26
SYMBOL Temp0 = b27
; Define a macro that drives the servo to a value by counting up...
#MACRO ServoSetUp(StartVal, EndVal, Counter)
FOR Counter = StartVal TO EndVal STEP 1
SERVOPOS ServoPin, Counter
PAUSE ServoDelay
NEXT Counter
LET StartVal = EndVal
#ENDMACRO
; ...and a second macro that does the same thing by counting down...
#MACRO ServoSetDown(StartVal, EndVal, Counter)
FOR Counter = StartVal TO EndVal STEP -1
SERVOPOS ServoPin, Counter
PAUSE ServoDelay
NEXT Counter
LET StartVal = EndVal
#ENDMACRO
; ...and a third one that selects in which direction to count depending on the starting values.
#MACRO ServoSet(StartVal, EndVal, Counter)
IF StartVal < EndVal THEN
ServoSetUp(StartVal, EndVal, Counter)
ELSE
ServoSetDown(StartVal, EndVal, Counter)
ENDIF
#ENDMACRO
; Define some handy constants.
SYMBOL ServoDelay = 20
SYMBOL ServoInitVal = 150
SYMBOL ServoHalfRange = 50
SYMBOL ServoMinAbs = ServoInitVal - ServoHalfRange
SYMBOL ServoMaxAbs = ServoInitVal + ServoHalfRange
; Load the EEPROM. Definition is byte at a time.
EEPROM 0, (ServoInitVal) ; The actual Ctrl0 servo value, initially set to the default value.
EEPROM 1, (ServoInitVal) ; The actual Ctrl1 servo value, initially set to the default value.
EEPROM 2, (ServoInitVal) ; The actual midpoint servo value, initially set to the default value.
; Set the unused outputs low.
LET pinB.1 = 0
LET pinC.4 = 0
; Force the yellow and green LEDs off.
LET OpMode = 1
LET AdjustGo = 1
; Load the servo end point and midpoint values into their respective registers.
READ 0, ServoCtrl0End
READ 1, ServoCtrl1End
READ 2, ServoMidpoint
; Start the pulsing for the servo motors.
IF ControlPin = 0 THEN
LET ServoCount = ServoCtrl0End
ELSE
LET ServoCount = ServoCtrl1End
ENDIF
SERVO ServoPin, ServoCount
; Set the isolation switch.
LET IsoDrvPin = ControlPin
; Test whether the end point values are still at their default values. If so, go to the adjusting routine.
IF ServoCtrl0End = ServoInitVal OR ServoCtrl1End = ServoInitVal THEN
PAUSE 500
LET TIME = 0
GOSUB task_adjust_servo_end_points
ENDIF
GOTO main_programme
task_adjust_servo_end_points:
LET OpMode = 0
DO
PAUSE 1
LOOP UNTIL AdjDecPin = 0 AND AdjIncPin = 0
LET IsoDrvPin = ControlPin
LET AdjustGo = 0
LET TIME = 0
DO WHILE TIME < 10
IF ControlPin = 0 THEN
LET IsoDrvPin = ControlPin
IF AdjDecPin = 1 THEN
LET ServoCtrl0End = ServoCtrl0End - 1 MIN ServoMinAbs
ENDIF
IF AdjIncPin = 1 THEN
LET ServoCtrl0End = ServoCtrl0End + 1 MAX ServoMaxAbs
ENDIF
ServoSet(ServoCount, ServoCtrl0End, Temp0)
FOR Temp0 = 0 TO 3
PAUSE ServoDelay
NEXT Temp0
SETINT NOT 0x00, 0x07
ENDIF
IF ControlPin = 1 THEN
LET IsoDrvPin = ControlPin
IF AdjDecPin = 1 THEN
LET ServoCtrl1End = ServoCtrl1End - 1 MIN ServoMinAbs
ENDIF
IF AdjIncPin = 1 THEN
LET ServoCtrl1End = ServoCtrl1End + 1 MAX ServoMaxAbs
ENDIF
ServoSet(ServoCount, ServoCtrl1End, Temp0)
FOR Temp0 = 0 TO 3
PAUSE ServoDelay
NEXT Temp0
SETINT NOT 0x01, 0x07
ENDIF
LOOP
LET ServoMidpoint = ServoCtrl0End + ServoCtrl1End / 2
WRITE 0, ServoCtrl0End
WRITE 1, ServoCtrl1End
WRITE 2, ServoMidpoint
LET AdjustGo = 1
LET OpMode = 1
RETURN
main_programme:
SETINT AND 0x06, 0x06
DO
LET PortCAct = pinsC AND 0x07
LET CtrlSw = PortCAct XOR PortCPrev AND 0x01
IF CtrlSw <> 0x00 THEN
ServoSet(ServoCount, ServoMidpoint, Temp1)
LET IsoDrvPin = ControlPin
IF ControlPin = 0 THEN
ServoSet(ServoCount, ServoCtrl0End, Temp1)
ELSE
ServoSet(ServoCount, ServoCtrl1End, Temp1)
ENDIF
ENDIF
LET AdjButtons = PortCAct XOR PortCPrev AND 0x06
IF AdjButtons <> 0x00 THEN
IF AdjDecPin = 1 AND AdjIncPin = 1 THEN
SETINT NOT 0x06, 0x06
ELSE
SETINT 0x06, 0x06
ENDIF
ENDIF
IF AdjDecPin = 1 AND AdjIncPin = 1 AND TIME > 1 THEN
GOSUB task_adjust_servo_end_points
ENDIF
PortCPrev = PortCAct
LOOP
interrupt:
LET TIME = 0
RETURN