Background Information
I have used CAN a few times now for multiple devices distributed over a physically small area, like within a few 10s of meters. In each case, the CAN bus was internal to the system and we could specify exactly what the protocol over CAN would be. None
of these systems had to, for example, interface with OBDII, NMEA2000, etc, where a specific protocol was already defined. One case was a large industrial machine that required lots of distributed sensors and actuators. The outside world interface just dealt with the overall operation of the machine. How the controller got the sensor information and caused the actuators to do stuff was a internal implementation choice that we happened to use CAN for. In another case, a company needed a good way for their customers to control multiple (up to a few dozen) of the gizmos they make within a single larger system. In this case we specified CAN as one communication means and documented the protocol. This protocol would be implemented by the controller of this system, but not surfaced to the end customer which bought this system as a whole and communicated with it thru different means at a higher level.
The EmCan solution
I have converged on a way of dealing with this over several implementations. I am now in the middle of two more such implementations, and this time I decided to use the previous experience to create a formal spec for a infrastructure layer immediately above CAN. CAN is a well designed protocol as far as it goes, and is directly implemented in a number of microcontrollers nowadays. It seems a natural way to connect multiple little devices over a limited physical distance as long as the data rate isn't too high. Basically, it can do everything you probably would have used RS-485 for 20 years ago, except that more protocol layers are specified, the specification makes sense, and hardware implementations are available built into low cost microcontrollers.
The result of this is what I call EmCan (EMbed CAN). I am slowly filling out the formal protocol specification as I migrate code from the previous implementations, generalize the concepts a bit, and make re-usable firmware modules where the EmCan protocol code can be used without change accross a variety of projects. I'm not really ready to officially publish the spec yet and provide the reference implementations, but you can look at what is there to see where things are heading. The current document is a work in progress, as it itself says.
So far I have PIC 18 and dsPIC 33 implementations of the EmCan device side, a stripped down host implementation for PIC 18, and a more full (more things handled locally) implementation for the dsPIC 33. Everything documented in the current version is implemented and seems to be working. I am working on the byte stream interface right now. I did this before in one of the previous systems, but it was more tied into the application and not a nice separable layer like EmCan.
The issue with a switched load
I think trying to switch the CAN bus with FETs or analog switches is a really bad idea. The main reason for the bit rate versus length tradeoff is not the total resistance of the cable, but the round trip propagation. Look at how CAN detects collisions, and you will see this mechanism assumes signal propagation from one end to the other within a fraction of a bit time. The CAN bus needs to be kept a transmission line. For most implementations, such as when using the common MCP2551 bus driver, the characteristic impedance should be close to 120 Ω. That means a 120 Ω resistor at each end of the bus, so any point on the bus looks like a 60 Ω load.
How EmCan fixes this
EmCan solves the node address problem without requiring special hardware. For details, see the EmCan spec, but basically, each node has a globally unique 7 byte ID. Each node periodically requests a bus address and sends this ID. The collision detection mechanism will guarantee that the bus master sees only one of these requests even if multiple nodes send a address request at the same time. The bus master sends a address assignment message that includes the 7 byte ID and the assigned address, so at most one single node is assigned a new address at a time.
If you are interested in this concept and are willing to discuss details of your system, talk to me. My biggest fear right now is specifying something that will be awkward later or prohibit certain usage that I hadn't considered. Having another implementation in progress as the spec is being finalized would be good for spec development and to test out the reference implemenation if you plan to implement it on Microchip PICs.
If you choose CAN then the "best" micro is one with CAN built in (many have this, Coldfire MCF5225x is one example).
I2C or RS485/RS422 are good choices too, depending on the electrical characteristics of the situation (distance, noise, power). The rest comes down to the protocol you use for communicating - how to address messages, control flow, avoid collisions.
I'll wish you good luck finding a micro which will work at 180c, automotive spec tops out at 125c and I don't think even military spec improves drastically on that.
You need to start with layer 1 (electrical) to work out what the physical interface has to do, after that it's mostly a software issue on how you talk. These days, ethernet might even be a viable option if the micros have the space to run a modest OS.
Best Answer
I mentioned SMBus in the comments, which is a variation of I2C. As far as I can tell, the only part of this that you need over a standard I2C protocol is the portion known as the ARP - Address Resolution Protocol. This part basically allows for address conflicts to be resolved automatically by dynamically reassigning a device to some other address if a conflict is detected.
Section 6.6 (page 48) of the SMBus 3.0 spec goes into detail on how this works. The full process is kind of complicated, as SMBus is designed to do a lot of things, cope with new devices appearing on the fly (hot plug), and having devices with fixed addresses.
You could either follow that document and implement a fully fledged SMBus (or see if you can find one in your favourite programming language), or create something inspired by the process.
If your system is simply N similar microcontrollers, one which is a master, and the others are slaves, I can envisage an inspired process which works as described below. Essentially to work, the master would keep a list of known slave addresses (ones which it has assigned), and keep a pool of reserved addresses which it can assign to new devices. The slaves have a unique identifier, and a register which keeps track of what their address is, and whether the address has been assigned yet.
After reset, the master clears its list of known addresses, and the slaves all revert back to some constant default address (all devices go to the same default), and set a register to indicate to themself that they have no assigned address yet.
The master sends a special read command to the default address, which tells all slaves listening on that address that address resolution is about to take place.
Any device which has not yet been assigned an address will immediately acknowledge the read and start replying with their unique identifier.
If there is no acknowledge, the master knows there are no more devices without an address. Go to step 7.
If an acknowledge is received, the master continues its read to receive the UUID of any slave that is responding. If there are multiple devices, they will all start talking at once, this is not an issue. Go to step 4.
As the slave device starts sending out its UUID, it must simultaneously be reading the SDA signal to check for bus contention. I2C hardware typically does this anyway if multi-master is supported. Many MCUs include a flag in their I2C implementation which detects and reports the contention
If a slave detects bus contention whilst trying to send its UUID, it must immediately stop transmitting. Otherwise it keeps sending its ID.
Eventually as the read continues, a full UUID will be read back by the master - only one slave device will be left at the end of the read, because bus contention is automatically resolved by giving priority to whichever slave has the UUID with most zero bits at the start (I2C is open drain, so a conflict will always result in a zero being sent). This also has the advantage that if you have the same devices in the system, they will end up with the same address each time.
Once the master has read a UUID back, it then sends a write command to the default address which echos back the UUID and sends a new slave address from the reserved pool. The slave with that UUID detects it is being talked to, acknowledges the master, and then changes its address to the provided address. Upon acknowledge, the master also stores the address and UUID in its table of known devices.
Go back to step 2.
Once all devices have been assigned address, the master now has a complete lookup table of all addresses its given out, and the UUID of the device at that address. Each slave device has a unique I2C address.
You can now use a simple I2C protocol to talk to each device using their assigned address, as if they simply had a fixed address. The address can be looked up in the masters UUID to slave address map.
If devices are likely to be hot plugged, or added later, or might reset unexpectedly, then you can perform ARP again. Any new device or device that crashed and reset will respond and either be reassigned the same address (if the UUID matches a value in the masters lookup table) or assigned a new address from the pool (if a new UUID). You can either periodically check for new devices at an interval of your choosing (good for hotplug) or rescan only if a previously known device stops responding (good to detect a reset).
If the master is likely to be reset without the slaves being reset, you will need an additional command in your arsenal. I2C features a broadcast address 0x00, to which every slave must listen to (usually this is write only). After a reset, the master can issue a write command to this address which instructs all slave devices on the bus to forget their previously assigned addresses and revert to the default address. The ARP process can now reassign all addresses that the master forgot.