I would suggest using 74HC165's (eight inputs each) and 74HC595's (eight outputs each); you can add any amount of I/O using only three or four port pins total. Further, unlike the 74HC164 that others have suggested, the 74HC595 includes output latches so the outputs will not glitch while the data are being shifted; it also includes a global output-enable signal and asynchronous reset. To wire the devices, you should tie the shift clock wires of all devices to one port pin and the load/latch wires to a second pin. The data-in from one of the 595's should be connected to a port pin; its data out should feed the next part's data-in, etc. until the last part's data-out either feeds another port pin or else goes through a 1K resistor into the pin that's used for the PIC's output data. The one caveat with this method is that any time you want to change any of the outputs or read any of the inputs, you'll have to do them all. You should thus plan carefully what devices you place on the shifters and what ones you put on the "high speed" port pins of the PIC itself. Still, I have used this method quite effectively on a system with 32 inputs and 32 outputs and found it more convenient than just about anything else (although I2C devices may allow you to update some data without rewriting everything, the extra overhead of the I2C protocol may largely negate this advantage). One other type of port expansion produced by Dallas Semiconductor that I'll mention because it's cute (whether it's practical is another question) is their one-wire-interface I/O port. It's a little TO-92 which can read or ground (open-collector) one I/O pin. It hangs on Dallas's one-wire bus and thousands of them could be controlled individually with a single port pin. Note sure if it's useful in many applications, but certainly cute.