Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Momentary button and interrupt


  • Please log in to reply
5 replies to this topic

#1 Nicolai

Nicolai

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationDenmark

Posted 18 January 2014 - 12:13 PM

So, you will probably start seeing tons of beginner questions from me :)

I hope you are patient people.

 

Anyhow, I have a button like this one:

http://www.adafruit....chnical_Details

 

I'm trying to have it turn its own LED on.

So, I've been using this example: http://forums.netdui...arch=1#entry339, but I am unsure how I need to hook the button up.

 

From what I have found out, C (on the button) is where I will always have a wire hooked up.

Then, I can chose NC or NO, which controls wether it is always on or always off, with the opposite being true while being pressed.

 

So, I assume always off is what I want? Then just register when it goes on?

But how will I even accomplish this?

 

Do I hook GND up to C and a digital IO to NO?

The code example has a pin called ONBOARD_SW1. I have no clue what that is supposed to be.



#2 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 18 January 2014 - 07:51 PM

Hi Again,

 

The "ONBOARD_SW1" is the name of the button on the Netduino board.

You can configure your program to use the button as an input instead of as a reset switch.

I won't offer you any code as I know it is the otherway up to the Netduino Plus v1 that I have.

The onboard switch is a good way to practice the software without connecting any external hardware.

 

Your push button would "normally" be wired between Gnd and a spare GPIO pin. As you have already said, you would want to use common and "N.O." connections. In this mode, it does not matter which way round they are - its just a piece of metal inside. When you create the GPIO in your software, use the pull up resistor mode - this way you don't need an external resistor. When the button is not pressed, the input will be pulled high by the internal resistor, and when you press the button, the input is pulled to ground by the switch.

 

Since this is a changeover switch, with NO and NC contacts, there are two other ways you might wire it up:

 

You could use the NC contact instead of the NO. In this case, the input will be pulled low when the button is not pressed, and high when pressed.

 

You could use both contacts, this will be useful if the button is more than 30cm or so from the Netduino. With a long lead length the internal pullup reisitor in the Netduino may not be strong enough. The circuit may not be reliable. So in this case, connect the common to the netduino GPIO, connect NO to +3.3V, and NC to Gnd. When creating the GPIO, disable the pullup resistor mode (you don't need a resistor - because the switch pulls the input high and low). (You could reverse the NO and NC pins to get the low/high to be reversed - BUT ONLY CONNECT common TO THE NETDUINO - DO NOT CONNECT COMMON TO THE +3.3V or Gnd rails).

 

Hope this helps - Paul



#3 ShVerni

ShVerni

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationNew York, New York

Posted 18 January 2014 - 08:10 PM

Hello,
 
Beginner questions are the always welcome!
 
Paul is absolutely correct about everything, but just to elaborate a bit:
 
Here's how I've used those same buttons before:
 
C --> Ground
NO  --> Input Port (in example, Pin D0)
+ --> Output Port (in example, Pin D1)
-   --> Ground
 
The buttons have a built in resistor for the LED so there's no need for a separate current limiting one.
 
Here's what the code would look like to turn the LED on when the button is pushed:

public class Program
    {
        private static InterruptPort button = new InterruptPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
        private static OutputPort LED = new OutputPort(Pins.GPIO_PIN_D1, false);
        public static void Main()
        {
            button.OnInterrupt += button_OnInterrupt;
            Thread.Sleep(Timeout.Infinite);
        }

        static void button_OnInterrupt(uint port, uint status, DateTime time)
        {
            if (status == 0)
                LED.Write(true);
            else 
                LED.Write(false);
        }
    }
}

You can find out more about interrupts here:
http://www.youtube.c...h?v=PbZnjutqtWs
 
If you're uncomfortable with interrupts, you can also do the same thing with a simple loop:

public class Program
    {
        private static InputPort button = new InputPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.PullUp);
        private static OutputPort LED = new OutputPort(Pins.GPIO_PIN_D1, false);
        public static void Main()
        {
            while (true)
            {
                LED.Write(!button.Read());
                Thread.Sleep(500);
            }
        }
    }

Hope that helps!



#4 Nicolai

Nicolai

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationDenmark

Posted 19 January 2014 - 03:06 PM

Thank you guys, that's working great!

However, when I press my button, I get into my interrupt handler, maybe 15 times, not just once.

Does that mean, that the entire time the button is pressed, it will fire events?

 

I don't get just one event when it is pressed or released?



#5 ShVerni

ShVerni

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationNew York, New York

Posted 19 January 2014 - 04:21 PM

Hi again Nicolai, and welcome to the wonderful world of bounce!
 
What you're experiencing is perfectly normal, and is called bounce. We like to think that buttons behave ideally, but that's far from the truth. I won't go into too much detail, since there are many excellent articles on bounce out there already. In short, when you push a button the physical contacts will actually bounce off each other a bit, somewhere on the micro to millisecond scale, before the button settles into a proper "on" or "off" position. So as it bounces it will appear to the microcontroller to be flipping on and off rapidly.

 

Here are two great posts on debouncing with the Netduino, which I'll summarize a bit below:
http://forums.netdui...input-debounce/
http://forums.netdui...ure/#entry55151
 
There are two ways to deal with bounce: Hardware debouncers and software debouncers. Hardware debouncers are better since they prevent the noise from even reaching the microcontroller, but they require additional hardware, maybe some math, and are more complicated. Software debouncing is easier to do, but will require the microcontroller to do some work, so it may still affect performance.
 
The simplest hardware debouncer (and certainly not the best one) is a capacitor and resistor that you place across your switch. So you'd connect the positive terminal of the capacitor to the positive side of the switch (in this case the GPIO) and the negative side, through a resistor, to the negative part of your switch (in this case, ground). The values of the capacitor and the resistor will affect how much debouncing you get. I'm not familiar will all the math involved, but I'm sure you can find someone else who's laid out the equations.
 
Here's how you'd implement a software debouncer for the above code:

 public class Program
    {
        private static InterruptPort button = new InterruptPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
        private static OutputPort LED = new OutputPort(Pins.GPIO_PIN_D1, false);
        private static DateTime lastEvent = DateTime.Now;
        public static void Main()
        {
            button.OnInterrupt += button_OnInterrupt;
            Thread.Sleep(Timeout.Infinite);
        }

        static void button_OnInterrupt(uint port, uint status, DateTime time)
        {
            //Check to see if the last event was more than 500 milliseconds before this trigger			    
            if (time.AddMilliseconds(-500) > lastEvent)
            {
                //Update when the last event was (we subtracted 500 milliseconds before, so now we need to add them back)
                lastEvent = time.AddMilliseconds(500);
                if (status == 0)
                    LED.Write(true);
                else
                    LED.Write(false);
            }
        }
    }

You'll notice the event will still fire, but now it won't do anything unless the time between events is greater than 500 milliseconds (or whatever you set this too). This is not the most elegant debouncer out there, it's just a quick one to show how it can be done, and there are many other examples (including the two links I provided) that you can use.
 
Using a software debouncer you probably won't notice any difference, since the event is still triggering and the LED would be blinking too fast for you to see when bouncing. But if your event did something, like adding to a counter, this would help by discarding events triggered by bouncing.
 
By the way, using the loop method instead of an interrupt won't cause this problem since the loop polls the button preiodically. However, interrupts are certainly more elegant, responsive, and very useful, so it's good to learn debouncing.
 
Good luck!



#6 Nicolai

Nicolai

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationDenmark

Posted 20 January 2014 - 01:56 PM

Thank you. Makes sense. Nothing ever works as ideally as I wish :)

 

This forum is great.






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.