PICAXE Model Railroad Speed Controller Software
d. bodnar
revised 11-02-11
Basic Operation
After connecting the controller to a source of DC voltage and connecting its output to the track you can use the following keys on the TV Remote to control the train:
  • Channel UP - Increase speed
  • Channel DOWN - Decrease speed
  • Volume UP - Change direction to forward (if not already going forward)
  • Volume DOWN - Change direction to backwards (if not already going backwards)
  • MENU - stop the train remembering the current speed - press MENU again to restart at the same speed and in the same direction
Step-by-Step Startup as Point-to-Point Using Above Software
  1. Make sure that the IR sensor is not in direct sunlight
    1. OPTIONAL:  Reset all settings
    2. Press RETURN
    3. Press V-Chip
    4. Press EXIT to reset or POWER to abort
  2. Point the IR Remote control towards the controller and press the CH UP button until the trolley / train reaches your preferred MINIMUM speed - I generally set this to a crawl
  3. You can press the VOL UP and VOL DOWN to reverse while testing the minimum speed
  4. Press the MUTE button to set the minimum speed
  5. Press the CH UP button until you reach the preferred MAXIMUM speed
  6. Again you can use the VOL UP and VOL DOWN buttons to reverse while testing
  7. Take note of how many seconds it takes to get from one end of the point-to-point to the other
  8. Press the RETURN button - the trolley / train will stop
  9. Press the NUMBER 3 button - the LED will flash three times
  10. After it has flashed you can type in the 3 digit time (in seconds) that you want the trolley / train to run before reversing.  You MUST enter 3 digits - 009 = 9 seconds, 033 = 33 seconds, 120 = 120 seconds (two minutes), etc.  The maximum time is 255 seconds.
  11. After each digit is entered the LED will flash out its value - you MUST wait for this to happen before entering the next digit.
  12. After the 3 digits have been entered the train will accelerate to top speed and continue for the set number of seconds before decelerating, reversing and speeding up again.
  13. If you have set a minimum speed you can press the POWER button when the trolley / train reaches the point where you want it to decelerate to the minimum speed.  This is generally done a short distance from the end of the point-to-point.

 

Additional Configuration Modes
In addition to mode 3, which was used above in the point-to-point mode, there are three other modes that you can use to set parameters.  To enter Configuration Mode press the RETURN button.  The unit will wait for you to enter 1, 2, 3 or 4.  These numbers select the following configuration modes:
   
1 Change Maximum Speed - the range is 0 to 255 with 255 being fast and 0 being stopped - note that the current speed is flashed out when this is selected.  For example, if the current speed is 187 the blue LED will flash once, then eight times then seven times.  You cannot enter a new value until the old one is flashed out.
2 Change Minimum Speed - the range is 0 to 255 with 255 - the minimum must be less than or equal to the maximum speed
3 Change Run Time - the range is 0 to 255 -  this is the time (in seconds) that the train will run in one direction before slowing, reversing and speeding up to the same speed.  Entering 0 will disable automatic reversing. 
4 Change Acceleration / Deceleration rate - the range is 0 to 255 with 0 being very fast acceleration / deceleration and 255 being very, very slow acceleration / deceleration - the useful range is -0 to about 30.  Beyond 30 the rate is too slow.

NOTE:  when in Auto-Reverse mode you must set minimum speed with OK/MUTE button then return to maximum speed with the CH UP button.  Press POWER to set deceleration time / point. 

Software

'd. bodnar - 11-02-2011 v6.2
#PICAXE 18M2
#TERMINAL 4800

Symbol Direction1 = b.5 'pin 11 - one high & one low - swap to change direction-if = fast motor stop
Symbol Direction2 = b.0 'pin 6 - one high & one low - swap to change direction
Symbol Motor = b.3 'pin 9 - PWM output for motor speed
Symbol IRSense = b.2 'pin 8
Symbol Aux1 = c.2 'pin 1 - can be used for current sensing - OR OTHER PURPOSES!
Symbol Aux4 = c.5 'pin 4 input only
Symbol Aux17 = c.0 'pin 17
Symbol Aux18 = c.1 'pin 18
Symbol LEDAmber = c.6 'pin 15
Symbol LEDBlue = c.7 'pin 16

Symbol InfraRED = b27 'store IR value
symbol Digit = b26 'Flash Value
symbol Value = b25 'Flash Value & Version
Symbol ValueTemp = b24 'Flash Value
symbol divisor = b23 'Flash Value
symbol temp5 = b22 'Flash Value & GetRndOnce
symbol temp = b21 'Flash Value & Version
Symbol CruiseTime = b20 'Time to run before reversing
symbol digitsbyte = b19 'Get number routine
Symbol TempByte = b18 'Flash Value & Version & Get IR Num
Symbol WaitTime = b17 'pause before reverse
Symbol ADRate = b16 'accel / decel rate
Symbol DecelTime = b15 'point where decel beings on p-2-p
Symbol RndmWait = b14 'RANDOM - needed?
Symbol TempWord = w5 'RANDOM - needed?
Symbol Loopie0 = w4 'Decel & Random
Symbol MinSpeed = w3
Symbol SetSpeed = w2
Symbol DecelFlag = Bit0 '=1 if decel time has caused deceleration otherwise =0
Symbol FwdBkwFlag = Bit1 '=1 if forwrad / =0 if backward
Symbol SlowDnFlag = Bit2 '=0 if no slow down point set, =1 if set
Symbol Decel2Zero = Bit3 '=1 if we want deceleration to zero, not minimum speed
'Also Using
'Memory 30 for Decel loop start value (word)
'Memory 32 for Decel loop end value (word)
'Memory 34 for time temp storage (byte)

Symbol LStart = 0'120'450
Symbol TTrigger = 7000
Symbol Period = 150
Symbol PWMMax = 1023'600
Symbol ChUp = 16
Symbol ChDown = 17
Symbol VolUp = 18
Symbol VolDown = 19
Symbol OK = 20
Symbol Retrn = 59
Symbol One = 0
Symbol Two = 1
Symbol Three = 2
Symbol Four = 3
Symbol Five = 4
Symbol Six = 5
Symbol Seven = 6
Symbol Eight = 7
Symbol Nine = 8
Symbol Zero = 9
Symbol Power = 21
Symbol MENU = 96
Symbol VChip = 14
Symbol Exxit = 99
Symbol VerWhole = 6
Symbol VerDecimal = 2
high direction1:low direction2

VeryTop:
Read 0, WORD SetSpeed 'read variables from memory
Read 2, WORD MinSpeed
Read 4, WaitTime
Read 5, ADRate
Read 6, DecelTime
Read 7, RndmWait
Read 8, slowdnflag
if DecelTime=0 then
DecelTime=WaitTime
endif
decelflag=0
if deceltime <> waittime then
decelflag=1
slowdnflag=1
endif

pwmout motor,50,500' set pwm duty
pwmduty motor, 0
Pause 500
sertxd("d. bodnar",13,10,"11-02-2011 v6.2",13,10,13,10) '4800 baud @ this clock speed


;Routine to flash out version number of software
for tempbyte=1 to VerWhole:high LEDBlue:pause 150:low LEDBlue:pause 150:next tempbyte:pause 400
temp=verdecimal
IF temp > 0 then
for tempbyte=1 to VerDecimal:high LEDBlue:pause 150:low LEDBlue:pause 150:next tempbyte
else
high ledblue:pause 10:low ledblue
endif
Pause 1000

GOSUB ShowReadValues
gosub accel
time=0

Cruise:
Random TempWord
if time <=2 then gosub GetRndOnce

'Routine to show time that has passed on Terminal
PEEK 34, TempByte
if time <> TempByte then
sertxd("t=",#time," ")
POKE 34, time
toggle ledamber
endif

'if no auto-reverse (waittime) has been set don't reverse or decel
if waittime=0 then
goto SkipReverse
endif

'Slow down to minspeed if decel point has been set - do it only once via decelflag
if time >= DecelTime and decelflag =0 and DecelTime<>CruiseTime then
sertxd("@deceltime ",#deceltime," f ",#decelflag,13,10)
gosub DecelSet2Min
DecelFlag=1
endif

'Run time has expired - bring to complete stop & reverse
if time >=CruiseTime then
sertxd("Time= ",#time,13,10)
time=0
decelflag=0
goto Revers
endif

SkipReverse:
'Get IR input and act on it
{Infrared=255
Irin [1, Cruise],IrSense, InfraRED
sertxd("IR= ",#infrared," ")

if InfraRED = Power then 'use POWER button to set deleration poing
DecelTime=time
SlowDnFlag=1
Write 6, DecelTime
Write 8, Slowdnflag
gosub ShowReadValues

endif

if InfraRED = OK then 'Mute on Westinghouse Remote - hit it to set minimum speed
MinSpeed=SetSpeed
Write 2, word MinSpeed
Write 8, Slowdnflag
gosub ShowReadValues
endif


if InfraRED = Retrn then GetOption 'after RETURN button choose 1-->4 to set options

if InfraRED = VolUp and FwdBkwFlag =0 then ' VOLUME UP and DOWN to change direction
FwdBkwFlag = 1
goto revers
endif

if InfraRED=VolDown and FwdBkwFlag =1 then ' VOLUME UP and DOWN to change direction
FwdBkwFlag = 0
goto revers
endif

if InfraRed = MENU then 'press MENU to pause & save speed or to restart after pausing
Sertxd("@ MENU",13,10)
if SetSpeed > 0 then
POKE 30,WORD SetSpeed
if MinSpeed <> 0 then
Decel2Zero=1
endif
gosub decel
SetSpeed=0
disabletime
pause 1000
else
PEEK 30, WORD SetSpeed
gosub accel
enabletime
endif
endif

if InfraRED=ChUp then 'CHANNEL UP and DOWN to speed up or down
high LEDBlue
SetSpeed = SetSpeed +5
pwmduty motor,SetSpeed
write 0, WORD SetSpeed
Write 8, Slowdnflag
sertxd(#setspeed,13,10)
else
low LEDBlue
endif

if InfraRED=ChDown then 'CHANNEL UP and DOWN to speed up or down
high LEDBlue
if SetSpeed > 5 then
SetSpeed = SetSpeed -5
sertxd(#setspeed,13,10)
endif
pwmduty motor,SetSpeed
write 0, WORD SetSpeed
Write 8, Slowdnflag
else
low LEDBlue
endif}
goto Cruise:

{
GetRndOnce: 'Put time to run train into Temp
Random TempWord
loopie0=65535/rndmwait
Temp5=tempword/loopie0
CruiseTime=WaitTime+temp5
return

GetOption:
pwmduty motor,0 ; STOP
sertxd("@GetO",13,10)
pause 1000
StayHere2:
Infrared=255
Irin [1, StayHere2],IrSense, InfraRED
sertxd("IR= ",#infrared," ")
if infrared = VChip then
goto ReadyReset:
endif
if infrared >4 then 'only accepts number buttons 1-->4
goto cruise
endif

Branch infrared, (speedmax, speedmin, runtime, acceldecelrate, RndmSetting)
goto cruise

RndmSetting:
value = RndmWait
gosub flashvalue
gosub getirnumber
RndmWait=digitsbyte
sertxd("RndmWait= ",#RndmWait,13,10)
write 7, RndmWait
Write 8, Slowdnflag
gosub ShowReadValues
gosub accel
goto cruise:

speedmax:
value = setspeed
gosub flashvalue
gosub getirnumber
setspeed=digitsbyte
sertxd("max= ",#setspeed,13,10)
write 0, word setspeed
Write 8, Slowdnflag
gosub ShowReadValues
gosub accel
goto cruise:

speedmin:
value = minspeed
gosub flashvalue
gosub getirnumber
minspeed=digitsbyte
sertxd("min= ",#minspeed,13,10)
write 2, word MinSpeed
gosub ShowReadValues
gosub accel
goto cruise:

runtime:
value = waittime
gosub flashvalue
gosub getirnumber
waittime=digitsbyte
write 4, WaitTime
Write 8, Slowdnflag
sertxd("wait= ",#waittime,13,10)
time=0
if DecelTime=0 then
DecelTime=WaitTime
endif
gosub ShowReadValues
gosub accel
goto cruise:

acceldecelrate:
value = adrate
gosub flashvalue
gosub getirnumber
adrate=digitsbyte
write 5, adrate
Write 8, Slowdnflag
gosub ShowReadValues
sertxd("ad= ",#adrate,13,10)
goto cruise:

ReadyReset:
Infrared=255
Irin [1, ReadyReset],IrSense, InfraRED
if infrared = Exxit then DoIt
if infrared = Power then Cruise
goto readyreset
DoIt:
deceltime=0:setspeed=0:minspeed=0:waittime=0:adrate=0:RndmWait=0:slowdnflag=0
Write 0, WORD SetSpeed
Write 2, WORD MinSpeed
Write 4, WaitTime
Write 5, ADRate
Write 6, DecelTime
Write 7, RndmWait
Write 8, slowdnflag
goto VeryTop:

AutoReverse:
for b0=1 to 10:toggle IrSense:pause 100:next b0
goto cruise}

Revers:
sertxd("@Revers",13,10)
Decel2Zero=1
gosub decel
pause 1000
toggle direction1:toggle direction2
gosub accel
goto Cruise:

Accel:
disabletime
sertxd("@Accel",13,10)
for loopie0= 0 to SetSpeed step 5
sertxd(#loopie0," ")
pwmduty motor,loopie0 ; set pwm duty
toggle ledblue
pause adrate
next loopie0
sertxd(13,10)
enabletime
return

Decel:
disabletime
sertxd("@Decel",13,10)
if decelflag=1 then
return
endif
if SlowDnFlag=1 then
for loopie0=minspeed to 0 step -3
gosub DecelLoop:
next loopie0
goto skip0:
endif
if Decel2Zero=1 then
Decel2Zero=0
for loopie0=setspeed to 0 step-3
gosub DecelLoop:
next loopie0
goto skip0:
endif
DecelSet2Min:
sertxd("@DecelSet2Min",13,10)
for loopie0= SetSpeed to MinSpeed step -5
gosub DecelLoop:
next loopie0
Skip0:
sertxd(13,10)
enabletime
low LEDBlue
return

DecelLoop:
toggle LEDBlue
sertxd(#loopie0," ")
pwmduty motor, loopie0
pause adrate
return

FlashValue: 'Flash out current reading
sertxd(13,10,"@FV ",#value,13,10)
ValueTemp=Value
for TempByte= 2 to 0 step -1
if TempByte=2 then
divisor=100
endif
if TempByte=1 then
divisor=10
endif
if TempByte=0 then
divisor=1
endif

Digit=ValueTemp /divisor
sertxd("digit ",#digit," ",13,10)' debug Digit
temp5=Digit * divisor
ValueTemp=ValueTemp - temp5
if Digit=0 then
high LEDBlue:pause 50:low LEDBlue:pause 100:pause 600:goto skipover3:
endif
for temp=1 to Digit
high LEDBlue:pause 200:low LEDBlue:pause 200
next temp
pause 600
SkipOver3:
next TempByte
return

GetIRNumber:
sertxd(13,10,"@GetIR",13,10)
DigitsByte=0:digit=3
GetDigits0:
Infrared=255
irin [1, GetDigits0],irsense, InfraRED
sertxd("IR ",#infrared," ",13,10)
if infrared > 9 then
return
endif
infrared =infrared +1
if infrared = 10 then
infrared=0
endif
if digit=3 and infrared>2 then getdigits0:'can't be above 2hunderds
if digit=2 and digitsbyte = 2 and infrared > 5 then getdigits0
if digit=1 and digitsbyte =25 and infrared > 5 then getdigits0
skiprnd:
sertxd("Digit= ",#digit,13,10)
if infrared=0 then
high LEDBlue:pause 50:low LEDBlue
endif
for tempbyte=1 to infrared:high LEDBlue:pause 200:low LEDBlue:pause 200:next tempbyte
DigitsByte=DigitsByte*10+infrared
digit=digit-1
pause 200':'command=0
if digit=0 then
sertxd("Digitsbyte ",#digitsbyte," ",13,10)
return
endif
goto GetDigits0:

ShowReadValues:
SERTXD("SPD, MIN, WAIT, AD, RdomWait,DecelFlag ",#setspeed," ",#minspeed," ",#waittime, " ", #adrate," ",#RndmWait," ",#deceltime," ",#b0, 13,10)
sertxd ("sdf=",#slowdnflag,13,10)
RETURN