I2C is the bus protocol or technology through which a microcontroller can communicate with many sensors or actuators. Thanks to the right software you can also connect different microcontrollers with each other and let them communicate. Normally there is only one master per I2C bus which can request data from or send data to a slave via the corresponding address.
In one of my projects I wanted or want to connect several microcontrollers. Several bus technologies are suitable for this. But I2C is almost the only one which is directly supported by almost every modern microcontroller without additional hardware requirements. So the choice was quickly made for I2C.
So by means of I2C several microcontrollers were or are now connected with each other. The master can easily send a command to each individual slave. To do this, simply send the slave address and the desired command over the bus. All slaves listen to what is going on on the bus, but only the slave with the corresponding address reacts to the sent command. So far so good.
But what if the master wants to send a command to all slaves? For example to start a command synchronously on all slaves? With two or three slaves you can still inform each slave individually. The processing speed is usually so fast that you don't notice a big time difference between the executions on the individual slaves. However, if you use this method with 100 slaves, you will quickly notice that the last notified slave starts much later than the first slave.
The solution for this problem is the I2C broadcast address. This is an address that every slave on the bus listens to. To activate this you just have to set a control bit. At least this is how it works with Arduinos based on Atmel processors đ .
How to set this bit is described in the following article.
Enable I2C broadcast for I2C slaves
So that all nodes on the I2C bus can be notified across the board, there is the broadcast address "0". So the zero is fixed defined as the address for broadcast messages and should not be used by any other slave.
By default a microcontroller does not respond to this address. This has to be activated by setting the corresponding control bit. You just have to insert the following line into the "setup()" function of your program code.
TWAR = (address << 1) | 1; // enable listening on broadcast messages
In a complete I2C initialization function this could for example look like this
void init_i2c() { Wire.begin(address); TWAR = (address << 1) | 1; // enable listening on broadcast messages Wire.onReceive(i2c_receive_event); Serial.print(F("I2C: I2C slave initialized at address: ")); Serial.println(address); }
General information about I2C and interrupts
An event on the I2C bus always calls an interrupt, which interrupts the regular sequence of your microcontroller. So the program execution jumps briefly from the regular program to the interrupt routine. But you should keep the stay in this routine as short as possible. Therefore it is "common practice" to set a "flag" within the interrupt routine. This "flag" is actually just a boolean variable, which is set to "true" there. Back in the main program flow of your microcontroller you can now regularly check if this variable is set.
If yes, you can now read out the received data or commands and react accordingly.
By the way: You should not use "Serial.print..." or similar time-consuming commands within the interrupt routines.
Further information
http://forum.arduino.cc/index.php?topic=183699.0
http://www.gammon.com.au/forum/?id=10896&reply=1#reply1
Have fun with the project
I hope everything worked as described for you. If not or you have questions or suggestions please let me know in the comments. I will then add this to the article if necessary.
Ideas for new projects are always welcome. đ
PS Many of these projects - especially the hardware projects - cost a lot of time and money. Of course I do this because I enjoy it, but if you think it's cool that I share the information with you, I would be happy about a small donation to the coffee fund. đ