14. Networking and communications¶
- Design, build, and connect wired or wireless node(s) with network or bus addresses
For this week assignment, I had to send a message between any combination of boards, computers and/or mobile devices. My original idea was to work on sending a message between a board with servo motors connected and one with the color sensor. However, life happened and I had to change my plans.
In the previous weeks I described how I designed and produced an All-in-One board with the aim to use it for as many assignments as possible. You can find the documentation in the following assignments:
I milled and soldereded two boards in order to have the possibility to use them also for this assignment, as it actually turned out.
๐ Communication¶
Before starting, I had to understand how communication works between two boards.
๐ I2C and Serial communication¶
IยฒC (short for Inter Integrated Circuit), (pronounced i-quadro-ci or i-two-ci), is a two-wire serial communication system used between integrated circuits.
The classic IยฒC bus consists of at least one master and one slave (literally “boss, master” and “subordinate, slave”). The most frequent situation sees a single master and several slaves; however, multi-master and multi-slave architectures can be used in more complex systems.
๐ Negative logic¶
The circuit reasons with negative logic so I need pull-up resistors and to do this I need a small breadboard following the drawing below:
๐ฏ Arduino Uno¶
I started with two Arduino Uno.
int servoPin = 10;
#include <Wire.h>
void setup() {
Wire.begin(); // join I2C bus (address optional for master)
Serial.begin(9600); // start serial for output
pinMode(servoPin, OUTPUT);
}
void loop() {
Wire.requestFrom(8, 6); // request 6 bytes from slave device #8
while (Wire.available()) { // slave may send less than requested
char c = Wire.read(); // receive a byte as character
Serial.print(c);
for (c = 0; c < 250; c + 25) {
analogWrite(servoPin, c);
delay(500);
}
}
delay(500);
}
#include <Wire.h>
void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onRequest(requestEvent); // register event
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Wire.write("hello"); // respond with message of 6 bytes
// as expected by master
}
master servo
int servoPin = 10;
int acc = 0;
#include <Wire.h>
void setup() {
Wire.begin(); // join I2C bus (address optional for master)
Serial.begin(9600); // start serial for output
pinMode(servoPin, OUTPUT);
}
void loop() {
Wire.requestFrom(8, 1); // request 6 bytes from slave device #8
while (Wire.available()) { // slave may send less than requested
char c = Wire.read(); // receive a byte as character
Serial.print((byte)c);
acc += byte(c) * 3;
analogWrite(servoPin, acc);
//delay(500);
}
delay(500);
}
Slave sender
#include <Wire.h>
bool flag;
void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onRequest(requestEvent); // register event
flag = false;
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
if (flag) {
Wire.write(0); // respond with message of 6 bytes
} else {
Wire.write(255); // respond with message of 6 bytes
}
flag = !flag;
// as expected by master
}
And this is the servo rotating accordingly:
๐งถ Code¶
The first thing I did regardin the code was to write a code that made the servo move according to time.
int servoPin = 8;
int d = 500;
void setup() {
pinMode(servoPin, OUTPUT);
}
void loop() {
analogWrite(servoPin, 0);
delay(d);
analogWrite(servoPin, 70);
delay(d);
analogWrite(servoPin, 180);
delay(d);
analogWrite(servoPin, 90);
delay(d);
}
๐ฉ Master¶
For the master board, I wrote a code using the Wire documentation I found on Arduino.cc. This was very helpful to understand how the code should be structured. Here is the full code.
#include <Wire.h>
int d = 500;
void setup() {
Wire.begin();
}
void loop() {
for (byte i = 0; i < 250; i+=25) {
Wire.beginTransmission(8);
Wire.write(i);
Wire.endTransmission();
delay(d);
}
}
Disclosing it in its parts, first off I include the Wire library.
#include <Wire.h>
Then in the setup, I initialize the Wire library and join the I2C bus as a controller. This function should normally be called only once.
void setup() {
Wire.begin();
}
In the loop, I programmed the action of the actual transmission from the master to the slave. I did so first off initiating a for cycle with bytes as variable. Then I used the function begin.Transmission() to begin a transmission to the I2C peripheral device with the given address, which in my case is 8. Subsequently, the function queue bytes for transmission with the write() function and transmit them by calling endTransmission().
void loop() {
for (byte i = 0; i < 250; i+=25) {
Wire.beginTransmission(8);
Wire.write(i);
Wire.endTransmission();
delay(d);
}
๐งข Slave¶
For the slave board, I needed the servos to move accordingly to the bytes that are received. For this code, too, I used the Wire documentation I found on Arduino.cc.
#include <Wire.h>
#define SERVO 8;
void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onReceive(receiveEvent); // register event
pinMode(SERVO, OUTPUT);
}
void loop() {
delay(100);
}
void receiveEvent(int howMany) {
while (1 < Wire.available()) {
byte c = Wire.read();
}
analogWrite(SERVO, c);
}
Disclosing it in its parts, first off I include the Wire library and defined the pin for my servo motor.
#include <Wire.h>
#define SERVO 8;
In the setup, I initialized the Wire library and join the I2C bus peripheral 8. I then used onReceive function to register receiveEvent to be called when the board receives a transmission from the controller board. I then attached the servo to its pin with pinMode.
void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onReceive(receiveEvent); // register event
pinMode(SERVO, OUTPUT);
}
I then set a delay in the loop cycle.
void loop() {
delay(100);
}
Lastly, I created a function called receiveEvent that moves the servo accordingly to the bytes received.
void receiveEvent(int howMany) {
while (1 < Wire.available()) {
byte c = Wire.read();
}
analogWrite(SERVO, c);
}
๐ฉด Final¶
๐ซ Master - ATtiny44¶
For the master board, I decided to use the ATtiny44 one. In order to do so, I had to change the library. The Wire.h only works for Arduino, indeed, and luckily there is a library also for ATtinys which is TinyWire. Here you find the documentation and the repository of this library. Of course, I had to change all the Wire functions in TinyWireM ones, but that was the only deal I had.
#include <TinyWireM.h>
int servoPin = 8;
int acc = 0;
void setup() {
TinyWireM.begin(); // join I2C bus (address optional for master)
// mySerial.begin(9600); // start serial for output
pinMode(servoPin, OUTPUT);
}
void loop() {
TinyWireM.requestFrom(8, 1); // request 6 bytes from slave device #8
while (TinyWireM.available()) { // slave may send less than requested
char c = TinyWireM.read(); // receive a byte as character
// mySerial.print((byte)c);
acc += byte(c) * 10;
analogWrite(servoPin, acc);
//delay(500);
}
delay(500);
}
๐๏ธ Slave - ArduinoUno¶
As a slave I used an ArduinoUno. Here is the code:
#include <Wire.h>
bool flag;
void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onRequest(requestEvent); // register event
flag = false;
}
void loop() {
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
if (flag) {
Wire.write(0); // respond with message of 6 bytes
} else {
Wire.write(255); // respond with message of 6 bytes
}
flag = !flag;
// as expected by master
}