| 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 |