Using an optocoupler to connect insulated rail to input pin of shift register

I just want to throw in a comment regarding shift registers.  If you're planning to use shift registers for either input or output with an Arduino, I highly recommend Macetech's Centipede shield.  They are more expensive than just buying a bunch of MCP23017's and hooking them up yourself, but they are ridiculously simple to use, with an included Arduino library, and support up to 128 I/O ports per Arduino (my project uses 7 Arduino Megas and 7 of these boards.)  I don't use them as "shields" because I'm using Megas and need two on several of my Arduinos -- I just wire them up separately.  I use them to control turnout relays (using the relay board previously mentioned, with 16 relays per board = control 8 turnouts per board), for monitoring isolated track occupancy (using time-delay-off relays), for illuminating control panel LEDs (including RGB LEDs,) and for monitoring control panel turnout pushbuttons.  Here is the product page link:

http://macetech.com/store/inde...o&products_id=23

64 ports for $25.  They also provide great tech support.

Randy

P.S. FYI, I am building an autonomously-controlled 15'x30' layout, with Arduinos monitoring occupancy, scheduling routes, throwing turnouts, and more -- and sending Legacy commands to all motive power via the Legacy serial interface.  This project was inspired by Prof. Chaos's layout, and the YouTube videos he posted.  My Arduinos communicate with each other via an RS485 bus.  If anyone is interested in this, we can start a separate thread about it, and share ideas.  I've learned a lot of things the hard way -- the RS485 bus was a nightmare to get working reliably, for example -- and it should have been trivial.

When using this I/O shield, note that while they specify 25ma per port sink/source, the overall power maximum doesn't allow nearly all off them to be active at the same time.  Not unexpected, but just something to be aware of.

Attachments

Photos (1)

Very true, John.  In my case, I use resistors on my LEDs that limit their draw to a few mA each and they are still plenty bright (though I had to sample a number of different LEDs to find high brightness at low current.)  For the 16-relay boards, I power the coils with a wall wart, so the shift register only needs to source or sink (I forget which) a few mA to close each relay.  I've confirmed this with a Fluke multimeter.

Without an external power source, the relay coils on those 16-relay boards draw about 30mA each.

If you were driving LEDs at the more conventional 20mA, and driving the relay boards without an external power supply, there could be serious problems.  It's a very important consideration!

When using the shift registers to monitor inputs going to ground, such as pushbuttons and relay contact closures (typically with a pull-up resistor), I don't think current sink/source limitations are a factor - at least not as I have been using them.

Randy

Randy P. posted:

I just want to throw in a comment regarding shift registers.  If you're planning to use shift registers for either input or output with an Arduino, I highly recommend Macetech's Centipede shield.  They are more expensive than just buying a bunch of MCP23017's and hooking them up yourself, but they are ridiculously simple to use, with an included Arduino library, and support up to 128 I/O ports per Arduino (my project uses 7 Arduino Megas and 7 of these boards.)  I don't use them as "shields" because I'm using Megas and need two on several of my Arduinos -- I just wire them up separately.  I use them to control turnout relays (using the relay board previously mentioned, with 16 relays per board = control 8 turnouts per board), for monitoring isolated track occupancy (using time-delay-off relays), for illuminating control panel LEDs (including RGB LEDs,) and for monitoring control panel turnout pushbuttons.  Here is the product page link:

http://macetech.com/store/inde...o&products_id=23

64 ports for $25.  They also provide great tech support.

Randy

P.S. FYI, I am building an autonomously-controlled 15'x30' layout, with Arduinos monitoring occupancy, scheduling routes, throwing turnouts, and more -- and sending Legacy commands to all motive power via the Legacy serial interface.  This project was inspired by Prof. Chaos's layout, and the YouTube videos he posted.  My Arduinos communicate with each other via an RS485 bus.  If anyone is interested in this, we can start a separate thread about it, and share ideas.  I've learned a lot of things the hard way -- the RS485 bus was a nightmare to get working reliably, for example -- and it should have been trivial.

Thanks for sharing the shield Randy. I will look at it more later and probably maybe make mine own if I could. I plan on using the MCP23017 for block detection. 

I'm working on several projects for my layout. The current one is using JMRI and Arduino CMRI library for turnouts, block detection, signals, and more. I also have Legacy control tied in. I would be interested in talking to you about your project. Specifically the topic at hand here. Block occupancy. 

 

 

Chris

TCA, LCCA

 

 

Chris, my method of block occupancy is very different from most approaches, but I am very happy with it.  Here is what I do:

I opted for isolated rail detection, rather than something like an opto sensor.  Isolated rails are monitored by an Arduino (I'll explain how, below) as a means of keeping track of where all of the trains are on my layout.  I use an isolated section at each end of every block, including, most importantly, at each end of every double-ended siding.  When a train trips the *entry* block of a siding where it is scheduled to stop, an Arduino sends Legacy commands to begin slowing down the train (and start ringing the bell, make an announcement, etc.)  The speed and momentum commands that are sent depend on several factors including the length of the siding, the speed at entry, and the individual locomotive characteristics.  I try to time this so that I'm moving slowly, but not *too* slowly, by the time the train trips the exit sensor of the block.  If it's a long siding, I don't start slowing down right away.  When the exit sensor is tripped, I do an absolute stop of the locomotive.

So here is one challenge: there are many factors that contribute to the latency between the instant an occupancy sensor is tripped, and when the locomotive receives and responds to a command -- such as to stop immediately before overshooting the block and fouling the exit turnout.  An optical sensor would allow me to move it farther into the block if I needed to allow for more latency, but that sensor also serves as an *entry* sensor if a train enters the block from the opposite direction -- and I want to know as soon as a train enters a block -- not a couple of feet into it.  So I need a "long" section of isolated rail -- that would trip the instant a train enters from that end, but also maybe a foot or so before it reaches the end if traveling the other direction.  I hope that makes sense ;-)  But how long should it be?  I won't know for sure what the latency will be until I have half a dozen trains running at the same time, with the Arduinos juggling lots of tasks etc.  But I can't test it until I have all of those isolated sections in place.  Catch 22.

My solution was to use a very thin insulating tape called Kapton tape, on top of the rails, followed by a layer of very thin adhesive copper foil tape.  The Kapton tape is 1/2" and the copper tape is 1/4" -- so I have an insulated strip of copper tape on top of my rails (I use MTH ScaleTrax.)  I solder a small wire anywhere along the outside edge of the copper strip, and that is my grounded/not-grounded indicator signal.  I can easily add or remove tape to adjust the length of the isolated section at any time.  I have to be a bit careful -- I can't clean my rails with a Brite Boy pad, or the tape would be destroyed.  But it's been working great for many months of testing.  And I can always convert these to "cut the rail" isolated sections at a later time, when I am confident that I know what length is ideal.

So the only thing left is how to get an Arduino to read that grounded/not-grounded wire, for over 50 isolated sections.  My solution -- which I'm sure many think is ridiculous -- was to use time-delay-off relays that I buy on eBay for $5 each:

http://www.ebay.com/itm/1A-12V...?hash=item281af6e689

This is an expensive and space-consuming solution but I love it.  I connect the isolated-rail wire directly to one side of the relay coil (the other connected to 12VAC "hot").  I connect one side of the contacts to ground and the other to an input pin of my shift register (a Centipede, in my case.)  When a train is on an isolated section, the relay coil energizes, the Arduino sees it (via the shift register) as a simple contact closure -- and the contacts stay closed for several seconds *after* the train has left the scene (any amount of time can be set using the dial) to eliminate issues of chatter, dirty wheels, etc.

I've attached some photos of the work that's been completed.  Feel free to ask questions!

Randy

Attachments

Photos (6)
Randy P. posted:
When using the shift registers to monitor inputs going to ground, such as pushbuttons and relay contact closures (typically with a pull-up resistor), I don't think current sink/source limitations are a factor - at least not as I have been using them.

 

It appears that they have a similar limitation on VSS, 150 ma maximum into the pin.  Any pull-down is going to have to go through the VSS pin and would be subject to the 150ma limitation.

crood58 posted:

JGL,

I have a question on your circuit. What is the 12V feeding into? A voltage divider or still an RC Circuit with Opt Amp? 

The 12VDC line is only used to power the optocouplers.  The circuit is pretty much a 1.5k resistor, an LED(inside the optocoupler), and a diode to prevent reverse current if AC is used on the sense lines.  With a 1.5k resistor on the cny17-1 optos I have, I get reliable results from 5vdc to 30vdc.  I have not tested below 5 volts, but going by the specs it should work down to about 3.5 volts if I recall.  The other end of the optocoupler is used to switch on a pin of the arduino (or other input device).  For a switch machine controller that does not need to know if a train is still there, only when one approaches even a 60Hz AC supply to the optocoupler will make pulses that last plenty long enough to be detected.  For other applications, however, an RC filter is used, if you want the input to remain on while a train is present, such as in my multi-function track presence detector project.  

Like I said previously, I plan to used the 12vdc because I have it and am not using it for anything else.  Accessory level AC, or track level AC are equally usable options.  


On the current limitations of the MCP23017:  There are also similar limits on the ports of the arduino its self.  Depending on the board in question the ports are split up differently, and usually the I/O pins are spread over several ports, but each port can only sink/source 100 or 200 mA (again depends on the port) It's something that you need to keep track of when you design, to make sure you're not drawing too much current through any one port.  You can also just use a transistor to up the current if needed, or an inexpensive transistor array if you need a lot of them.  

Another thing to keep in mind with those relay modules, while they only draw about 30mA per relay when on, they will draw about 70mA surge current when the relay is clicked on.  Make sure your power supply can handle the spikes of current.  As for driving them, you can get away with limiting the current further, but unless you do that, expect each channel to draw about 20 mA from your I/O port.  

The shift registers have the same problem as port expanders here, the common 74HC595 can sink 20mA per pin, for example, but only a total of 70mA across all 8 outputs.  

Transistor arrays like the ULN2803 can be very useful here as it can sink 500ma per channel.  

JGL

$ This is John Galt speaking.  $

“I swear by my life and my love of it that I will never live for the sake of another man, nor ask another man to live for mine.” 

 

 

Randy P,

I like what you're doing there with the Arduino's! The tape on the track idea is brilliant! Love it!

I was just wondering about the RS485 communication problems that you were having. Can you elaborate on what the best way is to avoid the problems that you encountered? I guess I want to know how you did this. I'm working on some stuff that would make use of the RS485 multi-drop bus but am no where near actually putting anything together yet. I'm also wondering what you used for the drivers. I'm looking at the Texas Instruments ones for around 80 cents each.

It's only a matter of time before this forum recognizes that Arduino is not a spelling error.

I get really wide sensing with an AC opto-coupler and a 4.7k resistor.  It triggers on less than 1.5 volts, and of course is good up into probably at least 20 volts.  The actual limit is simply the power dissipation of the SMT resistor, the opto would be good for way more power than it's handling at 20 volts.  The AC opto also eliminates any need for a protection diode.

Locomotive Motion Sensor, Rev. 3 Schematic

Consolidated Leo posted:
It's only a matter of time before this forum recognizes that Arduino is not a spelling error.

I don't get a spelling error with Arduino, I added it to my Firefox dictionary.  It's not the forum that thinks it's a misspelled word.

Attachments

Photos (1)

Leo, I had so many problems with RS485 that I can't keep track of them all ;-)  I used an oscilloscope to watch the quality of the signal, which was *extremely* helpful when evaluating different wire types, bias resistors, and termination resistors.

One thing is that I am using Maxim MAX485 chips, which are not traditional RS485 in the sense that they operate on 5vdc.  I started using the "RS485 Modules" available on eBay for $1/each, which include SMT resistors and capacitors in addition to a MAX485 chip -- and they worked perfectly on my workbench but then would not work when connected to my "real" network -- which consists of 7 modules and a total bus length of only about 10 feet.  Adding that many modules changed the total amount of resistance for the bias resistors, which might have been part of the problem (all of those resistors in parallel reduced the total resistance each time a new module was added.)

In the end, what finally worked for me is the following: I built my own boards (on small breadboards), including a 0.1uf ceramic non-polarized capacitor across the power pins of every chip, and made the bus with shielded twisted-pair wire, and monkeyed with bias and termination resistors until I had the cleanest signal on my oscilloscope.  I think what made the most difference is adding the 0.1uf capacitors -- once I did that, everything started working with 100% reliability.

I wrote my own message protocol which includes a CRC error check and if even one bit is not communicated correctly, my whole system does an immediate emergency stop (like pressing the emergency stop button on your CAB-2 controller -- everything including track power is shut off.)  I also added Transmit and Receive LEDs to each of my boards - controlled by code and not connected to the chip - so I can see when each chip is transmitting or actively receiving a message.  Mostly for fun, but also helpful in debugging.

I bought individual MAX485 chips from both a reputable U.S. supplier (expensive), as well as on eBay for about $1/each -- and in testing, could not find any differences in signal quality.  So the cheap ones on eBay are fine.  Just don't buy the ready-made "RS485 Modules" unless you are only hooking a couple together in close proximity.

I hope that helps!

Randy

gunrunnerjohn posted:

Consolidated Leo posted:

It's only a matter of time before this forum recognizes that Arduino is not a spelling error.

I don't get a spelling error with Arduino, I added it to my Firefox dictionary.  It's not the forum that thinks it's a misspelled word.

Sorry. My apology to the forum.

Randy,

I knew about the modules being setup to work for point to point communication. I saw a video that to use them for multi-drop, you have to remove some little tiny SMT resistors that would otherwise be a problem.

There are supposed to be terminating resistors on both ends of the bus to avoid signal reflection. And for microprocessors, they recommend a pull-up resistor on the A line and a pull-down resistor on the B line.

So you connect the drivers the right way around to Tx and Rx, add a pin for transmit/receive control and in the Arduino you just use the Serial interface. It always sounds so simple when you start out.

They recommend using shielded twisted pair which is what I plan on doing. The shield wire can supply the ground if the two wires can't cut it.

Thanks for the information. It's encouraging to hear that you've got your's working.

Randy thank you for the detailed description on how you achieved your block detection. That is very interesting regarding your RS485 problem. I currently have a test setup with Raspberry Pi and Arduino using RS485. I'm using shields for both from Linksprite. The distance is very very short, but working very well. For points across my layout I plan on building my own Arduino Shields or breakout PCB's using the OSH PCB service. I may just buy more of the shields form Linksprite or just add my own chip to my shields/breakouts, but will use the schematic for their shield as a template. 

Okay, back to the topic at hand. So when doing block detection with DC. Would that screw with the TMCC signal? Also, how would you setup the actual block? Would you isolate both outside rails? Then just add both AC ground and DC ground to the outside rail? Would an RC circuit still be required for Opt Amp? 

Professor Chaos I'm no electrical expert, but how would one size all the components for the RC circuit if using an AC source for the block detection? The only problem I fear is if I ran conventional trains, would they not be detected in the block as JGL mentioned because of the variable AC voltage? I pretty much run in command 98% of the time, but may want to run some of my post war trains on the layout every once and awhile. Do you have any problem with the TMCC/Legacy Signal? I'm assuming that you are just isolating the outside rail for the block. 

Chris

TCA, LCCA

 

 

Here's a diagram of my insulated rail signal driver, this is a sample of running from independent power as stated.  Track voltage doesn't affect the operation in any way, the external supply is powering everything.

Attachments

Photos (1)

How would one hook-up DC ground to the block track? Would you do the same way as if you were using AC ground and just place the DC ground on the outside rail with AC ground? I'm little confused by this and I'm probably over thinking it. I was thinking about using 12 VDC for my block detection, since I will have an ATX power supply for all my Arduinos, Signals, LEDS, and whatever else. I would pretty much not be using the 12V

rail on the power supply, so I might use it. I plan on using all 180W Lionel Bricks for track power. I also have no problem using 14V accessory transformer like Professor Chaos. 

I would use an RC circuit with Optocoupler for protection for any AC ground that may try to get into the circuit though. Then the schmitt trigger for debouncing the circuit. How does one size the components for the RC Circuit for both AC & DC (probably the same for both)? I guess with the RC circuit one wouldn't need about current on the Arduino pin or I/O expander correct? 

Chris

TCA, LCCA

 

 

Take wire from DC ground, connect to outside rail common, job done.

Yes, it's just common with the AC ground from the transformer, no magic here.  You'll notice my previous diagram simply connected the common of the external supply to the outside rail.

gunrunnerjohn posted:

Take wire from DC ground, connect to outside rail common, job done.

Yes, it's just common with the AC ground from the transformer, no magic here.  You'll notice my previous diagram simply connected the common of the external supply to the outside rail.

I figured as much, but wanted to make sure. Does the ground from the DC supply need to be tied to AC ground for track power at the supplies themselves? 

Chris

TCA, LCCA

 

 

Ground is ground the world around.   You can tie it in anywhere to the AC outside track common.

Chris, at the risk of repeating what has already been stated -- I connect the wire from each isolated rail to one side of my relay coil, which becomes "common"/ground when a train bridges a "live" outside rail to the insulated outside rail.  The other side of each relay coil is connected to a 12VAC transformer "hot" side and is always "on."  So providing a ground energizes the coil.

ALL of my power supplies, both AC and DC, have their "commons" and "grounds/negatives" connected together.  So every common/ground is the same as every other.  All AC "hot" transformers must be "in phase" (you can Google that if you aren't familiar.)  So it doesn't matter how much voltage is on the track center rail (in my case, constant 18VAC) -- I only care about getting a ground.  Even if you are using conventional control and have zero volts on the track, your ground is the same -- it works whether you have any power to the center "hot" rail or not.

Simply bridging the ground from one rail to another, and using that to power an AC relay coil, has not caused any problems with my Legacy signals.  I'm still a novice at all this, so it's possible that a relay coil could cause problems without a flyback diode or other inductive voltage suppression -- but I have not seen that problem, and most folks here are not driving coils directly, like I am.  It's also possible that the time-delay-off relays that I'm using already have that protection built-in -- I have not looked closely at the circuit.

For some reason it still doesn't seem to have been made clear that a shcmitt trigger does not debounce an input.  It only filters noise.  Bounce is the effect caused when a switch is thrown or button pushed or wheels bridge an insulated rail, where the contact points rapidly open and close.  You get dozens, or hundreds, of on and off pulses over the course of a fraction of a second.  A micro-controller will read each one of these pulses as a separate on/off event if not debounced in some manor.  Each of these pulses, however is a (near enough) logic high or low, so if for example you were working with a 5 volt system, when you push a button the processor will read a couple dozen pulses of 0 and 5 volts before the contacts settle.  This is solved by using an RC circuit in hardware, which uses a resistor and capacitor to filter out the pulses as it takes time to charge up and then discharge. Or in software by writing code that says to ignore any rapid input changes and only report changes that have remained steady for a given amount of time.

The Schmitt trigger, on the other hand is used to filter inputs with noise, where the voltage of the input is not a full 5 or 0 volts (again assuming a 5v system).  Lets say for the example that the input reads everything below 2.5 volts as a logic low, and everything above as a logic high.  Here when the input is transitioning from low to high there can be noise on the signal, little pulses of say, a tenth of a volt up and down.  As the signal is rising up toward 2.5 volts this noise can cause the input to read many points where the voltage swings above and below 2.5 volts until the low points of the noise are above 2.5v on the way to 5v.  This will cause the logic output to rapidly oscillate high and low each time the input noise goes above or below that 2.5v threshold.  The Schmitt trigger works by providing hysteresis, or a buffer zone between the voltage that switches  the logic high and the voltage to switch low.  As an example if we provide 1 volt of hysteresis on the input, the output will only go high when the input reaches 3 volts.  in turn it will remain high until the input drops below 2 volts.  this effectively filters out the noise on the input as it is not enough voltage change to reach to point where the output will change.  

An input signal with bounce will still have bounce when put through a schmitt trigger, since the bounce is swinging well beyond the hysteresis thresholds of the schmitt trigger.  Debouncing and Hysteresis are both needed for a reliable input signal, but they are two different things doing two different jobs.  In the case of the original reason Schmitt triggers were brought up in this thread, the problem is that the opto coupler may not fully saturate, and when this happens it's output can be some floating value that digital logic could read as anything.  The Schmitt trigger in this circuit works to turn this undefined on/off state into a clearly defined one.  


With the 74165 parallel to serial shift register, a Schmitt trigger is needed as these chips deal in absolute logic and will be undefined with voltages in the middle range.  Through various incarnations way up in this thread I attempted to remove the need for extra parts and complexity in the circuit by using the input pins of a micro-controller which have built in Schmitt triggers on them.  It runs up the cost, but makes the circuit much less complex to put together.  (Though if one accounts for PCB board space the cost difference isn't that much) By using a Mega instead of an Uno, Nano, or ProMini, one can eliminate 10 other chips from the circuit as well as all the wiring and soldering of those parts.  One could also use something like the MCP23017 port expander as it also has built in Schmitt triggers on all inputs, but this isn't as cost effective as just using a Mega clone, as you would need 2 or 3 of them to get the job done, and it's more parts to work with.  Using the Mega also gives 8 times the storage space for your program, allowing much more flexibility and added functionality.  

Anyway, main point is both debounce and Schmitt trigger are needed, but the Schmitt trigger is built in on Arduino micro-controllers as well as on the port expander chips.  (you can find the hysteresis of the port expander on page 28 of it's data sheet from Microchip.)

JGL

$ This is John Galt speaking.  $

“I swear by my life and my love of it that I will never live for the sake of another man, nor ask another man to live for mine.” 

 

 

If you want to know why software debounce is frequently preferred, just check out the price of the hardware option!  Maxim MAX6816EUS+T One channel hardware debounce Chip, $3.41 quantity one, and still $2.25 in hundreds! They must bounce the signals off of gold in the chip.

JGL,

Thanks for the explanation. You make a good point about complexity. I now have a Mega controlling 12 switches on my layout.  It was much easier to put together than the earlier system with shift registers, RC debounce, Schmitt triggers and optocouplers. Here are pictures of the only board that I had to assemble. The board has screw terminals to connect 24 inputs from isolated rails/push buttons. I am using 10v AC power to activate the AC optocouplers (there are 1k resistors soldered to the back of the board to limit current to the  optocouplers).

Mega with optocouplersoptocoupler board

 

Attachments

Photos (2)

JGL,

I know the schmitt trigger doesn't debounce. I'm including as part of the RC debounce circuit. 

Megas are great boards. Love their multi serial capability. 

Professor Chaos - I used an online calculator last night and came up with a debounce time of around 20 ms. Is this correct? I used 5V as the voltage connected to the pull-up and 3V for high, which is the minimum voltage needed to make a digital pin go HIGH.

http://protological.com/debounce-calaculator/

I agree that software debouncing is perferred and usually not a big deal. I think though for what it will cost to build an RC circuit thereare about even. If you are looking to make this open source and want easy for others to assemble then just putting debounce in software doesn't make it easy. Some people maybe not that great with code, so they be better with an RC debounce. A debounce statement in the code may lead to more setup issues. It is a double ended shord, because your are not going to be able to suit everyone. The one thing that is better with code is you can easily change the debounce time. 

 

Chris

TCA, LCCA

 

 

GRJ,

I think it's easy to use just software in this situation because I am only trying to detect when a button is pressed or an isolated rail has been triggered. I only want to throw a switch and change the indicator light when a signal is first received. Nothing else happens until a signal is received to switch the turnout in the opposite direction. My only debounce is to require that a signal is present for 10 consecutive loops of the code before it is considered good. I picked 10 randomly, but it seems to work well. It is short enough that I don't notice the delay when I push a button.  

Yep, that was my point, you either build the hardware with multiple components per channel or pay through the nose for a single chip.  Usually, I do software debounce in the timer routine.

A couple of thoughts regarding debouncing for those who are just learning about this.  If your code is not time-critical, you can use software to just loop for 20ms or so after it sees a contact closure, before moving along with whatever your code needs to do.  If your code *is* very time critical -- i.e. you don't want to use "blocking" code that holds up other operations while you sit around waiting for a switch to stop bouncing -- you can still do this in code using timers.  There are a ton of good tutorials online that you can use to learn about how to do this.

Bear in mind that every switch bounces differently -- 20ms may be plenty for some switches, but others may bounce longer than this, and some may seem to never bounce.  It's easy enough to write a little loop of code that will help you tweak your bounce timer, or if you have an oscilloscope, you can watch the switch bounce and see how long it takes, and adjust your code accordingly.  Of course allow for plenty more than the longest bounce time that you observe.

Also note that a switch can appear to "bounce" when it releases.  When the contacts separate, there is a moment when they are coming apart that can be read as open at one instant and closed at another instant and then open again.  This happened to me, so in my case I simply put a 20ms delay once I saw a pushbutton being released, to give it time to fully release before moving on with my code.

Also bear in mind that you can monitor for contact closures via "polling" where you keep looking at an Arduino (or shift register) input within a loop and wait for it to go low and then call a function to deal with it, or you can use an Arduino interrupt to automatically call a function when an input state changes -- but it's tricky to do software debouncing within an Interrupt Service Routine because you can't use the delay() command in an ISR -- generally you just set a flag that your code will notice has been set at some point.  Interrupts are best avoided by beginners unless you are really interested in learning about them.

The way that you handle bounce is a factor of how important it is for your code to keep going (to not "block" by using delays), and how willing you are to learn some new programming techniques.  If you set up a little proof-of-concept pushbutton (or relay) and small piece of test code, it's fun to experiment and you'll learn a lot in the process, as I did.

Randy

Loop for 20ms?  NOOOO!

I just service the debounce counter in the timer routine, you save the state and the count.  As long as the state stays the same, you decrement the debounce counter.  When it's at zero, you stop updating it, and the fact that it's zero tells you the switch state stored is debounced.  If the switch state is ever detected as changed, you reload the debounce timer and start decrementing it again.  All you have to do to know the switch state is check if the debounce counter is zero and read the switch state.  As for how large a value to use for debounce, as you say, that's dependent on what type of contact you're servicing.

 

Randy,

Exactly my point. There are limitations with both software and hardware debouncing. As I stated previously that is why object oriented programming is important for the Arduino. It allows it to multi task meaning it can run the class functions in the background and keep the loop function running. It allows it to break the boundary of reading line by line. It still is reading line by line, but it reads a line then calls the class and goes to the next line. For example if you have several servos running the program can pretty much move them all at the same time if class is used. Here is a good reference:

https://learn.adafruit.com/mul...uino-part-1/overview

I also agree with not using the delay function. It is best to use a timer to keep the program running.

I'm still thinking about what to use. If we are talking about only a 20 ms debounce time does it make more sense to just use an RC debounce circuit or a times software debounce. Also how does this change the circuit. You will have a 100k resistor on the voltage line into the optocoupler and pull-up resistor on the 5v line, but what else is needed? Some things I have seen on the internet  a diode is added on the input side of the optocoupler. Is a capacitor needed on the output of the optocoupler? 

I'm having a hard time reading the difference between JGL's circuit and Johnh's. Maybe a readable schematic can be posted? JGL has be sold on the 12v ground. I just need to determine the circuit.

Randy I do have a quick question for you. What is your longest run and what type of wire did you use for your RS485 bus?

 

 

Chris

TCA, LCCA

 

 

Chris,

As I mentioned in my RS485 post, I'm using shielded twisted pair wire, and the maximum run is about ten feet.  I tested it with a length of wire that was 100 feet long and it worked fine, but only tested as point-to-point with a total of two MAX485s.  But when you actually start connecting multiple MAX485 modules off of the main bus, things can get interesting.  Because the bypass capacitors that I mentioned were what finally fixed the last of my problems, it's possible that you could use just about any wire and it would work fine -- I don't know if non-twisted non-shielded wire was ever part of my problem, considering how close my modules are to each other.

Randy

Randy P. posted:

Chris,

As I mentioned in my RS485 post, I'm using shielded twisted pair wire, and the maximum run is about ten feet.  I tested it with a length of wire that was 100 feet long and it worked fine, but only tested as point-to-point with a total of two MAX485s.  But when you actually start connecting multiple MAX485 modules off of the main bus, things can get interesting.  Because the bypass capacitors that I mentioned were what finally fixed the last of my problems, it's possible that you could use just about any wire and it would work fine -- I don't know if non-twisted non-shielded wire was ever part of my problem, considering how close my modules are to each other.

Randy

Thanks. The reason why I asked is I was doing research on the wire and they said to use shielded twisted pair. I just was wondering what you used.

Chris

TCA, LCCA

 

 

Twisted pair is actually fairly important for RS485 signals.  Since the signals are differential, the twisted pair prevents EMI from upsetting the signal unless it's very strong.  The EMI is induced in equal and opposite directions on the twisted pair, that results in minimal signal degradation.  At high data rates, twisted pair also prevents excessive radiated EMI from the lines.  RS422 and RS485 really need twisted pair if it's going any distance.

gunrunnerjohn posted:

Twisted pair is actually fairly important for RS485 signals.  Since the signals are differential, the twisted pair prevents EMI from upsetting the signal unless it's very strong.  The EMI is induced in equal and opposite directions on the twisted pair, that results in minimal signal degradation.  At high data rates, twisted pair also prevents excessive radiated EMI from the lines.  RS422 and RS485 really need twisted pair if it's going any distance.

Thanks John! I thought about the wire type today and everywhere I read said the shielded twisted pair is required for RS485

Chris

TCA, LCCA

 

 

The shield is optional, I've run RS422 (same type of signal) at least 1000 feet with just three wires, the third being the ground reference.  As we discussed before, the ground reference is only needed for stuff that may have a different ground reference, for stuff all in the same room, it wouldn't typically be needed.

Chris,

The circuit I am using is very simple:

optoSchematic_schem

The 10v AC is from the same transformer that I am using for track power, so it has the same common as my isolated rail feeds. The Arduino pin is set as INPUT_PULLUP initially, and then it goes to LOW when the optocoupler is activated. I think JGL is just using a separate 12v DC source to trigger the optocoupler. He also added a diode on the inputs. The ground of the DC is connected to the layout ground.

Here is a link to my  Arduino sketch.  

Ok, first, for software debouncing, or any other timing task, the delay function is never the right choice.  It can be the easier option, and in really simple programs that are only doing one thing it can be a time saver in programing, but it shouldn't be in any program that is doing anything more complex than flashing an led on and off.  I wish they never put it in the blink sketch in the first place and just taught people to use timers from the start.  Timers take a couple more lines of code, something like this for a debounce, as I posted earlier in the thread:

CurrentTime = millis();
MB1_State = digitalRead(ManualButtonOnePin);
if (MB1_State != MB1_StateLast) ManualButtonOneClock = CurrentTime; 
if (CurrentTime >= ManualButtonOneClock + DebounceTime) ManualButtonOneCurrentState = MB1_State; 
MB1_StateLast = MB1_State;

There are plenty of tutorials online on how to use simple timers like this, or how to use interrupt timers for things where timing is critical.  In most cases when dealing with train-related projects, half a millisecond one way or the other is not that big of a deal.  


Someone asked for how to hook things up, so here's how I do it:  

insulated railIns-rail-trigger SCh

Sorry for the poor drawing.  The schmatic shows an RC filter used as this circuit was stolen from another project of mine (C4).  It's not needed for the anti-derail, switch machine controller, but is there to give a steady 'ON' from AC input sources.  

I choose to use a diode and one-direction Opto-coupler because it's dirt cheap (4 cents per channel), but you could also use a bi-directional Opto if you wanted and remove the diode (D5)

A pull-up resistor is needed on the logic-level output, as the opto can only pull the line LOW.  This is built in on Arduino boards, but has to be turned on.  The MCP23017 port expander also has internal pull-ups, but I've not done the homework on how to turn them on.  

JGL

$ This is John Galt speaking.  $

“I swear by my life and my love of it that I will never live for the sake of another man, nor ask another man to live for mine.” 

 

 

Attachments

Photos (2)

Add Reply



OGR Publishing, Inc.
33 Sheridan Road, Poland, OH 44514
330-757-3020

www.ogaugerr.com
×
×
×
×
×