A Pulse-width modulation controller for a model railway

hnorwood

New Member
I thought I should post my first picAXE project here. I had thought for a long time about a fully-digital train controller, but was put off by the large number of discrete logic chips needed, until someone suggested using a picAXE.



The device uses a rotary encoder as the input (the control knob) and the picAXE determines the direction of rotation of the encoder, and drives the output device (high power MOSFET) using the inbuilt PWM circuit. I'm pleased with the way the controller works and use it when I'm exhibiting my layout.

Full details are available on http://www.hnorwood.co.uk/files/pwm2.htm
 

hnorwood

New Member
And here is the code. OK it's not very elegant - should perhaps have used a loop for the main loop, but it works...

Code:
; PWM train controller 6 June 2013 HN
; using 08M2 chip
; C.2 is the PWM output
; C.1 is encoder A channel
; C.4 is encoder B channel
; C.3 is emergency STOP
; b0, b1 and b2 are locally used byte variables
; 22 June 2013 some mods after testing it in circuit
; the increment needs to be bigger than 4
; I need to debounce the emergency stop switch
; set a symbol for decrement as well
; This version - look for a change in the B channel as well
; also different values for the step in increment and decrement


symbol dutyCycle = b0
symbol oldStateA = b1
symbol oldStateB = b2
symbol encoderA = pinC.1
symbol encoderB = pinC.4
symbol stopButton = pinC.3
symbol ModulatorOutput = C.2
symbol dutyCycleMaximum = 194
symbol dutyCycleMinimum = 0
symbol dutyCycleIncrement = 5
symbol dutyCycleDecrement = 7

pwmout ModulatorOutput,50,0 ; set up PWM channel and set it off


; initialise the variable that holds the old state of encoder A channel
if encoderA = 1 then
	oldStateA = 1
	else
	oldStateA = 0
	endif
; initialise the variable that holds the old state of encoder B channel
if encoderB = 1 then
	oldStateB = 1
	else
	oldStateB = 0
	endif

	
init:
	dutyCycle = 0 ; initialise the speed variable

; main loop
main:
	if stopButton = 0 then ; check for emergency stop
		pause 8	; debounce
		if stopButton = 0 then
		pwmout ModulatorOutput, 50, 0 ; stop pwm output
		goto init
		endif
	endif
	
	if encoderA <> oldStateA then ;has encoder A changed state
		pause 4   ;slight delay
		if encoderA <> oldStateA then
			inc oldStateA
			if oldStateA >1 then
				oldStateA = 0
			endif ; toggle oldStateA
			if encoderB <> oldStateA then
			; clockwise
				dutyCycle = dutyCycle + dutyCycleIncrement ;increase speed
				if dutyCycle > dutyCycleMaximum then
					dutyCycle = dutyCycleMaximum
				endif
			else
			; anticlockwise
				if dutyCycle > dutyCycleDecrement then ; decrease speed
					dutyCycle = dutyCycle - dutyCycleDecrement
				else
					dutyCycle = 0
				endif
			endif
			pwmduty ModulatorOutput, dutyCycle ; set pwm output
		endif
	endif		
	if encoderB <> oldStateB then ;has encoder B changed state
		pause 4   ;slight delay
		if encoderB <> oldStateB then
			inc oldStateB
			if oldStateB >1 then
				oldStateB = 0
			endif ; toggle oldStateB
			if encoderA = oldStateB then
			; clockwise
				dutyCycle = dutyCycle + dutyCycleIncrement ;increase speed
				if dutyCycle > dutyCycleMaximum then
					dutyCycle = dutyCycleMaximum
				endif
			else
			; anticlockwise
				if dutyCycle > dutyCycleDecrement then ; decrease speed
					dutyCycle = dutyCycle - dutyCycleDecrement
				else
					dutyCycle = 0
				endif
			endif
			pwmduty ModulatorOutput, dutyCycle ; set pwm output
		endif
	endif		
	goto main
	end
 
Top