WEEK13 Networking and communications
WEEK13 Networking and communications
Group Assignment
send a message between two projects
Individual Assignment
design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s)
For this assignment, we will continue to work on the content related to the Final Project. The flow is as follows:
・Use the board created in Assignment 8
・Change the MCU from XIAO PR2040 to XIAO ESP32C3 (The reason for the change is that the ESP32C3 has Bluetooth functionality)
・Combine the code to obtain acceleration & gyro data used in Assignment 11 and the Arduino IDE UART sample code (File->Examples->BLE->UART)
・Transmit the acceleration and gyro data obtained from the MPU-6050 accelerometer sensor to a Bluetooth-connected smartphone in real-time
Use the board created in Assignment 8
Change the MCU from XIAO PR2040 to XIAO ESP32C3
ESP32C3 Datasheet
The ESP32C3 is a microcontroller developed by Espressif Systems as part of their ESP32 series. It is characterized by its low cost and low power consumption. Key features and specifications include:
Processor: The ESP32C3 is equipped with a 32-bit RISC-V single-core processor, which can operate at up to 160 MHz.
Memory: It supports built-in 384KB SRAM and up to 4MB of external flash memory.
Wireless Capabilities: It offers support for both Wi-Fi (802.11 b/g/n) and Bluetooth Low Energy (BLE) 5.0, making it well-suited for wireless communication applications.
GPIO Pins: It includes numerous General-Purpose Input/Output pins that allow for connectivity with a variety of sensors and actuators.
Security: The device incorporates security features such as AES, SHA, and RSA to enhance device security.
The ESP32C3 is commonly used in applications such as smart home devices, wearables, and IoT nodes, especially in projects requiring Bluetooth connectivity and energy efficiency.
Combine the codes
Combine the code to obtain acceleration & gyro data used in Assignment 11 and the Arduino IDE UART sample code (File->Examples->BLE->UART)
Arudino UART Sample code
/*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
Create a BLE server that, once we receive a connection, will send periodic notifications.
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
The design of creating the BLE server is:
1. Create a BLE Server
2. Create a BLE Service
3. Create a BLE Characteristic on the Service
4. Create a BLE Descriptor on the characteristic
5. Start the service.
6. Start advertising.
In this example rxValue is the data received (only accessible inside that function).
And txValue is the data to be sent, in this example just a byte incremented every second.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("UART Service");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify();
txValue++;
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
Execution Result
This is the execution result of the above code, checked from the eDebugger app connected to the smartphone after running the above code. It can be confirmed that data is being sent from the ESP32C3.
Next, let's send the text "test" from the smartphone side.The received result is displayed in the Serial Monitor.
Combined code
ChatGPT Prompt
Please write a code that sends data generated from the source code to a device connected via UART. Refer to the sample code for UART connections.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <Wire.h>
// UUIDs
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// MPU-6050 Settings
const int MPU_addr = 0x68;
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
// Create the BLE Device
BLEDevice::init("MPU-6050 UART Service");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic for transmitting sensor data
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting for client connection to notify...");
}
void loop() {
if (deviceConnected) {
// Read sensor data
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
AcX = Wire.read() << 8 | Wire.read();
AcY = Wire.read() << 8 | Wire.read();
AcZ = Wire.read() << 8 | Wire.read();
Tmp = Wire.read() << 8 | Wire.read();
GyX = Wire.read() << 8 | Wire.read();
GyY = Wire.read() << 8 | Wire.read();
GyZ = Wire.read() << 8 | Wire.read();
// Format the data for accelerometer
char bufferAcc[64];
snprintf(bufferAcc, sizeof(bufferAcc), "%d, %d, %d, %d", AcX, AcY, AcZ, Tmp);
pTxCharacteristic->setValue((uint8_t*)bufferAcc, strlen(bufferAcc));
pTxCharacteristic->notify();
// Delay to avoid congestion
delay(100);
// Format data for gyroscope
char bufferGyro[64];
snprintf(bufferGyro, sizeof(bufferGyro), "%d, %d, %d", GyX, GyY, GyZ);
pTxCharacteristic->setValue((uint8_t*)bufferGyro, strlen(bufferGyro));
pTxCharacteristic->notify();
delay(333); // Total delay
}
// Handling disconnection
if (!deviceConnected && oldDeviceConnected) {
delay(500);
pServer->startAdvertising();
Serial.println("Restarting advertising");
oldDeviceConnected = deviceConnected;
}
// handling new connection
if (deviceConnected && !oldDeviceConnected) {
oldDeviceConnected = deviceConnected;
}
}
Execution Result
Some adjustments were required to get these results.
Selecting the app on the smartphone side: It was difficult to find a smartphone app that could establish a connection, perhaps because there were few apps compatible with BLE. As a result, we settled on eDebugger.
20 bytes limitation: With the BLE standard, there is a limit to the amount of data that can be stored in one packet (usually around 20 bytes), but the sensor data I was sending exceeded this size, causing the data to be truncated midway. I resolved this issue by splitting the data and sending it over two transmissions.