Skip to content

11. Embedded Networking and Communications


Weekly Assignment:

Group assignment:

  • Send a message between two projects
  • Document your work to the group work page and reflect on your individual page what you learned

Individual assignment:

  • Design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output devices

XIAO ESP32C3 -- XIAO RP2040

For my individual assignment, I decided to combine my inputs and outputs weeks by having a XIAO ESP32C3 controlling a servo in communication with a XIAO RP2040 controlling the TTP223 touch sensor. The ultimate goal is for the servo to make a spin when the touch sensor senses my touch.


Coding

I first got each component to work seperately. Using Claude, I had it generate for me the suitable code for each part. Here is a public link to that conversation. This was the working code for the RP2040 (touch sensor):

```#define TOUCH_PIN D4 // GPIO4 for touch sensor

void setup() { Serial.begin(115200); Serial1.begin(9600); // RP2040 Serial1 uses pins 0 (TX) and 1 (RX) by default pinMode(TOUCH_PIN, INPUT);

delay(1000); // Give time for serial to initialize Serial.println("RP2040 Touch Sensor Ready"); }

void loop() { int touchValue = digitalRead(TOUCH_PIN); // Read sensor value Serial.println(touchValue); // Debug print

if (touchValue == HIGH) { Serial1.println("TOUCH"); // Send command to ESP32C3 Serial.println("Sent: TOUCH"); delay(500); // Debounce }

delay(100); // Small delay to reduce spam }

As commanded in the code, when the touch sensor senses touch, it should indicate that with the serial output of "TOUCH." When I uploaded it, that is what properly came up.

<video width="600" height="345" controls>
  <source src="../../images/week12-networking/touchsensor.mp4" type="video/mp4">
</video>

This was the corresponding code for the ESP32C3 (servo):

``` #include <ESP32Servo.h>

#define SERVO_PIN D5  // GPIO6 for servo control

Servo myServo;
bool triggered = false;
unsigned long lastTriggerTime = 0;

void setup() {
  Serial.begin(115200);        
  Serial1.begin(9600, SERIAL_8N1, 20, 21);  // TX=21, RX=20 for ESP32C3
  myServo.attach(SERVO_PIN);
  myServo.write(0);  // Initial position

  delay(1000);  // Give time for serial to initialize
  Serial.println("ESP32C3 Servo Controller Ready");
}

void loop() {
  if (Serial1.available()) {
    String msg = Serial1.readStringUntil('\n');
    msg.trim();  // Remove any trailing newline or whitespace

    if (msg == "TOUCH") {
      Serial.println("Touch received — spinning servo");
      myServo.write(90);  // Rotate servo
      triggered = true;
      lastTriggerTime = millis();
    }
  }

  // Reset servo after 1 second
  if (triggered && millis() - lastTriggerTime > 1000) {
    myServo.write(0);  // Return to start
    triggered = false;
  }
}

Breadboard and PCB

I then set up my breadboard. I planned on using UART (Universal Asynchronous Receiver-Transmitter) to communicate my two microcontrollers. That would be using the TX (transmit) and RX (receive) pins on the ESP32C3 and RP2040. The two important considerations when wiring were that 1) TX connects to RX 2) there must be shared grounds.

Once I uploaded the code for both microcontrollers, both serial monitors outputted the proper lines and the servo would spin when I touched the touch sensor.

With that, I started designing in KiCAD.

What I made a note of before was that is should be D6 to D6 (TX) and D7 to D7 (RX), which I got confused on for this board. In the ones above, its D6-D7 That's also why, spoiler alert, it didn't work.

Milled and soldered board.

However, when I uploaded the code, it would not work. It took a long time for me to realize that it was because of my UART connections.

So, I redesigned the board

to have the PROPER UART connections.

I milled and soldered that board.

And because the issues were not in the code I was using, it worked once I powered the two microcontrollers!


Group Assignment

The group assignment was to send a message between two projects. We chose to communicate between a touch sensor (my project) on a XIAO ESP32C3 and a servo motor (Amalia's project) on a XIAO ESP32S3. You can find our documentation here.


Individual Contribution

I worked on wiring the breadboard and coding the microcontrollers.

Breadboard

We first got the two microcontrollers connected on a breadboard.

Coding

We first used code to ensure the two microcontrollers could communicate with each other, checked with serial monitor.

For the C3:

void setup() {
  Serial.begin(115200);         // For debug
  Serial1.begin(9600, SERIAL_8N1, 20, 21); // RX=20, TX=21
  delay(1000);
}

void loop() {
  Serial1.println("Hello from C3!");
  Serial.println("Sent message to S3.");
  delay(1000);
}

For the S3:

void setup() {
  Serial.begin(115200);         // For debug
  Serial1.begin(9600, SERIAL_8N1, 44, 43); // RX=44, TX=43
}

void loop() {
  if (Serial1.available()) {
    String msg = Serial1.readStringUntil('\n');
    Serial.print("Received: ");
    Serial.println(msg);
  }
}

This is a video of what it resulted in. In serial monitor, we were able to see the change in output when the sensor sensed touch, but the servo motor did not move. However, it was a step in the right direction.

Amalia suggested we use code that worked for the servo for our individual assignments and have Chat edit it be compatible with UART for networking. Here is a public link to the ChatGPT conversations for troubleshooting the coding.

This approach worked and this was the final code we used for the sender side, the touch sensor on the ESP32C3:

#define TOUCH_PIN D4     // GPIO5 for touch sensor

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, 20, 21);  // TX=21, RX=20 — adjust as needed
  pinMode(TOUCH_PIN, INPUT);
}

void loop() {
  int touchValue = digitalRead(TOUCH_PIN);  // Read sensor value
  Serial.println(touchValue);               // Debug print

  if (touchValue == HIGH) {
    Serial1.println("TOUCH");               // Send command to other ESP
    Serial.println("Sent: TOUCH");
    delay(500);  // Debounce
  }

  delay(100);  // Small delay to reduce spam
}

This was the final code we used for the receiver side, the servo motor on the ESP32S3:

#include <ESP32Servo.h>

#define SERVO_PIN D5  // Set this to your actual servo control pin

Servo myServo;
bool triggered = false;
unsigned long lastTriggerTime = 0;

void setup() {
  Serial.begin(115200);        
  Serial1.begin(9600, SERIAL_8N1, 44, 43);  // RX=44, TX=43
  myServo.attach(SERVO_PIN);
  myServo.write(0);  // Initial position
}

void loop() {
  if (Serial1.available()) {
    String msg = Serial1.readStringUntil('\n');
    msg.trim();  // Remove any trailing newline or whitespace

    if (msg == "TOUCH") {
      Serial.println("Touch received — spinning servo");
      myServo.write(90);  // Rotate servo
      triggered = true;
      lastTriggerTime = millis();
    }
  }

  // Reset servo after 1 second
  if (triggered && millis() - lastTriggerTime > 1000) {
    myServo.write(0);  // Return to start
    triggered = false;
  }
}

This is a video of these two pieces of code working to get the two microcontrollers in communication on the breadboard.


Overview

Overall this week was kind of a struggle because I have never done networking between microcontrollers before. But at least now I know how UART works, the TX and RX pin connections and shared ground. It was also kind of a puzzle figuring out how to design the PCB, given all the requirements to get networking to work. But in the process, I have definitely gotten more comfortable with electronics.


Files

Design:

Print:



Last update: May 31, 2025