Wireless Communications With ChibiArduino 04: Wireless Pushbutton

Intro

There are many situations where I wished I could have had a remote pushbutton switch to reset or control some device. It could be when I’m on a business trip and I just need to power cycle a server or when I just want to turn off a light at home that I may have inadvertently left on. Something seemingly as simple as a pushbutton takes on much more importance when you can use it to control something remotely. Even though you’re only communicating one bit of information, i.e. ON or OFF, that bit and the timing of that bit can become hugely valuable. In this tutorial, I’m going to first start off with detecting and communicating a single pushbutton event and then extend that to communicate multiple pushbutton events.

Hardware

On the hardware side, I’m going to use our Freakduino 900 and FreakUSB 900 MHz devices. I like the 900 MHz devices because the band is less crowded than 2.4 GHz and the range is better. If I have a choice between using 900 MHz and 2.4 GHz, I normally choose 900 MHz.

I’m also going to wire up a single pushbutton and connect it to my board. It won’t be a thing of beauty but should demonstrate the concept. One thing to understand working with pushbuttons is it’s not as simple as it may seem at first glance. Pushbuttons are mechanical devices and don’t have clean ON and OFF connections. When you make contact, there are tiny little micro connections that get made and broken before you get a solid ON. The same goes for turning them off or breaking the connection. If you’re not careful, you’ll end up detecting all of the small little connections that happen which could result in phantom on/off transitions. This could potentially be disastrous so you will need to do something called debouncing.

The small on/off transitions that happen are called “signal bounces”. What you need to do is “debounce” the signal which means to ignore the signal transitions and wait for it to be stable before sampling it. Once it’s stable, you can make your decision to see if it’s ON or OFF.  Typically this will be done by waiting some set amount of time after you detect a signal transition to re-sample the signal. In this case, what I will do is wait until the typical bounce is gone before I detect any further transitions to prevent false detections.

I’ll be wiring up the pushbutton as shown. The pullup resistor is not needed because I’m going to use the internal pullup resistor inside the AVR, the microcontroller behind the Arduino platform. In this case, I’m be putting the output of the pushbutton into digital pin 3 of the Freakduino board.

Wireless Pushbutton (Singular)

Let’s get started with a single pushbutton to demonstrate how to detect a button event along with the debouncing. The method I’ll be using is called polling which means I will constantly be reading the pushbutton status to see if the state of the button changed since the last time I read it. If I detect a change, then I’ll act on it.

It’s not beautiful, but it works…

The pin connection to the Arduino

Here is the code for the transmit side of the connection. This is the side that the button is connected to.

Tx Code

For the transmit code, I start out with #include “chibi.h” which brings in our chibiArduino library. After that, I start with our define macros which will define the parameters I’ll use in the code. For the pushbutton sketch, I’m going to have three parameters. The first two are common for the Tx side of the code. They will be our destination address and the payload size. I’ll be using our standard destination address of 3 and our standard payload size of 100 bytes. You’ll see later I only use one byte of the actual payload so this can actually be scaled down to 1. However to maintain consistency, I’ll just use 100 bytes for now. The final #define macro is the debounce delay. This is the time in milliseconds that I’ll wait after I detect a transition before I allow another transition. As I mentioned earlier in the hardware section, the debounce will prevent us from detecting false transitions. To properly time the debounce, I actually need to view the signal on an oscilloscope and also add additional circuitry. However in this case, I’ll use some trial and error to time the debounce so I don’t get false transitions. In this case, I’m taking a guess that 30 milliseconds will be enough to prevent a false transition detection.

As mentioned, I’ll be using digital pin 3 for the pushbutton input to the Freakduino 900 board. I’ll also need to have a special variable called prevButton which will record the previous state of the button. This way, I can check to see if a transition occurred on the button. Finally, I declare our byte buffer which I’ll use to transmit the data. I declare it with a payload of 100 bytes, but actually, I’ll only use 1 of those bytes.

In the setup, I’m going to initialize the pin for the pushbutton to Digital Pin 3 and also set it to INPUT_PULLUP. This means that I’m going to use the pin as an input but I’m also going to use the internal pullup on that pin.  The pullup simply means that when the pushbutton is not pushed, the pin won’t be in an unknown state, aka floating. By adding a resistor to the power rail, I can introduce enough current to force the pin to a HIGH value when the button is idle. Since this is a known value, I can assign a value of 1 or HIGH to the idle state of the pushbutton. When the button is pushed, it will make a direct connection to the other pin which is connected to GND or LOW. Knowing this, when I detect a LOW on that pin, that means that the button is pushed and I can register an event. With well defined values, it’s easy to test for those conditions in the code. After I initialize the pushbutton input pin, I then initialize the chibiArduino stack by calling chibiInit(). This prepares the chibiArduino stack for usage. Here is a circuit diagram of the pushbutton. The pullup resistor is actually inside the AVR.

 

This takes us to the loop function where all of the work will be done. The first thing I do here is read the digital pin to see if there is any change of state. After reading the pin, I compare the current value of the pin to the previous value I read. If those values are equal, no change of state occurred. If the current value is not equal to the previous value, then a transiation has occurred. I then check to see if the pin has transitioned to the LOW or “active” state. If it has, I consider that a button push and take action.

When a button push occurs, I transmit a magic number to the receiver to indicate that a button push occurred. The value of the magic number doesn’t really mean that much, but it just indicates that a button push occurred to the receiver. You can just as easily transmit a 0 or 1,  but I happen to like 0x55 because it contains an alternating set of 1s and 0s. After transmitting, I go into a delay for the DEBOUNCE_DELAY number of milliseconds or 30 milliseconds. This is where the signal debouncing occurs. Yes, debouncing just means waiting! Ideally, I should only detect one button event every time I push the button. If I detect two or more button events on a single push, than I need to increase the debounce delay. If I find the pushbutton isn’t as responsive as I need, I can decrease the debounce delay as long as I don’t get multiple detections per single event. It’s not exactly a scientific way to handle a pushbutton but it gets the job done. In professional applications, you would actually need to use a more precise method which requires triggering an interrupt and writing an interrupt service routine. Stay tuned for that tutorial later.

Finally, the magic happens in the final line where I assign the previous button value to the current value. This will help us determine if a transition occurred on the next iteration of the loop. You might have also deduced that if a button push occurred faster than one loop cycle, it’s possible we don’t detect the transition. This is an inherent flaw of the polling method we are using. If we have a long delay inside the loop function, it’s very possible we will miss button pushes. Hence this method of detecting button pushes is easier to understand and write but can be a bit dangerous if our loop code gets too long.

Rx Code

Here is the code for the receive side of the wireless link:

For the receiver code, I start by bringing in the chibiArduino library using #include “chibi.h”. I then define our standard #define macros. In this case, I specify our device address which needs to match the destination address specified in the transmit side of things. I am also using a payload size of 100 bytes of which I’m only using one byte in this case. I also added a #define for the magic number that I’ll be checking for.

In the setup function, I initialize the serial port to 57600 bps using the Serial.begin() method. I then initialize the chibiArduino library by calling chibiInit() and set the short address to match the destination address I’m sending to in the transmitter.

In the loop function, I first check if I received any data by calling chibiDataRcvd(). If this returns true, data has been received and I  then call the chibiGetData() function and pass in my byte buffer. The function returns the length of the bytes received which in this case should be one byte. If the len is zero, then I received invalid data and should exit the current loop.

Finally, I check to see if the byte I received is equal to my magic number. If the byte is equal to my magic number, then that indicates a button push and I output a line on the serial port indicating I detected a button push. This is the code for a single button push.

Wireless Pushbuttons (Plural)

For a slightly more complex but useful example, lets extend the case to where we have multiple buttons. We actually have to start using arrays to specify our buttons but in this case, we can extend the code we previously wrote to handle the case where we have multiple buttons that we need to handle. If you’re not familiar with C++ arrays, I recommend checking out this or similar tutorials.

Tx Code

The beginning of this code is essentially the same as the case for the singular button. I needed to add the #define NUM_BUTTONS macro to make things easier in dealing with the arrays. I also added a macro for the magic number which I’ll use to indicate a button push. You may also notice that the debounce delay has been decreased by 1/3. This is because we have a debounce delay for each button that I’m using so the aggregate sum of the debounce delays of all three buttons will now be equivalent to the debounce delay we used previously.

For the buttonPin and prevButton variables, these have both become arrays to handle multiple buttons. In this case, I need to specify the number that each button pin will be using. I also initialized the prevButton values to the idle value of 1.

In the setup function, I used a for loop to initialize all the button pins to be INPUT_PULLUP. This is the nice thing about working with arrays since they play quite efficiently with for loops.

In the loop function, you can see that everything is now wrapped in a for loop as well. Each loop iteration, I run through three iterations checking if each button was pushed. Each iteration that I go through, I need to do the same sequence of actions as in the singular button case. I first read the button, then check to see if its the same as the previous value of the same button. If it is, then I check to see if its been pushed. If it has, then I insert the magic number into a three byte array where the position that I insert into corresponds with the button that was pushed. I then transmit the three byte arrray to the receiver and then do a delay to debounce the button.

Finally, I assign the previous button value in the array to the value that I read on the corresponding button pin.

Rx Code

On the receive side, the changes to extend the code to detect multiple button pushes is also quite small. In the beginning section of the code, I added one define for the NUM_BUTTONS macro which sets the number of bytes we are expecting based on the number of buttons.

In the loop function, after we detect a receive event and retrieve the data, I broke the code into a for loop to loop through each data byte corresponding to each button event. If I see a magic number, I print out the button number that the magic number occurred in based on the position in the byte buffer.

That’s pretty much it for extending this code from a singular button push event to handling multiple buttons.

Application

I hope this tutorial was useful in practically applying how a wireless button push event can be implemented. There are many applications this can be used in. This is an example of using multiple pushbuttons wirelessly to create a midi controller that controls a music sequencing program called Ableton Live. I put together a set of pushbuttons I could conceal in my hand, then sent the button events wirelessly to a received connected to the PC. The receiver attached to my PC interpreted those signals to MIDI values and sent them into Ableton where they triggered specific events such as starting and stopping different tracks of music.

Hopefully this tutorial can give you some ideas and concrete steps to try out to implement your own wireless pushbuttons. They’re quite useful in a variety of applications and you can do some fun and useful stuff with them.

Support FreakLabs

If you enjoyed this tutorial and are curious to learn more about wireless, please show your support by checking out the FreakLabs shop. All the boards used in this tutorial can be purchased here . Thank so much!