Model Train Controller

Forty years ago I had a couple of friends who got very involved with HO scale model trains.  I had outgrown my interest in trains after my old Lionel got passed down to my younger brother but I still admired the work my friends were doing.  I even found that my electronics background could be useful in their pursuit so I designed and built a few circuits for them.  I got reminded of those days when I pulled out some yellowing papers, dated 1977, that had my design for what was then a state of the art electronic throttle.  Interestingly, the central part of the design is still available today: the LM3900 quad op-amp.  That discovery gave me the idea to try and build a simple train throttle using the PIC and software instead of the op-amp and a bunch of discrete components.  While the design I present here is targeted for a 12 volt model railroad motor, it can easily be modified for a variety of other DC motor control applications.

Pulse Width Modulation (PWM)

Duty Cycle

For those of you who aren’t familiar with PWM, it isn’t as scary as it sounds.  All it really means for our simple motor control application is that we generate a square wave of some frequency, and then we change the duty cycle.  Duty cycle is defined as the ratio of time that the output is a logical high compared to the waveform period.  You can see that quite clearly in the diagram above with the top waveform at 10% duty cycle, the middle waveform at 50% duty cycle, and the bottom waveform at 90% duty cycle.  The dashed line overlaid on each waveform represents the equivalent DC voltage seen by the motor.  Given that many PICs have a PWM capability built in, it is really pretty simple to generate this type of DC motor control.  One other advantage of using PWM is that it helps to keep the motor from the lurching startup that can happen when using straight DC.  One disadvantage of PWM is that there is sometimes an audible noise from the motor at the frequency of the PWM.


Train Control

L298N Board

The first picture shows the PIC connections.  The resistor values are not critical as they are just used to hold their respective input pins at a high logic level.  There are weak pull-up resistors internal to the PIC that could be used instead but I prefer to use external resistors for greater noise immunity.  The Direction switch is a simple SPDT (single pole double throw) switch without a center off position.  The Throttle and Brake switches are shown as normally open, momentary contact push buttons.  You could easily replace these two switches with a single SPDT momentary contact toggle switch.  In this case, the center contact would be connected to ground, one outside contact connected to the Throttle pin of the PIC and the other outside contact connected to the Brake pin of the PIC.  That way you could push the switch up to accelerate and down to brake.  When you released the switch it would return to the center off position on its own.

The second picture is our old friend the L298N dual H-bridge module that we used in the post on the Bluetooth controlled toy car.  The wiring differences in this application are based on two changes from our previous application.  First, we need +5 VDC for the module logic and for the PIC but we want +12 VDC to drive the motor.  In this case we will apply the +12 VDC to the “+12V power” input of the L298N and we will leave the “5V enable” jumper in place.  This will allow the module’s built in 5 volt regulator to function from the 12 volt input.  We will then take the “+5 power” connection on the module and use it to power our PIC circuit.  Don’t forget to connect the ground wires for the +12 input and the +5 output to the module “power GND”.

The second change from our previous use of this module is that we want the output voltage to vary based on the PWM generated by the PIC instead of just being full on or full off.  To do that, we remove the jumpers from “A enable” and “B enable” and connect our PIC PWM output (pin 5) to “A enable” on the module.  Keep in mind that the actual enable pin is the one closest to the board edge (next to the “input” pins).  The back pin for each enable is +5 volts so we want to make sure we don’t connect to that.

The “IN1” and “IN2” pins on the module are connected to PIC pins 2 and 3 respectively.  Those pins control the motor direction and, yes, there is a good reason to let the PIC control them instead of simply connecting a switch to the module.  We will see why in the software discussion.


The software link is listed below.  While it is targeted for the 12F683, it is easily ported to other versions of the PIC.  You will need to change the line that identifies the PIC version (LIST=) and the INCLUDE file but those are intuitive changes.  The __CONFIG line may also need tweaking just because one or two of the labels used are spelled differently in some of the INCLUDE files.  You will also need to select a PIC that supports PWM.  Unfortunately, my other favorite PIC (the 16F688) does not have PWM capability.

The software is pretty simple once the PWM initialization is figured out.  To help with the register value calculations I used a PWM calculation website located at:

When I first wrote the PIC code I set the PWM frequency at 20-kHz.  I then connected a digital voltmeter to the PIC output and it varied in a nice linear fashion from 0 to 5 volts.  Unfortunately, when I connected the PIC to the L298N module I discovered that when the PWM started the first non-zero output was over 10 volts.  It dawned on me that maybe the L298N module wasn’t capable of reacting that quickly to the enable pulses so I cranked the frequency down and finally settled at 500-Hz.

One of the “features” of train throttles is a sense of momentum for acceleration and braking to simulate how a real train works.  To accomplish that, a simple time delay is inserted in Main_Loop.  With the values shown, it takes approximately 13 seconds to go from 0 to 12 volts or from 12 volts back to zero.  The delay can easily be modified for longer or shorter times.  The only case where momentum is not in effect is when the Direction switch is changed.  For protection purposes the PWM duty cycle is immediately set to 0% whenever this switch is changed.  So, in effect, the Direction switch also doubles as an emergency brake.

To ensure immediate handling of the Direction switch we put its code in an interrupt handler.  That also allows us to use a PIC function mentioned in an earlier Episode called “interrupt on change”.  What happens is that the interrupt is not based on the logic level on the pin (i.e.: high or low) like most interrupt inputs.  Instead, it will interrupt if the logic level changes from whatever it previously was.  That’s why our Direction switch has one side pulled up to +5 and the other side tied to ground.  That’s it for this post.  Check out my other electronics projects.

Train Controller