A PWM train controller with H-bridge output

hnorwood

New Member
A model train controller using pulse-width modulation for speed control and an H-bridge output to control direction

Following a discussion on the ngrm-online forum, I decided to look at modifying my picAXE-based pwm train controller so that the picAXE controls the direction as well as the speed. This would dispense with the mechanical double-pole double-throw (dpdt) switch.

To do this requires what is called an "H-bridge" driver; basically four power devices with the motor between pairs of them. The current through the motor (and hence its direction) is controlled by which two of the power devices are on at any one time.

I decided that the 8-pin picAXE that I used for the original controller could still be used because the two pins normally used for programming can be used by a program for input and output.

I also found a rotary encoder that incorporated a push-switch (for emergency stop and direction control) and three LEDs, which shine out through the transparent control shaft and translucent knob. I thought this would make a nice minimalist-look to the control box.

I used the AXE091 breadboard to develop the circuit; and what an advantage that was, as I found the performance of this particular rotary encoder was quite different from the one I had use in the Mk3 controller. I went through a few development cycles before finding a hardware and software solution that worked reliably.

This is the circuit diagram for the working controller. It has a few extra bits from the original design idea. The three LEDs and the push-switch are all integrated into the rotary encoder and they are all commoned to the positive line. Pressing down on the knob activates the push-switch.



The extra resistor and capacitor connected to each encoder output act as low-pass filters to counter any "chatter" from the switch contacts. I have included a 7404 hex inverter IC to drive the three LEDs and to reshape the pulses from the switches. There are two 10k resistors grounding C.0 and C.1, to prevent the H-bridge shorting the power supply while the picAXE goes through its initialisation at power-up.

In use, the encoder governs speed only, following convention that clockwise increases the speed and counter-clockwise decreases the speed.

If the button is pressed while the train is in motion, the PWM output is stopped, but the direction is saved, so the train will carry on in the same direction when the knob is rotated clockwise.

If the button is pressed while the train is stationary, then the direction is reversed. The colour shining out of the encoder shaft indicates the direction and speed, as we have three colours (red, green and blue) to play with.


Some modellers like to have control over direction as well as speed using the control knob; there are a number of controllers available with a "centre-off" control knob (indicated by a detent). You can't have a centre-off on a rotary encoder, of course, but it is quite possible to program this controller to behave in this way. I would think a programmed "dead-spot" at zero-speed would do the trick. Perhaps I'll leave that as an exercise for the reader!

More details on my web site, including the BASIC program.
 
Last edited:

techElder

Well-known member
Swell project, hnorwood, but this forum is better served if you post your project code here, too. There are many instances in the archives where personal websites go away and so would the link here.
 

hnorwood

New Member
OK (second try, my connection dropped just after I clicked on POST!)

Code:
; PWM controller mk4 rev H2 16 August 2015
; PWM train controller mk4 7 August 2015 HN
; 8 August 2015 in this version, the enable pins are activated by pressing the
; push switch - this allows the LEDS to light up
; and so indicate the direction
;
; using 08M2 chip
; C.2 is the PWM output
; C.3 is one output from the encoder
; C.4 is the other output from the encoder
; C.5 is emergency STOP
; C.0 is one direction control
; C.1 is the other direction control

; b0, b1 and b2 are locally used byte variables


symbol dutyCycle = b0
symbol NewAccel = b1  ; previous state of encoder channel A
symbol OldAccel = b2  ; previous state of encoder channel B
symbol moving = b3  ;flag to show if the train is moving
symbol direction = b4  ; flag to show the direction set
symbol temp = b5  ; byte variable 
symbol Encoder2 = pinC.3
symbol Encoder1 = pinC.4
symbol stopButton = pinC.5
symbol clockw = C.0   ; commands one enable input of driver chip
symbol cclockw = C.1  ; commands one enable input of driver chip
symbol ModulatorOutput = C.2  ; PWM output pin
symbol dutyCycleMaximum = 194
symbol dutyCycleMinimum = 0
symbol dutyCycleIncrement = 5
symbol dutyCycleDecrement = 7
symbol left = 0
symbol right = 1

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

init:
	disconnect    ; let us use the SERIAL-IN pin (C.5)
	dutyCycle = 0 ; initialise the speed variable
	temp = 1      ; init the byte variable
	direction = right ; init direction
	moving = 0    ; set train to stop
	low clockw
	low cclockw

; initialise the variable that holds the old state of Acceleration
if Encoder2 = 1 then
	OldAccel = 1
	else
	OldAccel = 0
	endif

	



; main loop
main:
	if stopButton = 1 then
		pwmout ModulatorOutput, 50, 0  ;stop pwm
		dutyCycle = 0 ; initialise the speed variable
		low clockw
		low cclockw
		if moving =0 then ; change direction if already stopped
			if direction = right then
				direction = left
				high clockw
			else
				direction = right
				high cclockw
			endif
		endif
		moving = 0
		pause 200    ; short pause after button press
	endif
	
skipme:  ;skip to here if button has not been pressed	
	if Encoder1  = 1 then
		if temp =1 then
			if  Encoder2= 1 then
				NewAccel =1
			else
				NewAccel =0
			endif
		;	decide on what to do
				if NewAccel <> OldAccel then ;speed change
					OldAccel = NewAccel
				endif
				if  OldAccel = 1 then
					gosub GoFaster
				else
					gosub GoSlower
				endif
			temp = 0
			pause 2	; short pause
		endif
		temp = 0
	else
		temp = 1		
	endif
	; the effect of temp should be that if Encoder1 is still high when
	; it comes round the loop again then it will skip the changes until
	; Encoder1 is read as low

	goto main
	end
			
; subroutine to go faster
GoFaster:
	dutyCycle = dutyCycle + dutyCycleIncrement ;increase speed
	if dutyCycle > dutyCycleMaximum then
		dutyCycle = dutyCycleMaximum
	endif
	if moving = 0 then
		moving = 1  ; set train flag to moving
		if direction = left then  ; set appropriate enable line high
			high clockw
		else
			high cclockw
		endif
	endif
	pwmduty ModulatorOutput, dutyCycle ; set pwm output
				
return
; subroutine to go slower
GoSlower:
	if dutyCycle > dutyCycleDecrement then ; decrease speed
		dutyCycle = dutyCycle - dutyCycleDecrement
	else
		dutyCycle = 0
		moving = 0 ; set train flag to stop
		low clockw ; clear enable
		low cclockw ; clear enable
	endif						
	pwmduty ModulatorOutput, dutyCycle ; set pwm output

return
 

westaust55

Moderator
Well done with PWM loco your controller.

With respect to your comment about using the 10 kOhm pull-down resistors to prevent the L293D conducting on all channels, an alternate option is the use the remaining (6th) inverter from the hex inverter IC (74HC04) so that a single PICAXE output is directly connected to one Enable pin and via the hex inverter gate to the second Enable pin.

With respect to considering the SN754410 as an alternate to the L293D (as mentioned on your website), I have not used the higher current rated part myself but, there have been quite a few past posts about difficulties with this alternative chip which were overcome by change from the SN754410 to a L293D part.
 
Last edited:

hnorwood

New Member
Thanks for the heads-up on the 754410; I'll keep an eye on it, but there are not that many posts about it that I can find.

However, the circuit is a bit of a kludge, really... I wanted to a) use as few ICs as possible; b) use DIL packages only (as I'm familiar with those).
I found the data sheet for the L293 appeared to state that it would not work reliably at 20kHz and was told the 754410 would (This is not born out by the data sheet however) Anyway, I decided that I could do it with only 2 ICs - the picAxe and the 754410 , and ordered the parts.

Unfortunately, the rotary encoder required its outputs to be "debounced", which required another IC (the 7404).

Ideally I would have liked a MOSFET driver IC, but they either come in a more "exotic" package (like small outline) and I wasn't happy about working with them, or required logic gates to switch the direction. With hindsight, I should have gone down this route, certainly if I make another, I shall do this.

Also, a lot of modellers use 12V dc "bricks" rather than 16ac transformers, so you can dispense with the bridge rectifier 4700uF cap and 7812, thus gaining more space in the enclosure and saving a bit of weight (I make my controllers into hand-held devices)
 

BellTyson

New Member
It is an appreciable work that you did and also thanks for sharing it with us. Well done with PWM loco your controller.
I want to say something about your 10K pull-down resistors to prevent the L293D conducting on all channels, instead of it you can also use the 6th inverter from 74HC04 so that a single PICAXE output is directly connected to one Enable pin and via the hex inverter gate to the second Enable pin.
 
Last edited:
Top