When hooking up switches or buttons to an Arduino I/O pin, sometimes the results might appear completely random. Sometimes it will appear as though there is a delay from when the button is pressed until the state of the pin actually changes. Other times the pin’s value will seem to randomly fluctuate from HIGH to LOW. Even more maddening might be as your finger gets closer to the switch, the pin’s state changes! The fix to these problems is simple: use the Arduino Internal Pull-up Resistor. Here’s how they can fix this problem and how you can use them with an Arduino board.

Alternate Arduino Internal Pull-Up Resistor Tutorial

AddOhms #15 Video Tutorial covers Pull-Up Resistors, including the Arduino Internal Pull-Up resistor. In the video, I am using a TI LaunchPad with Energia, but the same concept applies to Arduino.

Why doesn’t my button work!?

Consider the following circuit, which is a simple normally-open push-button on a breadboard. It has been wired so that one side is tied to +5V and the other side is connected to Pin 12 of an Arduino Uno. (Make you check with a multimeter to determine which pins are connected together and which are not.)
Floating Push Button Example
Picture 1: Floating Pushbutton on Breadboard
The code for this switch is very simple. The LED on Pin 13 should light up when Pin 12 is HIGH and be off when Pin 12 is LOW. The expected behavior is that the LED will be OFF whenever the button is not pushed and ON when the button is pushed.

void setup() {
  pinMode(13, OUTPUT); // Use Built-In LED for Indication
  pinMode(12, INPUT);   // Push-Button On Bread Board
}

void loop() {
  bool buttonState = digitalRead(12);  // store current state of pin 12
  digitalWrite(13, buttonState);
}
Take a look at this video to see what happens as the button is pushed. The LED’s behavior is not at all predictable! Sometimes it lights up, sometimes it stays on, sometimes it changes just when a finger gets close to it!
The pin is “Floating.” This schematic shows how the button is wired on the breadboard. What is PIN 12 connected to, when the button is unpressed? Nothing!
Floating Pin Schematic Version
Schematic 1: Schematic of Floating Pin
This means that any signals in the air, such as from nearby electronics, can cause the pin to “float” to either a HIGH or LOW. For example, this waveform from an oscilloscope shows what the pin is doing when nothing is connected.
Floating Pin Oscilloscope Screenshot
Picture 2: Oscilloscope Screenshot of Floating Pin
This video is the same breadboard circuit but with the oscilloscope waveform visible. As a human finger comes close to the pin, the waveform changes. 60Hz noise from the environment is being coupled into the circuit through the finger, which is what causes the “random” behavior of the input pin.
Great! Now that we understand why the pin randomly changes, how does it get fixed? Easy! Just make your Arduino do exercises… pull-ups in fact!

Using Pull-Ups to fix Floating

The fix for floating pins is to “pull them up” to a known value when the switch is unpressed. This is done with a Pull-Up resistor, as illustrated in the following schematic:
Pull-Up Resistor of an I/O Pin
Schematic 2: Pull-Up Resistor of an I/O Pin
Now when nothing is connected, current cannot flow through the resistor. So the Voltage on both legs will be the same. This means the same point where the resistor connects to the switch and Pin 12 will be forced to sit at 5V. When the button is pressed, that same point will drop to 0V as current starts flowing through the resistor (ohm’s law). Since the resistor is there, you don’t have to worry about a short circuit. In this case, 10Kohms was picked as a relatively large value. The exact value of the resistor does not matter. You want something big enough to limit the amount of current wasted when the button is pressed, but not so big (like 10Mohm that you start having noise problems again.) A really cool feature of the ATmega chips used by the Arduino platform is that they have these resistors already built into them! All that needs to be done is turn the Arduino Internal Pull-Up resistor on and you get the previous schematic, for free! Here is the new breadboard circuit. Notice that the red jumper wire has changed to yellow. Also, it is no longer connected to 5V but now is connected to GND. That’s the [i]only[/i] difference in the hardware.
Button Wired with Arduino Internal Pull-Up Resistor
Picture 3: Button Wired with Internal Pull-Up (Blue wire connects to Pin 12 of the Arduino)
It only takes a small change in the code to turn on these incredibly useful internal pull-up resistors. When a Pin has been configured for INPUT with pinMode(), simply use digitalWrite() to write a HIGH to that pin. Here is the same code with a single change:

void setup() {
  pinMode(13, OUTPUT);    // Use Built-In LED for Indication
  /* INPUT_PULLUP enables the Arduino Internal Pull-Up Resistor */
  pinMode(12, INPUT_PULLUP);      // Push-Button On Bread Board
}

void loop() {
  bool buttonState = digitalRead(12);  // store current state of pin 12
  digitalWrite(13, buttonState);
}
The combined video of the button working by using the internal pull-up and along with the waveforms on the oscilloscope is shown here.

Conclusion

When using any kind of “open” inputs with an Arduino such as switches, push buttons, reed relays, and some sensors a pull-up resistor is needed for reliable operation. These resistors hold the I/O pin at a known value until the switch forces the I/O pin to a different known value. On each board there are Arduino Internal Pull-Up resistors built-in, they just need to be turned on in the sketch, usually in setup().  
Author

Fan of making things beep, blink and fly. Created AddOhms. Stream on Twitch. Video Host on element14 Presents and writing for Hackster.IO. Call sign KN6FGY.

24 Comments

  1. Eden Ben Meshi Reply

    Hi,
    In case of Arduino Due the internal pull-up resistors goes to 5v?
    I wondering because Arduino Due’s I/O operating on 3.3v
    Thanks

  2. 1-How can I write programs by using a pulled up input in

    arduino, 2-And what’s difference between pulled up and pulled down input pins?

    • 1-How can I write programs by using a pulled up input in arduino

      INPUT_PULLUP enables a pin’s built-in pull-up resistor.

      2-And what’s difference between pulled up and pulled down input pins?

      Pull-up defaults to a HIGH. It’s value is LOW when active.
      Pull-down defaults to a LOW. It’s value is HIGH when active.

  3. I finally found this article of yours again. A bit over week ago I found this article by accident. A good accident for sure.

    I built a tipping bucket rain guage (TBRG). A project from the rain guage point of view a bit more involved than I thought. I wanted the 0.1mm resolution most commerical designs have (for countries that measure in metric). As I have often said DIY projects are usually more involved than what one expects. The software code via an Arduino Nano was simple to start and ready months prior to enable certain design elements I needed to test and work out for the DIY TBRG.

    I started the DIY TBRG build in early Spring this year after a few years to find the parts/materials I needed. The DIY TBRG was finally ready the mid August. The TBRG was installed about 10 inches above grade resulting in the top of the TBRG being about 14 inches above grade.

    The reason this article was important was I had not considered using a bypass capacitor despite the long cable typically needed to connect a TBRG to the electronics located inside. Few switch reference examples of many I have found used a bypass capacitor, so I did not include a bypass capicator. The same very few articles that included a bypass capacitor tended to also include a electrolytic capacitor I believe to smooth out any VCC glitches due to the power source being used to the Arduino. I did not include such an electrolytic capacitor for this project, but have provided in other projects with no bypass capacitor with no spurious issues.

    This article makes reference to long cables as one aspect of the noise and spikes that occur that cause spurious (interrupts). The cable to connect a TBRG are infinitely long by Arduino standards. Infinitely long meaning about 100 feet long in my case and usually at least 30 feet in many cases. The cable is twised pair on purpose to eliminate induction of RFI/EMI. It is not shielded sadly as just far too expensive. Still with no bypass capacitor and just a 10K external pull up resistor between VCC and the Arduino interupt pin all worked fine once the TBRG was install outside as had inside testing the tipper assembly.

    About 2 weeks later I started to have a single tip register via the Arduino. The varied timing and weather in the morning was such that I concluded the water sensitivity I had acheived was such that heavy dew was being sensed. I had already discoved the sensitivity (not resolution) one night in first two weeks when steady very light rain for over 5 hours was still being registered by my DIY TBRG at the rate of 0.1mm +- every hour. Amazing for sure for a DIY TBRG. I suspect few commerical designs are as sensitive. There were no bugs about nor inside the TBRG (easy to take apart and check). One design element was to make sure no bugs, no matter how small entered the DIY TBRG as bugs can cause just too many problems with a TBRG. Some commerical TBRG designs I believe enable small bugs to enter and grow larger inside the TBRG leading to spurious tips or inability to tip.

    A week ago Monday I discovered several tips registered with three tips in less than one second. Ummm not good, not possible and no rain. Open and check the TBRG with no bugs as expected. I was now starting to think the couple times a single tip was registered in the morning of heavy dew was not the same as the sensitivity to detect rainfall rate of 0.1mm +- hour. What was throwing me off was almost 2 weeks of perfect clean DIY TBRG operations no spurious tips and yet excellent sensitivity.

    The first question in such a problem is was what changed? I had not changed the pull up, nor cable length since I started the week prior to installing the TBRG. For a bit over a week I ran a number of calibration tests inside to calibrate the set screws of the DIY TBRG to set resolution at 0.1mm per tip. A task that is not nearly as easly as I thought initially how to effect the calibration tests. The set screws and rational for using set screws was sound. Just the DIY how to calibrate was not so straignt forward. I also wanted to do a “burn in” for a few days of constant simulated rainfall in case I missed something in the DIY design. These “burn in” tests did reveal some minor, but important design issues that were simple to test alternative solutions for and implement. That means I had been using the 100 foot cable connected to the breadboard with the three screw terminal block and external 10K pull up resistor for over 3 weeks with no spurious tips being registered. What had changed was again the question?

    I did alot of searching on internet for Arduino interrupts. Some how in the course of the searching for few hours this article link appeared and I read it. Clearly I was using a really, really, really, did I say really, long cable for what is basically a switch application that most use cables that are in order of inches and not many feet.

    I should note that unlike most TBRG that use a Reed Switch I use a Hall Effect Transistor. I was not able to find a right combination of Reed Switch/magnet as much as I tried in the year prior to starting the build this Spring. I was able to find a magnet size I could use with unipolar Hall Effect Transistor. I am assuming no matter if I used a Reed Switch, Hall Effect Transistor, or Photo Interruptor the same end result of spurious tips registered would have occurred.

    The only change I could arrive at was an external change. In this case the external change was humans that had cell phones, microwaves, and various other RFI/EMF emitting devices that were inducting into the 100 foot twisted pair cable from the TBRG to the indoor simple pull up resistor and Arduino inside. In essence even though the cable is twisted pairs it is acting like a large large dipole antenna. The simple electronics indoors is on a 160 pin breadboard with 10cm jumper cables from the breadboard to the Arduino Nano. I placed a 100nF ceramic bypass capacitor between VCC and the outout of the Hall Effect/Arduino Interrupt pin at the three screw terminal block that had the external pull up 10K resisitor for months prior between VCC and Hall Effect Transistor out/Arduino Interrupt pin.

    Initial tests were done to ensure the TBRG tips were still detected with the use of a bypass 100nF capacitor added and the existing 10K external pull up resistor. Tips were detected by the Arduino.

    Since a week ago Monday there have been no spurious interrupts from the TBRG. There has been one rainfall of about 24 hours, steady, no downpours, that the DIY TBRG has recorded and no spurious tips. I do have an old CRT scope, but felt there was no point to scope as one have to be scoping at time of the spurious tip that could be days/weeks as base reference and then compare to after where the expection is no spurious tip that would require hours/days or much longer in attempt to validate.

    What remains in question is should I bypass with the 100nF VCC to GND or VCC to output? I ask as when I specifically looked up examples there were those that bypassed VCC to GND and those that bypassed VCC to GND and GND to output. The latter in sense similar to what I did a week ago Monday that seems to be working in terms of no spurious interrupts on Arduino pin while the tips detected by the Hall Effect Transistor are doing just fine and as desired.

  4. Artur Babecki Reply

    One important remark about that schematic without the resistor: NEVER connect the voltage directly to the input without any resistor . It is just a short circuit. The input of the Arduino UNO shall not exceed 20mA so the resistor is needed at least to limit the input current. Arduino is merciful but some MCU modules definitely are not.. Using the pull-up resistor with the switch connected to the GND is OK. However using the internal pull-ups switched on by the programm needs some attention when accidentaly there is also the external pull-up resistor.It can cause problems – maybe not so dangerous but with proper communication with sensors and EEPROMs.

    • NEVER connect the voltage directly to the input without any resistor . It is just a short circuit.

      While I agree a current limiting resistor is helpful, it isn’t necessary. You are NOT creating a short circuit. When configured as an INPUT, pins are high impedance and have a significant amount of their own internal resistance.

      The input of the Arduino UNO shall not exceed 20mA

      Again, because of the impedance of the transistor’s gate, you aren’t ever going to force 20mA into a pin configured as an input. Unless you apply a ridiculous high voltage. The 20mA is a guideline for when pins are configured as OUTPUT.

  5. That resistor is usefull for a sensor input? i mean, talking about a sharp optical sensor “analog singnal”

    • I don’t see how you would use it for an analog sensor. The only option might be if you are building a voltage divider. However, the value of the internal resistor is not guaranteed. It is anything between 30k and 50k ohms. It would be better to use an external divider.

      The only sensor I can see using an internal pull-up is with one that has a digital pin using an “open collector” configuration. (Where something else must pull-up the output signal.)

  6. Really awesome tutorial! I love the simplicity of it. Thanks…looking forward to more videos.

  7. So when the pull-up resistor is enabled, a resistance of about 20K ohms comes into place between the 5V and the pin 12 configured for input. This is in addition to the 100 M Ohm or so resistance that gets enabled when the pin is made an input in the first place, I guess? It is this 100 M Ohm resistance that limits the current through the input pin and makes it read high( nearly 5 volts) when it is pulled up, hmm? Just clarifying.

    • when the pull-up resistor is enabled, a resistance of about 20K ohms comes into place between the 5V and the pin 12 configured for input.

      Yes. (it’s between 30k and 50k, not well controlled.)

      This is in addition to the 100 M Ohm or so resistance that gets enabled when the pin is made an input

      There isn’t “additional” resistance enabled. That’s the effective resistance of the transistor.

      It is this 100 M Ohm resistance that limits the current through the input pin and makes it read high( nearly 5 volts) when it is pulled up

      It’s the transistor that is present that reads the high or low. Because so low current flows into the transistor, because of it high impedance, that is why the pin floats.

      The Pull-Up resistor gives the current an easy path to flow.

      This is a more updated pull-up tutorial: http://www.addohms.com/ep15

      • Thank you. On one of the tutorial pages on the Arduino website there was this mention of the large resistance/impedance that an input pin has. I was not clear about how that impedance comes about. You have made it clear.

  8. I had a similar issue that needed a pull-up resistor. Learned the hard way. The system now works great, but one problem. After about one to two hours the pin suddenly drops to low, triggering the event programmed into the arduino. I have not been able to identify the issue. The line for the switch is 30 ft long. Do you think this long of a line could be a reason for this unexpected tripping?

    • It happened to me too. I just enabled the internal pull up. but pin goes low and triggering the event. I am thinking of adding an external pull up which may be reliable. no idea.

  9. Great video, very understandable. The oscilloscope(?) was a helpful addition to see what was going on.

    One question though: is pinMode(2, HIGH) and pinMode(2, INPUT_PULLUP) the same thing? I was a little confused reading through the arduino.cc stuff as they kept saying to use a pull up resister but the code only showed pinMode(…, HIGH)

    Thanks,
    Derek

    • Hi Derek, yes they are the same. INPUT_PULLUP was introduced in 1.0.3, which was long after I made the videos. One correction, you use digitialWrite() to send the HIGH, not pinMode(). Many tutorials (even on arduino.cc’s site) will mention the digitalWrite() method.

  10. James Blake Reply

    Thanks very much for your help, and for clearing up the confusion about pin13.

    The Leonardo arrived yesterday. I love it!

  11. James Blake Reply

    Very useful info, thanks.

    One quick question, if you don’t mind – I’m going to use the Leonardo for a project of mine. Using the internal pullup resistors as you described above, how many buttons could I attach, and which pins can I attach them to? I want to avoid frying the board, if I can! 🙂

    I presume each of the buttons would be connected between the pin and 5v, although I understand that pin 13 would need an extra resistor as it’s also connected to the LED.

    Thanks for any advice,

    (another) James

    • You can use any of the digital or analog pins for a button. Just remember if you are using an analog pin, to refer to it as A0 or A1 in your code. As far as connections go, you want one side of the button to your pin and the other to ground. You DO NOT need to do anything special for Pin 13. The board is decided to reduce the impedance effects of having the LED there.

  12. The polarity of the pin is VCC with this ?
    What is the default polarity in the Input pin mode ?
    Nice tuto, thx

    • Polarity isn’t the right word. 5V and 0V are not polarities, they are voltages. The value of a pin is whatever voltage is applied to it. The default for the pin is to be floating. That’s the whole point of using the pull-up resistor, to force it to a known voltage / state.

    • Yes. INPUT_PULLUP was added in the 1.x branch, after I made these videos. Probably won’t go back to fix them. I’ve converted over to just using INPUT_PULLUP. Less typing. 😉

Write A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.