You want to use USB for communications with the computer. If you have a number of microcontrollers, you will probably only connect one of the microcontrollers directly to the computer. The other microcontrollers will need to get their commands from the main microcontroller.
The communication you choose will depend on a number of factors:
- required bandwidth (we will assume you are running them at 16MHz)
- complexity (wiring and coding)
- bi-directional, or master-slave
Almost all options have built-in support on the AVR microcontroller. There is no option you might reasonably prefer over the built-in options which would require additional hardware. Because they have built-in support, the software complexity is all similar, in that you just configure the port (using registers), put the data to transmit in another register, then trigger the transmission by setting a bit in another register. Any data received is found in another register, and an interrupt is triggered so you can handle it. Whichever option you choose, the only difference is the change in register locations, and some changes to the configuration registers.
A USART loop has the following features:
- Maximum baud rate of CLK/16 = 1MHz (at 16MHz clock) which is a transfer rate of around 90KB/s
- fully bi-directional communications (no master or slave designation)
- requires separate wires between each pair of microcontrollers - the Atmega32u4 supports two USART ports natively, limiting the number of microcontrollers you can connect in a network in practice (or else you end up with a long string of microcontrollers - ie. connected in a linked list manner)
Note: this is also what you would use to get RS232 communication, except that because RS232 requires 10V, it requires a driver to get those voltage levels. For communication between microcontrollers, this is not useful (only voltage levels are changed).
RS485:
- Essentially, you use the USART port in a different mode - there is no advantage in bandwidth, and it may only simplify the wiring slightly, but it also complicates it. This is not recommended.
Two-wire interface:
This is also referred to as I2C. This means that all devices share the same two wires.
You need a pull-up resistor on both wires
It is slow (because the pull-up resistors are limited in value, and there is increasing capacitance as the number of devices increases, and the wire length increases). For this AVR microcontroller, the speed is up to 400 kHz - slower than USART (but this speed depends on limiting your capacitance). The reason is that although a device drives the data wire low, the opposite transition is accomplished by letting the wire float high again (the pull-up resistor).
It is even slower when you consider that ALL communication shares the same limited bandwidth. Because all communication shares the same limited bandwidth, there may be delays in communication where data must wait until the network is idle before it can be sent. If other data is constantly being sent, it may also block the data from ever being sent.
It does rely on a master-slave protocol, where a master addresses a slave, then sends a command/request, and the slave replies afterwards. Only one device can communicate at a time, so the slave must wait for the master to finish.
Any device can act as both a master and/or a slave, making it quite flexible.
SPI
This is what I would recommend/use for general communication between microcontrollers.
It is high speed - up to CLK/2 = 8MHz (for CLK at 16MHz), making it the fastest method. This is achievable because of its separate wire solely for the clock.
The MOSI, MISO data, and SCK clock wires are shared across the whole network, which means it has simpler wiring.
It is a master-slave format, but any device can be a master and/or slave. However, because of the slave select complications, for shared wiring (within the network), you should only use it in a hierarchical manner (unlike the two-wire interface). IE. if you organise all devices into a tree, a device should only be master to its children, and only a slave to its parent. That means that in slave mode, a device will always have the same master. Also, to do this correctly, you need to add resistors to MISO/MOSI/SCK to the upstream master, so that if the device is communicating downstream (when not selected as a slave), the communications will not affect communications in other parts of the network (note the number of levels you can do this using resistors is limited, see below for better solution using both SPI ports).
The AVR microcontroller can automatically tri-state the MOSI signal when it is slave-selected, and switch to slave mode (if in master).
Even though it might require a hierarchical network, most networks can be organised in a tree-like manner, so it is usually not an important limitation
The above can be relaxed slightly, because each AVR microcontroller supports two separate SPI ports, so each device can have different positions in two different networks.
Having said this, if you need many levels in your tree/hierarchy (more than 2), the above solution using resistors gets too fiddly to work. In this case, you should change the SPI network between each layer of the tree. This means each device will connect to its children on one SPI network, and its parent on the other SPI network. Although it means you only have a single tree of connections, the advantage is that a device can communicate with both one of its children and its parent at the same time and you don't have fiddly resistors (always hard to choose the right values).
Because it has separate MOSI and MISO wires, both the master and slave can communicate at the same time, giving it a potential factor of two increase in speed. A extra pin is required for the slave-select for each additional slave, but this is not a big burden, even 10 different slaves requires only 10 extra pins, which can be easily accommodated on a typical AVR microcontroller.
CAN is not supported by the AVR microcontroller you have specified. As there are other good options, it is probably not important in this case anyways.
The recommendation is SPI, because it is fast, the wiring isn't too complex, and doesn't require fiddly pull-up resistors. In the rare case where SPI doesn't fully meet your needs (probably in more complicated networks), you can use multiple options (eg. use both SPI ports, along with the two-wire interface, as well as pairing some of the microcontrollers using a USART loop!)
In your case, using SPI means that naturally, the microcontroller with the USB connection to the computer can be the master, and it can just forward the relevant commands from the computer to each slave device. It can also read the updates/measurements from each slave and send these to the computer.
At 8MHz, and 0.5m wire length, I don't think it will become a problem. But if it is, try be more careful of capacitance (keep ground and signal wires getting too close, and also be careful of connections between different conductors), and also signal termination. In the unlikely event that it remains a problem, you can reduce the clock rate, but I don't think it is necessary.