Pin State Changes

What command would I use when I want something to happen when a pin changes from HIGH to LOW?

What I am using now is if (pin = LOW) do this...

However it will continuously do it until the pin is HIGH again. I would like to use something that only performs the actions when the pin changes state and then does not do it again.

Basically I'm using a pushbutton that when pushed down it will send a keyboard function to the computer. Although the button either stays up or stays down. When it is down I don't want it continuously sending the same keyboard function, I only want it to send it one time.

You need to save the state of the pins the last time you checked:

if pin is high and last time pin was low
do stuff

How exactly do you wright the "last time low" part in code?

Actually, what you need is an interrupt.
http://arduino.cc/en/Reference/AttachInterrupt

schoolsterz123:
How exactly do you right the "last time low" part in code?

You don't have to use interrupts (you can if you want an extra challenge). :slight_smile:

myPin = digitalRead (SWITCH_PIN);
if (myPin == LOW && oldPin == HIGH)
  {

  // pin has changed, do something

  delay (10);  // debounce might be useful
  }
oldPin = myPin;  // remember for next time

Okay that makes sense. Now what would I use for like a switch that could either switch the pin to HIGH or LOW depending on if it's open or closed?

I would like it to send a keyboard function to the computer when the pin the switch is on changes from high to low and from low to high but only when it changes. Is there a function that would work easily for that?

A variation that should detect both changes of state

nowState = digitalRead(SOME_PIN);

if (lastState != nowState) {
	delay (10);				// debounce
	if (lastState != nowState) {		// test again
		Serial.print ("State changed: ");
		Serial.println (nowState, DEC);
		lastState = nowState;
	}
}

Rob

When you are defining the variables for nowState and lastState at the top do you just write:

int nowState
or do you have to set it equal to something? If you do set it equal to something, what would you set it equal too?
When I try it, it says "nowState not declared in this scope".

schoolsterz123:
When you are defining the variables for nowState and lastState at the top do you just write:

int nowState
or do you have to set it equal to something? If you do set it equal to something, what would you set it equal too?
When I try it, it says "nowState not declared in this scope".

You don't have to, but as good form, I would set it to whatever the state would most likely be when the sketch first starts.

Also, you need a semicolon at the end of it.

Add

int nowState = 0;
int lastState = 0;

at the top of the program, not inside the loop() or setup() functions.

If there are still problems post your entire code.


Rob

Got that to work perfectly!

As far as interrupts go is that like changing to an entirely different loop when it's triggered?
I was reading the interrupt tutorial that someone posted on here earlier but its kind of confusing to me. Are you only able to use pins 0 and 1 with the interrupt command?

Basically, instead of having to constantly watch for it, the interrupt will let you do other things with your code, then the instant the interrupt is triggered it'll execute one function, then return to your normal loop(). like this:

void setup()
{
  attachInterrupt(0, interruptFunction, FALLING);
}

void loop()
{
  //all sorts of other stuff
}

void interruptFunction()
{
  Serial.println(F("Pin 0 just went from HIGH to LOW"));
}

This will tell you when pin 0 gets pulled low, without having to do something like

int newval;
int oldval;

void loop()
{
  oldval = newval;
  newval = digitalRead(0);
  if(newval == 0 && oldval == 1)
  {
    Serial.println(F("Pin 0 just went from HIGH to LOW"));
  }
  //lots of other stuff
}

Which can easily miss very quick pulses, if they happen while the program is doing other stuff.

And yes, on the uno you can only use interrupts on pins 0 and 1. If you have a mega or mega2560 you can use interrupts on several other pins as well.

Okay got it. If in my code i have several pushbuttons and lights blinking normally with different functions and then I want them to stop what they are doing when a certain button is pressed,then it looks like the interrupt isn't what I need.

I am making a control panel and when in normal operation you are able to do everything like normal. When the emergency stop pushbutton is pressed, I would like all of the blinking and functions of the other buttons to stop until the emergency stop pushbutton is reset with a reset pushbutton.

I was originally thinking that when the Emergency Stop pushbutton is pressed I could have it go to an interrupt but it doesn't seem like that stops the other sections of the code from being carried out. I hope all of this makes sense! Thanks again everyone.

I don't believe you understand the exact usage of interrupts; they're exactly what you need there. Interrupts stop normal execution only so long as the function is active, which is likely only a few microseconds.

You need a state variable. When the emergency button is pushed, the state is changed. The normal code will only run if the state variable is a certain value.

Can there be more than one function in the interrupt? Like let's say when it goes to the interrupt can I have it blink the led in the pushbutton, send a keyboard command, and stay there until I end the interrupt by pushing a reset pushbutton?

It just sounds to me that it jumps down to the interrupt function then goes back to the regular loop until its triggered again. I would need it to stay in the interrupt loop.

Arrch:
You need a state variable. When the emergency button is pushed, the state is changed. The normal code will only run if the state variable is a certain value.

Could I do that with one large if else statement?

schoolsterz123:
Can there be more than one function in the interrupt?

No, you want to keep code in interrupt handles as minimal as possible.

schoolsterz123:
Could I do that with one large if else statement?

Yes.

xolroc:
Basically, instead of having to constantly watch for it, the interrupt will let you do other things with your code, then the instant the interrupt is triggered it'll execute one function, then return to your normal loop(). like this:

void interruptFunction()

{
 Serial.println(F("Pin 0 just went from HIGH to LOW"));
}

I know this is just an example, but an interrupt should not do Serial prints. They themselves use interrupts. This particular code could hang.

xolroc:

  attachInterrupt(0, interruptFunction, FALLING);

And yes, on the uno you can only use interrupts on pins 0 and 1. If you have a mega or mega2560 you can use interrupts on several other pins as well.

The attachInterrupt for 0 is really pin D2, and interrupt 1 is D3 (not pins 0 and 1).

Interrupts in general should do something short (like save some data in an array) or set a flag. So really you want:

void interruptFunction()
{
 buttonPressed = true;
}

void loop ()
  {
  if (buttonPressed)
    {
    // do something here if button pressed
    }

...
  }

So you aren't much better off than detecting the button press in loop. You are a bit better off, but not enormously better off.

Like let's say when it goes to the interrupt can I have it blink the led in the pushbutton, send a keyboard command, and stay there until I end the interrupt by pushing a reset pushbutton?

No. Interrupts should be short. You can't use them to jump to other parts of your sketch, and you certainly should not stay inside one waiting for a button press.