I've noticed a lot of things work without pull-up/down resistors, tx, rx, miso, mosi, etc. They all seem to work without them. From what I understand, these resistors are necessary for draining any charge to prevent the gate of a mosfet or open switch from floating. I'm pretty sure mosfets are involved in all these things, so why do they work without them? How do I know when to use a resistor and when it's not necessary?
Half those signals are outputs so they don’t need anything.
Inputs normally do but they are often actively driven by another device on the board. If that’s not the case at any time then a PU/PD resistor is normally used to stop the input floating.
Floating inputs may cause program issues (for example if there’s an interrupt on the pin) but also I think it’s possible for some of the input circuitry to enter its linear mode and that’s bad as a lot of current can flow.
For driving a N MOSFET: The problem comes when a floating pin drives the transistor. An output pin on the Arduino is either HIGH or LOW. However, at restart (power up also) this pin is in an input mode until your pinMode line is run. During this time the MOSFET may turn on or go into a linear region, which is not advisable.
You need pullups or pulldowns when a pin could otherwise be "floating" where that would be problematic and on open drain / open collector busses like I2C. Since all pins on most microcontrollers are inputs on startup/reset, you need to consider what happens to your project if all pins are acting like inputs (ie, high impedance, so a pin not otherwise pulled up or down will float)
SPI is not open drain - the pins are actively driven high and low when SPI is in use, so it's not floating, and you probably don't care that it's all floating on startup - though there are probably cases out there where it is. One could definitely argue in favor of pullups on the (active low) CS lines for SPI devices....
Serial lines are driven high by the TX side. So pullups are not needed unless the RX line may be connected to nothing - and even then, I've never had to use the pullup - never saw bad behavior here. They may turn on the internal pullups or something. Not sure.
I2C is an open collector/open drain bus - the devices can only drive the pins low - thus you need pullups, otherwise the lines will never go high and I2C won't work.
When driving external MOSFETs, you typically need a pulldown (for N-channel fets) or pullup (for P-channel fets) - these devices have no internal pullup or pulldown, and if the gate voltage floats away from the source voltage, the fets will turn themselves on, which is almost always undesirable.
When using a switch or button as an input - when the switch is not connected, one side will float if there isn't a pullup or pulldown on it. Typically, switches connect to ground when closed, and you use the internal pullup.
As you can see from my above description, whether you need them really depends on the situation. Pullups and pulldowns are not something you can do by rote (like, say, decoupling caps) - you need to assess the circuit and read the relevant datasheets and determine if they are needed for a given situation.
Normally i use Pull down/up resistors when I want to take any action based on an input. For e.g. take action from a push button connected to an pin (input mode).
If I dont connect the resistors then the pin will be in floating state and I get unwanted results, have a look at this post http://forum.arduino.cc/index.php?topic=403331.0
Graynomad: Inputs normally do but they are often actively driven by another device on the board. If that's not the case at any time then a PU/PD resistor is normally used to stop the input floating.
Floating inputs may cause program issues (for example if there's an interrupt on the pin) but also I think it's possible for some of the input circuitry to enter its linear mode and that's bad as a lot of current can flow.
It turns out these statements are somewhat nonsensical, as many if not most sketches only configure a limited number of pins - those which are actually connected to other components.
All the other unused pins are left floating and not usually configured as INPUT_PULLUP. And these sketches/ projects work perfectly well; clearly it does not matter in the slightest. Also, most analog pins are simultaneously digital inputs, and deliberately driven into the "linear" region.
Now if your program code is affected by the state of pins which you have not actually connected, whose fault it that?
Its good design practice to avoid leaving unused pins floating. High impedance input(s) = antennae(s) just waiting to pickup RF or EMI.
I don't know how many threads here have had issues with relays switching an AC load. For applications like this or any application in a noisy environment, I would definitely recommend at least using INPUT_PULLUP for all unused pins.
I know most Arduino uses never set unused inputs to PU/PD resistor or use external resistors, heck I don't myself when I'm dicking around.
But that doesn't make it the right thing to do. On a real project I make sure ALL inputs are tied off one way or another.