Skip to content

13. NETWORKING & COMMUNICATION - fixed. to be marked

This weeks task was to connect two or more microprocessors together and get them to communicate.

Group work

Individual assignment

  • This week individual assignment is to design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s).

parts

my board

  • The 2nd microcontroller I decided to use was the SEEED rp2040 with the vertical pins soldered on.

rp2040 wired up

Wiring it up

  • Connecting the 2 boards together involved:
  • Connecting the RX pin from board 1 to the TX pin of board 2.
  • Connecting the TX pin from board 1 to the RX pin of board 2.
  • Connecting the Vcc pin from board 1 to the 5V of board 2 so that either board could power the other (after one was disconnected from a computer).
  • Connecting the GND pin from board 1 to the 5V of board 2 so that either board could power the other.
------------     -------------
|       RX |-----| TX        |
|       TX |-----| RX        |
|      Vcc |-----| 5V        |
|      GND |-----| GND       |
|          |     |           |
|          |     |           |
|  board1  |     |    board2 |
------------     -------------
  • my ATtiny board

ATtiny wired attiny1614

  • The RP2040

RP2040 wired rp2040 pinouts

  • All wired up. Here’s what everything looks like connected together:

RP2040 wired

Programming

  • I programmed the boards using Arduino IDE.

  • I used a seperate computer for each microcontroller (a desktop and a laptop). This was to avoid potential conflicts.

  • I had a different program for each microcontroller:

  • Program 1 (Attiny board):

  • Constantly measures the the ultrasonic reading and displays it on OLED screen.
  • When it recieves a MSG, reads the MSG and displays it on OLED screen and then send a confirmation MSG and the ultrasonic reading for the exact moment back.
  • ATtiny Program
/*
James Khan Fab Academy networking and communication week week.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week13/

Used the code I developed for my input week as a starting point and modified for communication.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week11/

This program is for my selfmade Attiny14 board and has an ultrasonic sensor attached to it 
and communicates with another board (an RP2040, with a different program).

This program constantly measures the distance from the ultrasonic sensor.
When it gets sent a message on its RX data pin, it displays that message
on the attached OLED screen as well. It then sends back confirmation on the TX pin along with the
measured distance.
*/

#include <Wire.h>             // for OLED
#include <Adafruit_GFX.h>     // for OLED
#include <Adafruit_SSD1306.h> // for OLED

const int SCREEN_WIDTH = 128; // OLED display width, in pixels
const int SCREEN_HEIGHT = 64; // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // for OLED

// DEfine variables Ultrasonic
#define ECHO_PIN 9
#define TRIG_PIN 8

String incomingString ; //to hold incomming serial data.

void setup() {

  Serial.begin(115200); //

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed")); // genetare arror msg if oled can't initialize
    while(true);
  }

  // for ultrasonic setup
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

  //read and calculate the distance from ultrasonic sensor. 
long readDistanceCM() {  // changed it from the regular float because of memory issues with serial.print
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  unsigned long duration = pulseIn(ECHO_PIN, HIGH);  //corrects possible negative interperetation if measurement too big
  return duration * 0.034 / 2;
}

void loop() {

  long distance = readDistanceCM(); // changed it from the regular float because of memory issues using serial.print
  delay(200); 

  if (Serial.available()) {         
      incomingString=Serial.readString(); // If anything comes in Serial save it to variable
      Serial.print("got it: ");           // send confirmation back to sender with string sent
      Serial.println(incomingString);
      Serial.print("dist: "); 
      Serial.println(distance);           // send the distance measured from attiny's ultrasonic sensor to serial 
      delay(100);
  }

  display.clearDisplay();               // oled clear
  display.setTextSize(2);               // oled setup
    // text size of 2 only gives us grid size of 10 wide by 4 tall characters.
    // but a text size of 1 is pretty tiny to show up well on a video, but gives allot more characters.
    // the below prompts are minimal to keep the bigger size font.
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.print("d:");                // static display
  display.println(distance);          // display distance
  display.println("incoming:");       // static display
  display.println(incomingString);    // display string from serial input
  display.display();
  display.println("\n");
  delay(200);

}
  • Program 2 (RP2040):
  • When it receives a MSG on serial (from the computer’s serial monitor), reads that MSG and sends it on serial1 (to the ATtiny board).
  • When it recievs a MSG on serial1 (from ATtiny), reads that MSG and sends it to serial (computer).
  • RP2040 Program
/*
James Khan Fab Academy networking and communication week week.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week13/

Used the code I developed for my input week as a starting point and modified for communication.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week11/

This program is for an SEEED RP2040 board 
and communicates with my self made ATtiny board (with a different program).

This program constantly listens for a message on two seperate serial ports
Serial is the regular connection to the computer via USB
SErial1 is the UART connection to my second board

When a message comes in on either of the serial ports it 
sends the message on the other serial port.
*/

void setup() {
  delay(2000);
  Serial.begin(115200);               // set's up the connection speed, needs to match the other program
  delay(200);
  Serial1.begin(115200, SERIAL_8N1);  //defines a unique Serial addresses:default Serial is USB/computer, Serial1 is RX/TX or UART
  Serial.println("\n--- UART communication with XIAO RP2040 ---");
  Serial.println("-------------------------------------------------------");
}

void loop() {
  if (Serial.available()) {         // If I send anything from the computer's serial monitor
    Serial1.write(Serial.read());   // then rean it and send it over UART to other device   
       // read it and send it out Serial1 (pins 0 & 1)
    digitalWrite(29, HIGH);
    delay(50);
    digitalWrite(29, LOW);          // flashes LED to indicate received sent
  }

  if (Serial1.available()) {        // If anything comes in Serial1 (my connected second board)
    Serial.write(Serial1.read());   // then send it to the computer's serial monitor
    digitalWrite(29, HIGH);
    delay(50);
    digitalWrite(29, LOW);          // flashes LED to indicate received message
  }
}

Running the programs

  • After writing the programs to each board from their connected computers, I disconnected the Attiny from its desktop while leaving the RP2040 connected to its laptop.

  • I did this so that it could genuinly be demonstrated that they were talking to each other and not being faked with a connection to a second computer.

  • I then used the serial monitor on the laptop to send MSGs to the RP2040 and recorded the results.

V2 With node ID

  • When creating my first programs I made both the microcontrollers a little “dumb”, so I missed an element of the assignment:
  • The RP2040 just forawrded the messages it got, and never “read” the message to know if it should do anything else.
  • The ATTiny did the same, treating every message like it was meant for itself, and reacted the same.
  • I altered the RP2040’s program so that it now read the first character of any message it received and did different actions depending on what is was:
  • If the first character of any message it recieved was a “l” or “L” (standing for LED), it turned ON or OFF any of the 3 single-colour LEDs on the SEEED board.
  • the next 3 characters after the “l” or “L” refered to the R(red), G(green), or B(blue) LEDs in that order.
  • If any of these characters was a “1” it turned ON that particular LED, any other character turned it OFF.
  • If the message was one of these LED messages it DID NOT forward that message over to the other serial line.
  • I made only a tiny change to the ATTiny program just so the text of message it sent back was a little more clear as to who it came from.

  • The ATTiny Program V2 program only had that small change, so I didn’t repeat it’s whole content, but you can download the new one here ATtiny Program V2.

  • Here’s the new SEEED RP2040 Program V2:

/*
James Khan Fab Academy networking and communication week week.
Version 2 with node recognition.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week13/

Used the code I developed for my input week as a starting point and modified for communication.
https://fabacademy.org/2021/labs/vancouver/students/james-khan/assignments/week11/

This program is for an SEEED RP2040 board 
and communicates with my self made ATtiny board (with a different program).

This program constantly listens for a message on two seperate serial ports
Serial is the regular connection to the computer via USB
SErial1 is the UART connection to my second board

When a message comes in on either of the serial ports it "reads" the first character.
If that character is NOT a "l" or "L" it sends the message on the other serial port.

If that character is and "l" or "L" it means this board is being messaged directly and reads the next 3 characters 
and takes action depending on the characters. each character refers to one of 3 onboard leds RED, BLUE and GREEN
in that order. a 1 turns that LED on, anything else turns that led off.

*/

String newstring ; // to hold incomming serial data.

void setup() {
  pinMode(PIN_LED_R, OUTPUT);     // RED LED
  digitalWrite(PIN_LED_R, HIGH);  // initialize off
  pinMode(PIN_LED_G, OUTPUT);     // GREEN LED
  digitalWrite(PIN_LED_G, HIGH);  // initialize off
  pinMode(PIN_LED_B, OUTPUT);     // BLUE LED
  digitalWrite(PIN_LED_B, HIGH);  // initialize off

  delay(2000);
  Serial.begin(115200);               // set's up the connection speed, needs to match the other program
  delay(200);
  Serial1.begin(115200, SERIAL_8N1);  //defines a unique Serial addresses:default Serial is USB/computer, Serial1 is RX/TX or UART
  Serial.println("\n--- UART communication with XIAO RP2040 ---");
  Serial.println("-------------------------------------------------------");
}

void loop() {
  if (Serial.available()) {         // If I send anything from the computer's serial monitor
    newstring=Serial.readString();  // save incomming string from serial
    if ((newstring[0]=='l') || (newstring[0]=='L'))  {      // is this message for me?
      if (newstring[1]=='1') digitalWrite(PIN_LED_R, LOW);  // sets RED LED ON 
        else digitalWrite(PIN_LED_R, HIGH);                 // sets RED LED OFF 
      if (newstring[2]=='1') digitalWrite(PIN_LED_G, LOW);  // sets GREEN LED ON 
        else digitalWrite(PIN_LED_G, HIGH);                 // sets GREEN LED OFF
      if (newstring[3]=='1') digitalWrite(PIN_LED_B, LOW);  // sets BLUE LED ON 
        else digitalWrite(PIN_LED_B, HIGH);                 // sets BLUE LED OFF
      Serial.print("received [for me] and returned: ");     // send back confirmation to sender
      Serial.println(newstring);
    }
    else Serial1.println(newstring);            // if it's not for me send it over UART to other device   
       // read it and send it out Serial1 (pins 0 & 1)
    digitalWrite(29, HIGH);
    delay(50);
    digitalWrite(29, LOW);          // flashes LED to indicate received sent
  }

  if (Serial1.available()) {        // If anything comes in Serial1 (my connected second board)
    newstring=Serial1.readString();  // save incomming string from serial
    if ((newstring[0]=='l') || (newstring[0]=='L'))   {     // is this message for me?
      if (newstring[1]=='1') digitalWrite(PIN_LED_R, LOW);  // sets RED LED ON 
        else digitalWrite(PIN_LED_R, HIGH);                 // sets RED LED OFF 
      if (newstring[2]=='1') digitalWrite(PIN_LED_G, LOW);  // sets GREEN LED ON 
        else digitalWrite(PIN_LED_G, HIGH);                 // sets GREEN LED OFF
      if (newstring[3]=='1') digitalWrite(PIN_LED_B, LOW);  // sets BLUE LED ON 
        else digitalWrite(PIN_LED_B, HIGH);                 // sets BLUE LED OFF
      Serial1.print("received [for me] and returned: ");     // send back confirmation to sender
      Serial1.println(newstring);
    }
    else Serial.println(newstring);   // then send it to the computer's serial monitor
    digitalWrite(29, HIGH);
    delay(50);
    digitalWrite(29, LOW);          // flashes LED to indicate received message
  }
}

V2 Video:

Here’s what the new programs look like: - The big RED led on the SEEED board is just it’s power LED, that’s not the red LED I’m turning off or on. - The 3 LEDs I’m toggling are small and right next to each other, so it looks a little like a single LED (but it’s not). So when 2 or 3 of the LEDs are ON, it can look like a single LED with the colour being blended of the others (yellow, cyan, magenta, or white).

Lessons learnt

  • the ATtiny’s onboard memory fills up really fast. Even if you think your code is quite small, when compiling from your C++ program, it can actually get big quickly depending on the variables, libraries and profecures and functions you use.
  • I kept getting a memory full error when making small tweaks to my ATtiny program.
  • I eventually fixed it by changing the readDistanceCM function to use “long integer” variables instead of “float” variables. It seems the assembly code generated or memory allocation needed for using floating point variables was much bigger than just integers.

  • The UART protocall is a very old one, but still works really well.


Last update: May 30, 2025