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

External buttons problem


  • Please log in to reply
19 replies to this topic

#1 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 07 November 2010 - 04:48 PM

Hi, i'm using 2 external buttons (like this http://rocky.digikey...PS1024A-RED.jpg) and 5 leds on my board.
I'm trying to code a simple program that shifts a lighted led, right or left depending on the pressed button.
The problem is that the routine that shifts the led, is executed more time during the "pressing" action.
How can avoid this? here is my code:

I've an array of led with only 1st one setted on true.

Initializating 2 buttons...
button1 = new InterruptPort(Pins.GPIO_PIN_D8,true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelHigh);
button2 = new InterruptPort(Pins.GPIO_PIN_D9, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelHigh);

Linking with event handler...
button1.OnInterrupt += new NativeEventHandler(button1_OnInterrupt);
button2.OnInterrupt += new NativeEventHandler(button2_OnInterrupt);

That's just one of the 2 methods, one make the led shift to right, the other to left.
        static void button1_OnInterrupt(uint pid, uint stato, DateTime time)
        {
            button1.DisableInterrupt();
            ledON = (ledON + 1 == ledCount ? 0 : ledON + 1);//if last led, i restart from 1st
            for (int i = 0; i < leds.Length; i++)
            {
                if (i == ledON)
                    leds[i].Write(true);
                else
                    leds[i].Write(false);
            }
            //Thread.Sleep(500); also tested with a delay but nothing
            button1.ClearInterrupt();
        }

I noted that seems to store all others interrupts in a queue, and after an execution of the method, executes it again (2-5 time also)
tnx in advance, Giovanni

#2 Marius

Marius

    Advanced Member

  • Members
  • PipPipPip
  • 59 posts
  • LocationCenturion RSA

Posted 07 November 2010 - 05:06 PM

Giovanni You can start by selecting a edge triggered interrupt. This way the interrupt will only happen once no matter how long you haold the button. On a level triggered interrupt it can happen several times while you hold the button.
If at first you don't succeed, then try and try again.

#3 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 07 November 2010 - 05:21 PM

Hi NduVino,

Welcome to the Netduino community.

As Marius mentioned, you'll want to use a different option when you create your InterruptPort.

Instead of using InterruptEdgeLevelHigh as the final parameter in your constructor you'll want to use:
// currently:
button1 = new InterruptPort(Pins.GPIO_PIN_D8,true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelHigh);

// change to:
button1 = new InterruptPort(Pins.GPIO_PIN_D8,true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeHigh);

"High" triggers your event when the input goes from low to high. "LevelHigh" (your current selection) triggers your event over and over again while the level remains high.

Chris

#4 Marius

Marius

    Advanced Member

  • Members
  • PipPipPip
  • 59 posts
  • LocationCenturion RSA

Posted 07 November 2010 - 05:33 PM

Chris, You missed your calling teacher!!
If at first you don't succeed, then try and try again.

#5 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 07 November 2010 - 05:41 PM

Tnx you both for answering. I've made the correction but still nothing... that's the video test: http://dl.dropbox.co...896792/test.mp4 I've pressed 2 times the button, and instead to light 3rd led, ... you can see... I have also had to add EnableInterrupt() after ClearInterrupt() because buttons worked only one time. Any idea?

#6 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 07 November 2010 - 05:43 PM

can you post your complete source code?

#7 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 07 November 2010 - 05:46 PM

NduVino,

Also...try removing the Disable/Enable/ClearInterrupt commands, and let's see what that does. [I don't remember off the top of my head, but I believe one can request that the InterruptPort re-trigger if one plays with these too much.]

[And yes, as bill mentioned...please post your latest and complete code.]

Chris

#8 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 07 November 2010 - 05:56 PM

that's all
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.Collections;

namespace Hallo_world
{
    public class Program
    {
        static InterruptPort button1;
        static InterruptPort button2;
        static OutputPort[] leds;
        static int ledON;
        static int ledCount;

        public static void Main()
        {
            ledON = 0;
            ledCount = 5;
            leds=new OutputPort[ledCount];
            leds[0] = new OutputPort(Pins.GPIO_PIN_D0, true);
            leds[1] = new OutputPort(Pins.GPIO_PIN_D1, false);
            leds[2] = new OutputPort(Pins.GPIO_PIN_D2, false);
            leds[3] = new OutputPort(Pins.GPIO_PIN_D3, false);
            leds[4] = new OutputPort(Pins.GPIO_PIN_D4, false);

            button1 = new InterruptPort(Pins.GPIO_PIN_D8,true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeHigh);
            button2 = new InterruptPort(Pins.GPIO_PIN_D9,true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeHigh);

            button1.OnInterrupt += new NativeEventHandler(button1_OnInterrupt);
            button2.OnInterrupt += new NativeEventHandler(button2_OnInterrupt);

            while (true)
            {
                Thread.Sleep(Timeout.Infinite);
            }

        }

        static void button2_OnInterrupt(uint pid, uint stato, DateTime time)
        {
            ledON = (ledON - 1 == -1 ? ledCount-1 : ledON - 1); //if 1st led, i restart from last
            for (int i = 0; i < leds.Length; i++)
            {
                if (i == ledON)
                    leds[i].Write(true);
                else
                    leds[i].Write(false);
            }
        }

        static void button1_OnInterrupt(uint pid, uint stato, DateTime time)
        {
            ledON = (ledON + 1 == ledCount ? 0 : ledON + 1); //if last led, i restart from 1st
            for (int i = 0; i < leds.Length; i++)
            {
                if (i == ledON)
                    leds[i].Write(true);
                else
                    leds[i].Write(false);
            }
        }

    }
}

Could it be a problem with the bouncing during button's press/release?

UPDATE:
I added a 3rd button: the onboard microswitch. I copied the forward event code into the new handler, and works!
What could be the problem?

#9 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 08 November 2010 - 12:18 AM

UPDATE:
I added a 3rd button: the onboard microswitch. I copied the forward event code into the new handler, and works!
What could be the problem?


Are your external pushbuttons wired to ground or to power?

Chris

#10 Marius

Marius

    Advanced Member

  • Members
  • PipPipPip
  • 59 posts
  • LocationCenturion RSA

Posted 08 November 2010 - 04:13 AM

The best way to connect the switches is to have a resistor (1k - 10k) connected to 3.3v and then have the switch pull down to gnd. Use a falling edge interrupt. Just copy the switch circuit on the Netduino schematic.
If at first you don't succeed, then try and try again.

#11 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 08 November 2010 - 09:36 AM

The best way to connect the switches is to have a resistor (1k - 10k) connected to 3.3v and then have the switch pull down to gnd. Use a falling edge interrupt. Just copy the switch circuit on the Netduino schematic.


The buttons are connected to ground

#12 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 08 November 2010 - 09:40 AM

The best way to connect the switches is to have a resistor (1k - 10k) connected to 3.3v and then have the switch pull down to gnd. Use a falling edge interrupt. Just copy the switch circuit on the Netduino schematic.


but enabling the pullup by code, it shouldn't be necessary an external pullup...

#13 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 08 November 2010 - 06:13 PM

It could also be bouncing. There is some debouncing built into the firmware--but it's limited to a few samples. If you use Debug.Print to print out the time (DateTime) of your event callbacks, are they _really_ close to each other (as in microseconds) or farther apart? If they're really close together, you may be dealing with an exaggerated bouncing issue (to probably be solved in software by doing a time comparison). Chris

#14 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 08 November 2010 - 07:29 PM

If you use Debug.Print to print out the time (DateTime) of your event callbacks, are they _really_ close to each other (as in microseconds) or farther apart? If they're really close together, you may be dealing with an exaggerated bouncing issue (to probably be solved in software by doing a time comparison).

Chris


I've made a test inserting a debug.print as 1st instruction.
I just have pressed 1 time the button, and the lighted led dashed off from 1st to 5th position!!!
That's the debug printing:
9:313
9:423
9:423
9:423

ehm.... seems to be really exxxxaggerated... :blink:

#15 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 08 November 2010 - 09:33 PM

However I added this in each method static void button1_OnInterrupt(uint pid, uint stato, DateTime time) { /* Glitch protection */ if ((time - button1_antiglitch).Milliseconds < 200) return; ... ... /* Glitch protection */ button1_antiglitch = time; } using a static Datetime initialized to DateTime.Now, and seems to be solved. tnx you all guys! B)

#16 AlfredBr

AlfredBr

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationConnecticut, USA

Posted 14 November 2010 - 05:43 AM

You should not compare the '.Milliseconds' property to your constant glitch value of 200. That would compare only the millisecond portion of the TimeSpan that is implicitly created when you calculate 'time - button1_antiglitch'. You will miss button presses, even if those button presses are separated by several seconds. For example: Button press #1: Time = 0.000 seconds Button press #2: Time = 10.123 seconds TimeSpan ts = buttonPress2 - buttonPress1 = 10.123 - 0.000 = 10.123, but the value you will get from '.Milliseconds' is 123 which is less than 200, so I believe you may miss button press #2. Consider using this approach instead: static void button1_OnInterrupt(uint pid, uint stato, DateTime time) { TimeSpan glitchTime = new TimeSpan(0, 0, 0, 0, 200); /* Glitch protection */ if ((time - button1_antiglitch) < glitchTime) return; ... ... /* Glitch protection */ button1_antiglitch = time; } Initialize 'button1_antiglitch' to DateTime.MinValue instead of DateTime.Now and you should be all set. I hope this helps. -AlfredBr

#17 NduVino

NduVino

    New Member

  • Members
  • Pip
  • 8 posts

Posted 14 November 2010 - 10:14 AM

Oh damn! :o It have slipped through!!! Thank you Alfred!

#18 Richard Lafrance

Richard Lafrance

    New Member

  • Members
  • Pip
  • 4 posts

Posted 09 March 2011 - 08:18 PM

I have a 'new guy' question regarding the interrupt handler... I see that the native event handler receives 3 arguments when an interrupt is detected: The hardware port number, the value, and the time. Does this mean that it would be possible for 2 or more buttons to share the same event handler, and to use the first argument as a means to distinguish which button was pressed in code? If so, how would the call to the event handler be setup for the second and any subsequent buttons sharing the handler? Sorry if this is a stupid question, but I was wondering what the purpose of the first argument is. Thanks.

#19 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 09 March 2011 - 08:52 PM

Does this mean that it would be possible for 2 or more buttons to share the same event handler, and to use the first argument as a means to distinguish which button was pressed in code? If so, how would the call to the event handler be setup for the second and any subsequent buttons sharing the handler?

Yes, you can share the same handler...

static class Program
{
  private static InterruptPort button0;
  private static InterruptPort button1;
  private static InterruptPort button2;

  public static void Main()
  {
    button0 = new InterruptPort(Pins.GPIO_PIN_D0, true, ResistorModes.PullUp, InterruptModes.InterruptEdgeLow);
    button0.OnInterrupt += button_OnInterrupt;
    button1 = new InterruptPort(Pins.GPIO_PIN_D1, true, ResistorModes.PullUp, InterruptModes.InterruptEdgeLow);
    button1.OnInterrupt += button_OnInterrupt;
    button2 = new InterruptPort(Pins.GPIO_PIN_D2, true, ResistorModes.PullUp, InterruptModes.InterruptEdgeLow);
    button2.OnInterrupt += button_OnInterrupt;

    // ...

    Thread.Sleep(Timeout.Infinite);
  }

  private static void button_OnInterrupt(uint pin, uint state, DateTime time)
  {
    switch((Cpu.Pin)pin)
    {
      case Pins.GPIO_PIN_D0: // Button0 pressed
        break;
      case Pins.GPIO_PIN_D1: // Button1 pressed
        break;
      case Pins.GPIO_PIN_D2: // Button2 pressed
        break;
      default:
        throw new InvalidOperationException("Unknown button pressed");
    }
  }
}


#20 Richard Lafrance

Richard Lafrance

    New Member

  • Members
  • Pip
  • 4 posts

Posted 09 March 2011 - 10:48 PM

Awesome... Thanks CW2!

Before I got your reply, I tried and failed using this:

    InterruptPort button0 = new InterruptPort(Pins.GPIO_PIN_D2, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
    button0.OnInterrupt += new NativeEventHandler(button_OnInterrupt);
    InterruptPort button1 = new InterruptPort(Pins.GPIO_PIN_D2, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
    button1.OnInterrupt += new NativeEventHandler(button_OnInterrupt);

... which resulted in this message upon execution:

"An unhandled exception of type 'System.Exception' occurred in Microsoft.SPOT.Hardware.dll"


But your method works perfectly. Thanks again!


Rich




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.