How to Network Many Arduinos w/Sensors using I2C
In this example, I have wired five Arduino (ATmega328) microcontrollers together via I2C protocol. Four Arduino slave units read from accompanying sensors then send their respective sensors' data to a master Arduino unit for processing. The Arduino example code has been enhanced with arrays and min/max constants so now it can be used with few modifications to support any number of Arduino I2C nodes with any size payload, within the limitations of I2C in a Master Reader/Salve Sender configuration. When it comes to I2C, the headache is not in the wiring which is simple, but in synchronizing the I2C nodes and data transmission. I hope my code can simplify some of your Arduino networking.
If you want to connect many sensors and other components to your microcontroller but you don't have enough pins, or enough memory to run the needed libraries and code, or the microcontroller is just not fast enough to juggle the computations, you can always swap the old microcontroller with a more powerful one.
Or, depending on your project design, you simply modularize your circuit by spreading your sensors and components over multiple microcontrollers. Then network the microcontrollers using a protocol such as I2C.
Recently, I had to build a prototype made up of many components and sensors. The wiring and coding to glue all of these parts together were cumbersome. To make matters more frustrating my Arduino ran out of memory. So I decided to divide my circuit the way I divide large programs into smaller subroutines.
Instead of one Arduino with a dozen or so sensors and components attached to it, now I have five Arduinos each supporting one or two sensors. The sensor data is then sent to the master Arduino unit to do integration calculations and I/O.
By pairing key components with a microcontroller and programming it to send data via I2C to a central microcontroller, I have modularized my design making it simpler to construct and debug.
This is how many gadgets are built today, from cell phones to computers. Components from various vendors plug into a network such as I2C instead of being wired into pins of central
Most of my code now is decentralized. Each of my I2C networked component has enough processing power dedicated to it. When it's ready, it sends its data to my central Arduino using only 2 wires, one for data and the other for timing.
Better yet, these components can be hot-swapped. I2C specifications make it possible to plug and unplug I2C nodes into the bus while its running. Cool! I tested this feature by unplugging then plugging slave nodes, and the network kept working. This is not exhaustive testing of the hot-swap feature of I2C, but it was interesting to try.
The price of microcontrollers today is so low you can get an Atmel microcontroller with I2C support for a couple of dollars. That's peanuts when compared to the savings in time (and money) as will as the fault tolerance you gain by modulrazing your system design instead of a monolithic microcontroller with a dozen components attached and managed by complex program with a single point of failure.
Philips Semiconductors (now NXP Semiconductors) developed a simple bidirectional 2-wire bus for efficient inter-IC control. This bus is called the Inter-IC or I2C-bus. Only two bus lines are required: a serial data line (SDA) and a serial clock line (SCL). Serial, 8-bit oriented, bidirectional data transfers can be made at up to 100 kbit/s in the Standard-mode, up to 400 kbit/s in the Fast-mode, up to 1 Mbit/s in the Fast-mode Plus (Fm+), or up to 3.4 Mbit/s in the High-speed mode. The Ultra Fast-mode is a uni-directional mode with data transfers of up to 5 Mbit/s
I2C for Arduino supports 127 attached devices via pins Analog 04 (SDA) and Analog 5 (SCL). The I2C pins may vary on different Arduino boards.
This is not a tutorial of I2C. If you are interested in learning more see the resources section below and visit this comprehensive I2C tutorial by John Boxall
This is the list of components I have used in this project. Your project may have different requirements.
In this example, I am using 5 Arduinos. 1 acting as a master unit (to use I2C lingo) and 4 as slave units. The slave Arduinos wait for the master Arduino to request data then send it promptly.
I am using a potentiometer plugged into the Analog 0 pin of each slave Arduino to simulate a sensor.
By turning the pot which is wired as a voltage divider, I will change the value of Analog 0. The code in each slave node will read Analog 0 and send its value to the master Arduino.
The I2C specifications call for two pull-up resistors one for the SDA line and the second for the SCL line. For this demo circuit, initially I did not use any resistors just to test the stability. Then I used 10K Ohm pull-up resistors. I did not run into any issues in the short time I have tested the circuit. But in a production environment, the two pull-up resistors values must be calculated according to a formula explained in section 7.1 Pull-up resistor sizing (pdf) of the official I2C manual by NXP.
For hi-res schematic, download attached file i2c_arduino.png
I have two programs: one for the master Arduino, and a second for all the slave Arduinos. Before uploading the program to each slave Arduino, change the node I2C address number to make sure each Arduino node on the I2C bus can be identified with a unique address. The addresses are in HEX.
The example code is ready to upload to any number of I2C nodes (within the 127 node limit). Simply change the #define constants to change the maximum nodes and the node payload size.
Arduino has a bundled library for I2C communications named Wire.h . The related examples are simple enough to understand and modify.
Program: I2C Master Reader
Program: I2C Slave Sender