Go Down

Topic: Newbie Question re Interrupts (Read 955 times) previous topic - next topic

dmielken

So I'm brand new to the world of programming and have a small project where I'm reading the value of a push button, printing the result on the Serial Monitor, and turning on an LED.  Within the program I also want to debounce the signal and have an interrupt that prevents the program from continuously checking the input pin.  I've tried to do some searching/Googling/Youtubing but just can't seem to find an explanation that fullfills my understanding.  My code is below and what I'm asking is what should I place in the function I'm calling (tagt) to make it so that my program only checks the pin when the button is depressed, preventing my Serial monitor from ALWAYS polling that pin?

Code: [Select]
/**********************************************************/
/* READ A PUSH BUTTON, PRINT TO SM, DEBOUNCE, INTERRUPT   */
/**********************************************************/

/***********************************/
/*        DECLARE VARIABLES        */
/***********************************/

int push_pin = 2;  // Push button on digital pin 2
int led = 8;       // LED on digital pin 8
int val;          // value to store the state of the push button
int val2;         // value to store the state of the push button to cross reference for the debounce
int button_state;  // variable need for the debouncing

/********************************************/
/* BEGIN SERIAL COMS, SET PINMODES, ADD VARS*/
/********************************************/

void setup()
{
  Serial.begin(9600); //setup Serial coms @ 9600 baud
  while (! Serial);  // Needed for Leonardo
  pinMode(push_pin, INPUT);  //set the push pin as an input
  pinMode(led, OUTPUT);    //set the LED as an output
  button_state = digitalRead(push_pin);    //store the push pin state in the button_state variable
  attachInterrupt(1, tagt, RISING);
}

/***************************************/
/* SETUP LOOP, SM PRINTING, DEBOUNCING */
/***************************************/

void loop()
{
  Serial.print("The push pin is depressed:");
  Serial.println(digitalRead(push_pin));    //print the state of the push button as either 1 or 0
  val = digitalRead(push_pin);    //store the state of the push button in the val variable
  delay(10);    //add a short delay for stability
  val2 = digitalRead(push_pin);   
  if (val == val2)                 /************************************/
    {                              /* THIS SEGMENT USED FOR DEBOUNCING */
     if (val != button_state)      /************************************/
      {
         Serial.println(button_state);
         button_state = val;
      }     
    } 
 
  if (val == HIGH)               
    {                             
     digitalWrite(led, HIGH);     
    }                             
                                                               
  if (val == LOW)                         
    {                             
     digitalWrite(led, LOW);     
    }                             
  button_state = val;             
}
 
/***************************/
/*   INSERT INTERRUPT FN   */
/***************************/
 
void tagt()
  {
     
  } 
 

cjdelphi

Well, apart from a small delay to "de-bounce" it...

you say "depress" well you set an interrupt for a "rising edge"  meaning, it will send an interrupt to Arduino WHEN it detects a voltage going from 0v to 5v (eg a press) but this is literally the PRESS of a button, not the DEPRESS of a button, you'd need to set a "Falling Edge" for it to detect the end signal of a key press.

UKHeliBob

I don't see that you need an interrupt.  You get the message "The push pin is depressed:" every time the loop executes, whether or not the button is depressed which will be very fast indeed.   You need to check the value returned by digitalRead(push_pin); and only print the message when it is true.

One way or the other the program is going to need to check whether the button is depressed.
Oh, and you are trying to use interrupt 0 but your button is on pin 2.  Is that right ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Nick Gammon

On the Uno pin 2 is interrupt 0, so that part is OK.

@OP: Your sketch has some issues, try reading this:

http://gammon.com.au/interrupts

Your interrupt routine should set a flag, and that flag should be declared volatile.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

UKHeliBob

Whoops, sorry.

I really must learn to read.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

PaulS

Does it really matter whether your code is always checking the state of the pin, or if you pass that responsibility off to another function?

I don't see any reason for you to be using interrupts. It's not like Arduino will be doing anything else, anyway.

By the way, some of your comments (and serial print text) is plain wrong. The first print statement will execute every time, regardless of whether the switch is pressed, or not.

The comments about debouncing refer to the wrong code. That code detects a state change (from released to pressed or from pressed to released). It has nothing to do with debouncing.

dmielken

Thank you for inputs and criticisms!  I'm really just attempting to get to grips with some of the concepts in the programming library.  For future projects, the interrupt feature will be important for the scope of work so I wanted to try it and see what could come of it. 

Much appreciated thank you!  I will do some more research on some of the suggestions people have made, thank you for the link!

majenko

How I would do it, if you really really want to use interrupts:

(untested:)
Code: [Select]

volatile unsigned char pressed = 0;

void setup()
{
  pinMode(2,INPUT);
  Serial.begin(9600);
  attachInterrupt(0, bpress, RISING);
}

void loop()
{
  if (pressed == 1) {
    Serial.println("Pressed");
    pressed = 0;
  }
}

void bpress()
{
  pressed = 1;
}


The theory:

In the loop:
If the variable "pressed" is 1, then print out that the button is pressed, then set the variable "pressed" to 0.

In the interrupt:
Set the variable "pressed" to 1.

You press the button, which sets the pressed flag.  The main loop notices that the pressed flag is set, and tells you, resetting the pressed flag so it only tells you once.  Next time you press the button the pressed flag gets set to 1 again, and the main loop tells you, etc.

The main thing to notice here is that the "pressed" variable is set as "volatile".  This tells the compiler it shouldn't trust what it thinks the variable might contain and optimize it away, and instead force it to get the value from memory every time it is referenced.  This is needed for interrupts, as the compiler cannot know for sure when the variable will have been changed, so its optimizations will be wrong.

Also, the variable is an "unsigned char", aka "byte".  This is a single byte of memory, and most simple operations, like assignments etc, are fairly atomic, and the interrupt shouldn't cause any problems interrupting accesses to that variable.  If it were an int, then it would take multiple assembly instructions to access or modify the variable, and there is a chance the interrupt could be fired in the middle of accessing the variable, with the possibility of the variable ending up corrupted.  Not really an issue for this example, but something to keep at the back of your mind.

Go Up