HOME - - - - - - - - Table of contents, my Arduino "How To" articles
Other material for programmers    Delicious Bookmark this on Delicious   Recommend to StumbleUpon

Simple Digital Inputs, dealing with "bounce"

Without using a blocking routine

This tutorial presents another answer to the problems which arise when you have an input which "bounces" as it is made or opened. We looked at the issue of bounce in an earlier tutorial, which included a simple answer to the problem. Sadly, the simple answer involved "blocking" code. While users pressed the button which provided the input, the Arduino sat in a small loop, ignoring everything else.

(At an even simpler level, if you want help with connecting an input to an Arduino, I have a page for you on that subject.)

Some background....

Compared to our computers, even the "little" Arduino, we humans are dreadfully slow.

There are many times when your assumptions about what your Arduino is "seeing" will get you in trouble.

Many of the things, especially switches, which you might connect to an Arduino exhibit switch bounce or switch chatter

Consider a simple momentary switch, the sort you would have on a doorbell. You might think that if you wire it up right, then the Arduino will see a 0 on the input most of the time, then a 1 while the button is pressed, and then the input "should", you would think, go back to 0. If I were to write out the state of the input every millisecond, with "...." for long strings of 0s or 1s, you would imagine, I suspect, that one press and release of the button would look like.....


In fact, what will happen with many switches is more like....


The difference is that, for a moment or so after the first closing of the switch, as you press the switch down, the connection is broken and made and broken several times, before settling down in the "made" state. This is discussed more thoroughly in the simpler tutorial on switch bounce which I gave you a link to a moment ago.

A non-blocking way to read switches which bounce

This tutorial (at this time!) is not complete with Arduino code. This is unusual for one of my Arduino tutorials. But it is what I have time to present now. You want perfect? Happy hunting!

At the heart of my solution is an array of, say, five elements. (You can change that, but making it less than 5 may be a mistake which will lead to faulty results.) Although each element of the array will hold a simple boolean value ("true" or "false"), I suspect that you won't lose much by using an array of byte values. I'm calling the array baSwitch0State. ("ba" for "byte array"). The zero in the variable's name is to pave the way for monitoring more than one switch. A skilled programmer could use a two dimensional array to solve the problem of monitoring multiple switches. I will leave that as "an exercise for the student", and, to monitor a second switch, would just set up parallel byte array called baSwitch1State. The indices for the array elements will be 0-4.

You might as well... it could prove helpful... also create and use a constant called bSwitch0MaxIndex, which would be set to 4, if there were 5 elements (0-4) in the array.

I also need a variable called bSwitch0Where. (If I were monitoring two switches, there would be a parallel baSwitch1Where, too.)

For my scheme to work, you have to give me a program in which the "loop()" procedure is executed many times a second, and my "boSwitch0InputHigh" function call is executed each time the loop executes.... I hope you'll see why by then end. If you don't, look at it again.

My boolean function boSwitch0InputHigh will return true if, in simple human terms, the input is returning "high".

In fancier, more theoretical computer terms, here is what the programming inside boSwitch0InputHigh does...

First it samples the input, and gets a "high" or a "low". This may be coming in because the input is in that state consistently at the moment, or it may be that the Arduino is "seeing" a switch which is bouncing... which is why we need the complexity I am about to go into....

When the program knows the state of the switch at this instant, it stores the state in an element of the array baSwitch0State. Stores a 1 if the input is high, a zero if the input is low.

Next, before returning a "true" or a "false", boSwitch0InputHigh adds up all of the values in the five elements of baSwitch0State. Unless you want to make the routine "reluctant" to "see" a high state, if the total of the five values is more than 2, you have the subroutine return "true", i.e. the switch is set so that the input is being driven high.

Now then... a detail which I hope you didn't notice yet.

I said that after the program checks the state of the switch at this instant, it stores the state in an element of the array baSwitch0State.... but I left which element vague.

Before looking at the code for how we will do it, I will explain in different terms what we want to do. We want to have the array baSwitch0State be a mini-history of recent instantaneous readings of that input. If there are five 1's in the array, it means that every time we have looked at it over the past 5 cycles, it has been high.

Recording History In An Array

So how do we accomplish this?

First we need to think about initializing the elements of our array baSwitch0State. In setup(), we will make elements 0,1,2,3 and 4 equal, respectively, 0,1,0,1 and 0... IF we don't know what state to expect the input to be in when the program in the Arduino starts. (If we can reasonably expect that the input will be low when the program starts, we would initialize the array with 0,0,0,0 and 0. Conversely, if we expect that the input will be high at first, we initialize the array with 1,1,1,1 and 1.)

Remember I said that besides the array, we'd also be using a variable I decided to call bSwitch0Where? This we will need to initialize with zero.

Each time the function is called, the current state of the input will be stored in an element of the array, as follows...

The code is pseudo-code... you may have to tweak it to make it exactly right for an Arduino... Please write in and tell me the exactly right stuff.

if (input low)
  else {baSwitch0State[bSwitch0Where]=1;}

The part (input low) would be replaced by something which returns whether the input is low at this instant.

Immediately after that, we would do...

if bSwitch0Where>bSwitch0MaxIndex
  then bSwitch0Where=0

The subroutine's code then goes on to add up all of the values in the array, and return "true" or "false" based on the number of 1's in the "history" of the input's state.

That's it! Think about it if it doesn't yet make sense. It really isn't very "clever", but it is clever in the sense that a safety pin is clever: Simple enough to understand when someone else has thought of it.

Final details

You are not completely out of the woods yet. Depending on how "slow" your main loop is... does it execute hundreds of times per second, or merely ten times?... and how bouncy your switch is, and how soon it "settles" after being made or broken, you may need to increase the number in bSwitch0MaxIndex. Or, if your loop is very fast, introduce a tiny "waste time" command in it. The history of states stored in baSwitch0State needs to span more time that you switch bounces for.

For extra credit...

The algorithm above proposes adding together all of the elements of baSwitch0State each time you call it. A more clever... possibly unnecessarily clever... "solution" would work as follows. (It does fewer operations to achieve its goal, but how it works is not as immediately obvious.)

During setup(), you would do noting different. You'd fill all elements of the array, set bSwitch0Where to zero, have constant bSwitch0MaxIndex as before.

You'd also have a new variable, bSwitch0ArrayTotal, in which you would keep the total of the values in the array.

As before, although we hadn't given where the total would be a name, you'd look at bSwitch0ArrayTotal to see if the function should return "true" (i.e. the input has been high more often than not, in the history we have recorded) or "false".

The difference would be that each time through the loop, instead of re-adding all elements of the array, we would do...


if (input low)

  else {baSwitch0State[bSwitch0Where]=1;

if bSwitch0Where>bSwitch0MaxIndex
  then bSwitch0Where=0

   Search this site or the web        powered by FreeFind
  Site search Web search
Site Map    What's New    Search

The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with material you might find useful.....

Sequenced set of tutorials on Arduino programming and electronics interfacing.
Tutorials about the free database supplied with Open Office version 2. (If you experienced Adabas with Star Office, ooBase is nothing like it!)
Some pages for programmers.
Using the parallel port of a Windows computer.

If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service.

Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!

Click here to visit editor's Sheepdog Software (tm) freeware, shareware pages.

If you liked the material above, here is more from the same source....

Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?FrmAht" I added to that link causes your browser problems. Please let me know, if so?

Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.

To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed!

Valid HTML 4.01 Transitional Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org

Why does this page cause a script to run? Because of the Google panels, and the code for the search button. Why do I mention the script? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....