Skip to content

14. Communications


Week assignment

  • Sending a message between two projects (in group)
  • Designing, building, and connecting wired or wireless node(s) with network or bus addresses (individually)

How will my modules communicate with another device?

I wanted to use this week to understand how the components of my board were going to communicate between each other with the game on another device.

I’ll need only one board with the MPU6050 and the OLED and also an HC-10.

board communication

What’s UART?

UART stands for Universal Asynchronous Receiver/Transmitter. So, as it’s name says, it’s main purpose is to transmit and receive serial data. It only uses two wires to transmit data between devices. However, it’s not a communication protocol I2C, but a physical circuit in a microcontroller.

We’ll have a Reciving UART and a Transmitter UART. The UART that is going to transmit data receives the data in this case from the microcontroller. Then, the Data is transferred to the transmitting UART. There are some additional steps in the process and all this data from the UART transmitted is organized into packets. One advantage is that the receiving UART to tell if any data has changed during transmission. One main disadvantage is that it can only manage communications between two, and only two, devices.

What’s I2C?

I2C is a serial communication protocol, so data is transferred bit by bit along a single wire (the SDA line). Using I2C we can connect multiple devices and also have multiple controllers. Like UART communication, I2C only uses two wires to transmit data.

  • SDA (Serial Data) – The line for the master and slave to send and receive data.

  • SCL (Serial Clock) – The line that carries the clock signal.

Each follower has a unique device address so the conductor can choose with which follower will be communicating.

Designing, building, and connecting wired or wireless node(s) with network or bus addresses

As part of this week assignment I needed to design, build and connect nodes. One of my options to deal with the memory issues was to use 2 microcontrollers and connect them using TX/RX. By this moment I’ve already designed a new board using an Attiny3216, but I still wanted to try how this worked.

So, as I used my fist Attiny1614 and my new Attiny3216. I wanted to try I2C, so I connected SDA and SCL from my boards. My goal was to try something simple, so I wanted my controller to send a message to the follower to blink the led

attinys

Code for the Controller:

#include <Wire.h>

void setup()
{
  Wire.begin(); // join i2c bus
}

void loop()
{
  Wire.beginTransmission(1); // transmit to device #1
  Wire.write("1");        // sends one byte
  Wire.endTransmission();    // stop transmitting

  delay(500); //time it takes to send the value
}

Then, I flashed the follower with this code:

#include <Wire.h>
#define LED_BUILTIN 10 //PC0 (Pin 10)


void setup()
{

  Wire.begin(1);                // join i2c bus with address #1
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
  // initialize digital pin LED_BUILTIN as an output.
    pinMode(LED_BUILTIN, OUTPUT);
}


void loop()
{
  delay(500);
  Serial.println("chau");

}

bool ledon = false; //boolean variable 

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  Serial.println("hola");

    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character

    if (ledon){
      digitalWrite(LED_BUILTIN, LOW);    // if the LED is on then turn the LED off by making the voltage LOW
    } else {
      digitalWrite(LED_BUILTIN, HIGH);   // if the LED is off turn the LED on (HIGH is the voltage level)
    }
   ledon = !ledon; // ledon is the variable that indicates if the LED is on or off

}

attinys

Connecting my board and my phone using an HC-10

I didn’t remember which were the ATtyiny1614 for Tx and Rx so I had to check the pinout diagram. I added an illustration of the HC-10 as shows how simple the module is (at least for wiring). I just connected Tx, Rx, GND and VCC. This module also has a power consumption of 3.3V. I specifically looked for low energy components because I need my device to be as small as possible.

pinout

When I discussed about the final project with Oscar he shared with me this repository.

So, I started by flashing the code to see if it worked. In my case Tx was pin 5 and Rx pin 4. So, I changed them. I also moved the “Goodnight moon!” out of the setup, just because I constant validation.

/*
  Software serial multple serial test
 Receives from the hardware serial, sends to software serial.
 Receives from software serial, sends to hardware serial.
 The circuit:
 * RX is digital pin 10 (connect to TX of other device)
 * TX is digital pin 11 (connect to RX of other device)
 Note:
 Not all pins on the Mega and Mega 2560 support change interrupts,
 so only the following can be used for RX:
 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69
 Not all pins on the Leonardo and Micro support change interrupts,
 so only the following can be used for RX:
 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
 created back in the mists of time
 modified 25 May 2012
 by Tom Igoe
 based on Mikal Hart's example
 This example code is in the public domain.
 */
#include <SoftwareSerial.h>

SoftwareSerial bluetooth(5, 4); // RX, TX

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Goodnight moon!");

  // set the data rate for the SoftwareSerial port
  bluetooth.begin(9600);
  bluetooth.println("Hello, world?");
}

void loop() { // run over and over
  if (bluetooth.available()) {
    Serial.write(bluetooth.read());
  }
  if (Serial.available()) {
    bluetooth.write(Serial.read());
  }
}

It worked fine.

Bluetooth code

Next step was to share some information with another device. So, I followed this tutorial and downloaded from Apple Store an app called LightBlue as it’s an app that can connect to a device that usese BLE (Bluetooth Low energy). HC-10 is BLE. I also had to check this as I had no idea how to write a message or recieve one: How to use LightBlue.

Trying LightBlue

  1. First we need to choose the device. Mine was BT05. I found it by connecting/disconnecting.
  2. Then, we’ll need to scroll down and tap TX & RX. To see something on the screen we’ll need to select UTF 8-string, HEX is selected by default.
  3. If you choose write new value, you can send a message to the device.
  4. If you choose to listen you’ll recieve the data from the device or you can send a message via the serial monitor.

BLighblue screens

In my case, I wanted to see in my phone the gyroscope’s position. To do that I needed to mix my new code with the code I made for last week, the one that has the OLED and the MPU6050. I wanted to be able to send angle Y to my phone and simultaneously print it on the OLED.

In order to do this I used the following code:

// Choose your I2C implementation before including Tiny4kOLED.h
// The default is selected is Wire.h

// To use the Wire library:
//#include <Wire.h>

// To use the Adafruit's TinyWireM library:
//#include <TinyWireM.h>

// To use the TinyI2C library from https://github.com/technoblogy/tiny-i2c
//#include <TinyI2CMaster.h>


#include <Tiny4kOLED.h>
#include <Wire.h>
#include <MPU6050_light.h>
MPU6050 mpu(Wire);

#include <SoftwareSerial.h>

SoftwareSerial bluetooth(4, 5); // RX, TX


void setup() {
 // set the data rate for the SoftwareSerial port
  bluetooth.begin(9600);

  // Send the initialization sequence to the oled. This leaves the display turned off
  oled.begin();

  // Two rotations are supported,
  // The begin() method sets the rotation to 1.
  //oled.setRotation(0);

  // Some newer devices do not contain an external current reference.
  // Older devices may also support using the internal curret reference,
  // which provides more consistent brightness across devices.
  // The internal current reference can be configured as either low current, or high current.
  // Using true as the parameter value choses the high current internal current reference,
  // resulting in a brighter display, and a more effective contrast setting.
  //oled.setInternalIref(true);

  // Two fonts are supplied with this library, FONT8X16 and FONT6X8
  // Other fonts are available from the TinyOLED-Fonts library
  oled.setFont(FONT8X16);

  // Clear the memory before turning on the display
  oled.clear();

  // Turn on the display
  oled.on();

  // Switch the half of RAM that we are writing to, to be the half that is non currently displayed
  oled.switchRenderFrame();
  Serial.begin(9600);
   Wire.begin();
 byte status = mpu.begin();
   Serial.print(F("MPU6050 status: "));
   Serial.println(status);
   while (status != 0) { } // stop everything if could not connect to MPU6050
 Serial.println(F("Calculating offsets, do not move MPU6050"));
   delay(1000);
   mpu.calcOffsets(); // gyro and accelero
   Serial.println("Done!\n");
}

void loop() {

  mpu.update();

//     Serial.print("X : ");
//     Serial.print(mpu.getAngleX());
//     Serial.print("\tY : ");
//     Serial.print();
//    Serial.print("\tZ : ");
//     Serial.println(mpu.getAngleZ());

  delay(50);
  float angle = mpu.getAngleY(); // declare the angle Y of the gyro on the variable angle
  updateDisplay(angle);
  Serial.println(angle);

}

void updateDisplay(float angleY) {
  // Clear the half of memory not currently being displayed.
  oled.clear();

  // Position the text cursor
  // In order to keep the library size small, text can only be positioned
  // with the top of the font aligned with one of the four 8 bit high RAM pages.
  // The Y value therefore can only have the value 0, 1, 2, or 3.
  // usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
  oled.setCursor(0, 1);

  // Write text to oled RAM (which is not currently being displayed).
  oled.print(F("ms: "));

  // Write the number of milliseconds since power on.
  oled.print(mpu.getAngleY());

  // Swap which half of RAM is being written to, and which half is being displayed.
  // This is equivalent to calling both switchRenderFrame and switchDisplayFrame.
  oled.switchFrame();
}
showing the same data

New board: Attiny3216

After struggling with Attiny1614 memory size I decided to make a new board using an Attiny3216. I’m iterating towards the board for my final project but I need to define a size as soon as possible. My device need to be small enough to fit on top of a shoe. So, I started thinking of sandwich and how my components should be placed. After some consideration, I ended up with this board.

Schematic of the new board. I missed connecting the LED to VCC so I made a switch between the LED and the resistor.

schematic

Soldering and testing my board.

building

Testing the board with the modules with the code that I used to flash the Attiny1614.

working

Download files here:

My next steps are:

  1. Add the battery(3.3v) and the battery charger.
  2. Improve board design (fix LED, add holes, improve the use of height)
  3. Connect the board with Unity 3D.

Sending a message between two projects

I did this with Diego as we both were working with I2C and Attinys. So, we decided to merge his test code with mine.

group assignment

We enede up with this code for the controller

#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  Serial.println("start");
  delay(1000);
}

void loop() {
  Serial.println("first req");
  Wire.requestFrom(8, 6);    // request 6 bytes from slave device #8
  Serial.println("requesting");

  while (Wire.available()) { // slave may send less than requested
    Serial.println("reading");
    char c = Wire.read();    // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(500);
}

And for the follower we ended up using Diego’s code. Mainly because we found that our boards were not working well together. Josep helped us to figured out what was going on and then Edu found that a 10k resistor was needed to make comunication more stable.

#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("diego "); // respond with message of 6 bytes
      // as expected by master
  }

after josep

Tip

Our take away from this part of the assignment was that I2C may need resistors for SDA and SCL to be more stable. In some plates it can work perfectly but in others not. Things can happen like the OLED suddenly turns off or there is a failure for no reason. So, I decided to add a couple of resistors to my new-to-be-born board.


Last update: July 4, 2021