Electronics > Beginners
How to initialise INPUT_PULLUP before Interrupt runs in Arduino?
<< < (3/4) > >>
skillz21:

--- Quote from: mjkuwp on March 23, 2019, 12:26:34 am ---interrupts can be pretty sensitive and sometimes they cause too much trouble when they are used for a feature that doesn't really call for them.  That said  -  I wrote something you could try.  There is a bit of a delay added before the interrupts are enabled.

if I were doing this I would likely do this by polling, not an interrupt and there would be a state machine to help with de-bouncing.


--- Code: ---volatile int buttonPin = 21;         
volatile bool gotPressed= false;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(buttonPin, HIGH );
  noInterrupts();
  attachInterrupt(digitalPinToInterrupt(buttonPin), Button, FALLING);
  delay(1);
  interrupts();
}

void loop() {
if(gotPressed)
  {
      //Does stuff
    gotPressed = false;
  }
}

void Button() { 
 
    gotPressed = true;
 
}

--- End code ---

--- End quote ---

I tried it, but it didn't do anything. How would you do it by polling? I the code is running a delay for example, and I pressed the button, it wouldn't register the click right?
mjkuwp:
"didn't do anything"

well, to be fair the code doesn't do anything : )  it is empty code. 

you are correct in that a button press that occurs in hardware while the code is in delay will not get noticed in a polling situation.  A couple of ways to address that.

1. don't use delay
2. write a state machine that looks for the button to be pressed, starts a timer and checks that it is still pressed X number of milliseconds later while never having been un-pressed during that time.


or, better yet look at this:

https://www.arduino.cc/en/tutorial/debounce

Ian.M:
The weak internal pullup needs time to charge the stray capacitance of the pin & button wiring to reach a valid logic '1' level.  Therefore a delay between pinMode(buttonPin, INPUT_PULLUP); and attachInterrupt(digitalPinToInterrupt(buttonPin), Button, FALLING); is essential if you want to avoid a spurious interrupt. 

1 ms is excessive - somewhere between 10 and 100 us should be sufficient.  If you've got a  scope, write a test program that outputs '0' on the pin then switches to INPUT_PULLUP mode, in a loop with a 1ms delay.  With the switch wiring connected, probe the pin and measure  the risetime (to 90%) and triple that time to get a reasonable delay to use in your actual code.

Also, its a good idea to clear any pending pin change interrupts after you've set up the interrupt on the pin, before enabling interrupts.  Reading the pins followed by PCIFR=7; should do that (assuming an  ATmega328P based Arduino, see datasheet section 17.2.5. Pin Change Interrupt Flag Register).

There's a tutorial on AVR pin change interrupts at http://microchipdeveloper.com/8avr:pin-change-interrupts
The Arduino libraries hide some of the complexity but the hardware and registers are the same.

N.B.  Pin interrupts are a *HORRIBLE* way of handling user buttons, and you risk an interrupt storm if the buttons don't have 100% effective hardware debouncing.    Jack Ganssle's article on debouncing is worth a read :  http://www.ganssle.com/debouncing.htm
skillz21:

--- Quote from: Ian.M on March 23, 2019, 03:27:22 am ---The weak internal pullup needs time to charge the stray capacitance of the pin & button wiring to reach a valid logic '1' level.  Therefore a delay between pinMode(buttonPin, INPUT_PULLUP); and attachInterrupt(digitalPinToInterrupt(buttonPin), Button, FALLING); is essential if you want to avoid a spurious interrupt. 

1 ms is excessive - somewhere between 10 and 100 us should be sufficient.  If you've got a  scope, write a test program that outputs '0' on the pin then switches to INPUT_PULLUP mode, in a loop with a 1ms delay.  With the switch wiring connected, probe the pin and measure  the risetime (to 90%) and triple that time to get a reasonable delay to use in your actual code.

Also, its a good idea to clear any pending pin change interrupts after you've set up the interrupt on the pin, before enabling interrupts.  Reading the pins followed by PCIFR=7; should do that (assuming an  ATmega328P based Arduino, see datasheet section 17.2.5. Pin Change Interrupt Flag Register).

There's a tutorial on AVR pin change interrupts at http://microchipdeveloper.com/8avr:pin-change-interrupts
The Arduino libraries hide some of the complexity but the hardware and registers are the same.

N.B.  Interrupts are a *HORRIBLE* way of handling user buttons, and you risk an interrupt storm if the buttons don't have 100% effective hardware debouncing.    Jack Ganssle's article on debouncing is worth a read :  http://www.ganssle.com/debouncing.htm

--- End quote ---

Instead of using an interrupt, is there any other way for the Arduino to recognise a button press and change a variable? It wouldn't actually do this if there is another piece of code running, right?
Ian.M:
Instead of making the button trigger an interrupt, poll the button from a timer ISR (which avoids any risk of an interrupt storm), and implement one of the software debouncing algorithms from part 2 of J. Ganssle's article.

N.B. The Timer 0 overflow interrupt is used for various Arduino sytem functions involving timekeeing, and (unless thing have changed since I last looked at the Arduino libraries), its very difficult to patch in your own code in that ISR.   If you want to run your button code on a Timer 1 interrupt (approx. every milisecond), you'll need to use the timer's Compare A interrupt.   Set OCR0A to 0 and enable OCIE0A to interrupt immediately after the system overflow routine.
Navigation
Message Index
Next page
Previous page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod