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.
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
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.
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.
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?
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.]
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.
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 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...
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
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
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!
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
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.
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");
}
}
}