Bench note
Pull-up resistors that won't lie to your microcontroller
The problem with trusting internal pull-ups
Most microcontrollers ship with internal pull-up resistors you can enable with a register bit. They're convenient. They're also weak—often 20kΩ to 50kΩ—and that range isn't guaranteed across temperature or supply voltage. For a button debounce circuit on a breadboard, fine. For I²C communication or a GPIO input with any capacitance on the line, you're asking for intermittent reads and bus timeouts you'll blame on everything else first.
External pull-ups give you a known value. You pick the resistance. You control the rise time. You stop second-guessing whether that missed interrupt was code or physics.
Sizing for I²C without the guesswork
I²C needs pull-ups on both SDA and SCL. The bus capacitance and your clock speed determine the minimum resistance; too high and your rise time violates the spec. Too low and you waste current.
Start with the formula: R_min = t_rise / (0.8473 × C_bus) where t_rise is your target (300ns for standard mode, 120ns for fast mode). For a 100pF bus at 400kHz, that's roughly 1.5kΩ minimum. I typically land at 2.2kΩ or 4.7kΩ for short runs. Measure your bus capacitance if you're not sure—a scope and a known capacitor will get you close enough.
If you're chaining multiple I²C devices, remember each one adds capacitance. That 10kΩ pull-up that worked with one sensor will give you sluggish edges with three. When you see interrupt-driven sensor reads start missing beats, check your scope before you rewrite the ISR.
GPIO inputs that don't float
A floating GPIO pin reads whatever noise couples into it—RF, switching supplies, your hand waving near the breadboard. Internal pull-ups usually fix this, but if your input line has a long wire or sits near a motor driver, you want a lower-value external resistor to sink that noise to a rail.
10kΩ is the safe default for most GPIO pull-ups or pull-downs. It's low enough to overcome typical leakage and capacitance, high enough not to source significant current when the input is driven low. If you're reading a mechanical switch, pair it with a 100nF ceramic cap to ground for debouncing—hardware debounce you write once instead of tuning in code every time you change switches.
Placement and power budget
Put your pull-up resistors close to the pins they're pulling. On a PCB, that means within a few millimeters of the IC package. On a breadboard, keep the wire short. A 10cm jumper wire adds inductance that turns your clean logic edge into a ringing mess.
Power budget: a 10kΩ pull-up on a 3.3V rail draws 0.33mA when pulled low. If you have ten inputs, that's 3.3mA you're burning constantly. Not catastrophic, but it adds up in battery-powered projects. If you're optimizing for sleep current, consider 100kΩ pull-ups where the load allows, or disable internal pull-ups entirely and use an external resistor network you can switch off.
When to use a resistor array
For multiple lines on the same bus—like an 8-bit parallel interface or a cluster of GPIO inputs—use a resistor array instead of eight individual resistors. Bourns 4600X series or similar. Same footprint as a DIP IC, all resistors matched to ±2%, and your board layout stays sane. You'll also reduce your BOM line items, which matters when you're ordering parts for more than one build.
Log what you picked and why
Document your resistor values in your schematic notes or project README. Not just "4.7kΩ pull-up" but "4.7kΩ pull-up, sized for 150pF bus capacitance at 400kHz I²C, measured 280ns rise time." Future you—or anyone else reading your design—will know it was intentional, not a random jellybean part you grabbed from the drawer.
Pull-up resistors are not exciting. They're also not optional if you want reliable digital communication. Pick a value, place it close, and move on to the parts of your project that actually require thought.