Multiplexing + Controlling points (or other high-current devices) with an Arduino
OK, the Arduino only has a limited number of pins at your disposal (more depending on what model you are in possession of) but, don't fret, there is a way of extending the amount of inputs _and_ outputs.
Multiplexing, as defined by Wikipedia is:
In telecommunications and computer networks, multiplexing (also known as muxing) is a process where multiple analog message signals or digital data streams are combined into one signal over a shared medium. The aim is to share an expensive resource. For example, in telecommunications, several phone calls may be transferred using one wire. It originated in telegraphy, and is now widely applied in communications.
In our situation, we're using digital data and our shared medium will be a smaller group of pins than the amount required if we were to hook up the sum total of devices able to be connected. So, in our case we will use the CD4514BC "4-Bit Latched/4-to-16 Line Decoder" to control/read 16 digital lines from only 6 digital pins.
Quick note:
If you don't mind that the chip is always outputting then just ground the Inhibit pin. It'll save you a pin on your Arduino!
First, a short stint of binary logic. Our numbering scheme will start from 0 and end at 15, giving us 16 possible values. This can be written in binary using 4 digits.
Bit 4 | Bit 3 | Bit 2 | Bit 1 | Value | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Value | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 8 | |
0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 9 | |
0 | 0 | 1 | 0 | 2 | 1 | 0 | 1 | 0 | 10 | |
0 | 0 | 1 | 1 | 3 | 1 | 0 | 1 | 1 | 11 | |
0 | 1 | 0 | 0 | 4 | 1 | 1 | 0 | 0 | 12 | |
0 | 1 | 0 | 1 | 5 | 1 | 1 | 0 | 1 | 13 | |
0 | 1 | 1 | 0 | 6 | 1 | 1 | 1 | 0 | 14 | |
0 | 1 | 1 | 1 | 7 | 1 | 1 | 1 | 1 | 15 |
Right, from this table you can see that by setting the Bits to either '1' or '0' we can, with 4 bits, create the numbers from 0 to 15. Now, this is how the input of the CD4514BC Line Decoder works; it accepts digital input on 4 pins, and dependent on whether they are high or low, will output a +5v on the decoded output pin. The chip has, of course, 16 output pins.
The only catch to using this chip is that it also requires 'Strobe' and 'Inhibit' digital inputs. It is called a 'Latched' Line Decoder since it actually holds the output that you have selected. So, the basic idea when controlling it is to:
- 1 - Set the 4 bits to the desired output
- 2 - 'Toggle' the 'Strobe' pin. This means setting it to 'HIGH' and then 'LOW' again (this then 'latches' the next pin to output on)
- 3 - Set the 'Inhibit' pin 'LOW' to output on this pin. When this is 'HIGH', there will never be any output.
Here is the wiring I have used for the CD4514BC:
Dragging the 'Inhibit' HIGH should prevent the points from erratic data on the pins when there is no proper input signal.
From this we can see that we can control 16 devices. The only note is that the multiplexer can only ever output on one pin at a time.
Controlling this chip is quite simple. The steps, as outlined above, are documented in the following code:
#define STROBE_PIN 51 #define INHIBIT_PIN 53 #define BIT1_PIN 31 #define BIT2_PIN 33 #define BIT3_PIN 35 #define BIT4_PIN 37 #define DIRECTION1_PIN 22 #define DIRECTION2_PIN 24 #define TOTAL_OUTPUTS 5 //should 16, but we're only controlling 5 pins for now. void setup() { Serial.begin(9600); //set the output mode. pinMode(INHIBIT_PIN,OUTPUT); pinMode(STROBE_PIN,OUTPUT); pinMode(BIT1_PIN,OUTPUT); pinMode(BIT2_PIN,OUTPUT); pinMode(BIT3_PIN,OUTPUT); pinMode(BIT4_PIN,OUTPUT); //initial state digitalWrite(INHIBIT_PIN, HIGH); //high = off. digitalWrite(STROBE_PIN, LOW); //toggle low -> high -> low to set output. digitalWrite(BIT1_PIN, LOW); digitalWrite(BIT2_PIN, LOW); digitalWrite(BIT3_PIN, LOW); digitalWrite(BIT4_PIN, LOW); } void changeOutputPin(int out) { //work out bits if (out >> 3 & 0x01) digitalWrite(BIT4_PIN, HIGH); else digitalWrite(BIT4_PIN, LOW); if ((out >> 2) & 0x01) digitalWrite(BIT3_PIN, HIGH); else digitalWrite(BIT3_PIN, LOW); if ((out >> 1) & 0x01) digitalWrite(BIT2_PIN, HIGH); else digitalWrite(BIT2_PIN, LOW); if ((out) & 0x01) digitalWrite(BIT1_PIN, HIGH); else digitalWrite(BIT1_PIN, LOW); //toggle strobe digitalWrite(STROBE_PIN, HIGH); digitalWrite(STROBE_PIN, LOW); } int currentOutput = 0; int switchDir = 0; void loop() { changeOutputPin(currentOutput); currentOutput++; if (currentOutput > TOTAL_OUTPUTS) { //only control 8 outputs... change the dir once looped. currentOutput = 0; switchDir = !switchDir; if (switchDir == 1) { digitalWrite(DIRECTION1_PIN, HIGH); digitalWrite(DIRECTION2_PIN, LOW); } else { digitalWrite(DIRECTION1_PIN, LOW); digitalWrite(DIRECTION2_PIN, HIGH); } } //toggle inhibit to low to actually output power digitalWrite(INHIBIT_PIN,LOW); delay(25); //25ms is long enough. digitalWrite(INHIBIT_PIN,HIGH); delay(1500); //now delay before going to next point. }.
Controlling Point Motors
The Tomix Finetrack points I use on my layout have in-built electromagnets to change their direction. Electromagnets are known to suck a large amount of current in a short burst as they receive power and begin to 'throw'. Due to this, powering one directly off one of the Arduino's output pins is not recommended. Another issue is that the electromagnets will heat up if they are constantly powered. Due to this, they require an external power source controlled in short bursts.
A H-Bridge is used when controlling the actual model locomotives and here one will also be used to control the point magnets. H-Bridges are a great solution to the above issue as they utilise an isolated power supply and can output a reversed polarity. The point magnets from Tomix are only 2-wire and require the polarity to be reversed to switch the track in the other direction.
Note that this can therefore be used to control anything that requires a 5v-34v DC ~1A power source. This could be bulb lighting (where you can vary the voltage/brightness), motors/actuators/solenoids for scenery effects, etc...
So, firstly here's an example of hooking up an L293D or SN754410 H-Bridge to two point motors/magnets:
Now, there are three wires feeding into the above circuit (per point motor/side of circuit) that need signals. First is the 'activate' pin which should stay low and only be brought high for brief periods of time to send voltage to the point magnet. Second is the 'directional' pins where:
- LOW, LOW: No output
- LOW, HIGH: Left (-/+)
- LOW, HIGH: Right(+/-)
- HIGH, HIGH: SHORT! Do not do this!
So, to get the 'enable' signal to the H-Bridge we will utilise 6 pins on the Arduino. One for the actual signal to send and then 3 to control a multiplexer which will then allow us to actually control 8 outputs. This multiplexer (CD4514BC) can only send a signal on one of it's 16 pins at a time. The goal therefore is to set the four input wires (which then selects the output) and then produce the HIGH signal for a brief period of time. This will send the required signal to the H-Bridge which will, in turn, output the 12v pulse to the point magnet.
The final requirement is to set the direction. I have bridged the inputs on all H-Bridges to a single pair of digital outs on the Arduino. I simply set one HIGH and the other LOW to switch in a direction. You could actually use one pin and have a Hex Inverter create the opposite signal required for the other input on the bridge.
Since I only ever enable one side of one H-Bridge, it is perfectly safe to set all inputs on all bridges at the same time.
Here is the final setup:
My ugly diagram showing you how to connect the components.
The functional dog's breakfast... This is a tiny piece of veroboard with 4 H-Bridges (8 outputs) and an LM7805 to provide the +5v. The inputs on the H-Bridges are chained together and the enable pins (8 of them) run to one side of the CD4514BC.
Here is the CD4514BC Multiplexer. This receives 6 wires from the Arduino and then outputs 16 digital to whatever I require.
And everything working in concert.
March 17th, 2010 - 09:42
Very nice. Once again, you’ve already built and testing something I’ve only begun to think about.
Have you considered trying a shift-register instead of a muxer? Advantage is that you get to control arbitrary pins, instead of only one at a time. For instance, I’ve been playing around with the Texas Instruments TLC5941 LED driver, which combines 16 constant-current sinks with two shift-registers (one 64-step-per-channel to calibrate each LED so they appear the same brightness by adjusting the amount of current they each get; one 4096-step-per-channel for fine-grained PWM control of brightness). It’s overkill for controlling turnouts, but the closely related TLC59401 is rated to 120mA/channel (not all at once though! It can’t dissipate that much heat), which might mean you wouldn’t need the H-bridges. Perhaps. Anyway, there are simpler ones (e.g. 74HC595) which might suit. Which leads me to my next question:
How much current do these motors draw, exactly?
Anyway, once again a delightfully informative and inspirational post.
March 17th, 2010 - 10:03
Don,
I had thought about using a shift register for this, but seeing as that I never wanted to control more than one point at a time, I decided against it. This chip really is perfect for systematically bursting power to points. I’d use the shift register maybe for 12v lighting or other items where I’d need/want more than one item on at a time.
The only advantage here would be that a shift register would potentially use less pins if it accepted serial input.
I’ll be uploading the code tonight (blame fatigue that I forgot to in the early hours this morning) which shows the timing required to throw the points and a little more detail on how to control the Line Decoder/Multiplexer.
As for LED Drivers, I wouldn’t go hooking up anything like a point motor/solenoid to one. I’ve already killed a few components with obsessive current and I’m no whiz when it comes to actually calculating what everything actually needs. Since these components are cheap, I choose to overkill the requirements and ensure that if an item can get current if it wants it.
Regarding current draw, I have no idea how much these point magnet/motors need… I should do a little measuring.
Meanwhile, you always manage to ruin my next surprise :P …next… Driving 64 LEDs with 3 pins.
Thanks again for your comments!
August 9th, 2015 - 07:55
Thanks for a very interesting article.
Do you know how much current the point motors draw ?
How long does one apply the power for ?
Is there a set of datasheet style information ? I’d like to know the theoretical correct power requirements.
Did you get any issues with back-emf? The L293D should take care of it somewhat.