概要
M5Stamp C3U MateのBLEにてシリアル通信の無線化を行いました。
以前Bluetooth Classicの時にSPPによるシリアル通信を使っていたのですが、
BLEでは使えなくなりました。SPPは手軽で良かったのですが、BLEではなにやら難しくて。
色々探していたところ良い情報がありやっと実現できました。
私の使い勝手から送受信データは'テキスト'、終端文字'\n'としています。
M5Stamp C3U Mate2台を使い片方をServer、もう片方をClientに設定して
相互にBLE通信を行います。ラベル無しがServer、ラベル有りがClient側です。
下記が通信の状況です。COM3:Server、COM4:Clientとなっています。
ServerからのテキストデータがClient側で受信されています。
逆も同じように受信されています。
今回はUSBSerialで行いましたがUART通信も同様に無線化が可能です。
接続が切れるとLEDが赤に点灯します。(Client側の電源を切っています)
環境など
エディタ:VisualStudioCode(PlatformIO IDE)
マイコン:M5Stamp C3U Mate 2台
フレームワーク:Aruduino
コード(Server側)
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <Adafruit_NeoPixel.h>
BLEServer *pServer = NULL;
BLECharacteristic *pTxCharacteristic;
BLECharacteristic *pRxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
bool receivedflg=false;//受信フラグ
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
//serverとcliantでTX,RXは逆転するのに注意
#define SERVICE_UUID "e942c8e4-1a8e-11ef-9262-0242ac120002"
#define CHARACTERISTIC_UUID_RX "e942cbbe-1a8e-11ef-9262-0242ac120002"
#define CHARACTERISTIC_UUID_TX "e942cdee-1a8e-11ef-9262-0242ac120002"
#define SERVER_NAME "esp32ble"
std::string rx_Data;
String rx_Str;//受信文字列
String tx_Str;//送信文字列
//LED設定
#define LED_PIN 2
Adafruit_NeoPixel pixels(1, LED_PIN, NEO_GRB + NEO_KHZ800);
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
// BLE接続でLED青点灯
pixels.setPixelColor(0, pixels.Color(0, 0, 50));
pixels.show();
};
void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
// BLE接続でLED赤点灯
pixels.setPixelColor(0, pixels.Color(50, 0, 0));
pixels.show();
}
};
//受信時コールバック 文字列取得
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
rx_Str=rxValue.c_str(); //受信文字列取得
receivedflg=true; //受信フラグセット
}
};
void setup() {
// 起動時LED緑点灯
pixels.begin();//NeoPixel制御開始
pixels.setPixelColor(0, pixels.Color(0, 50, 0));//LED設定(赤, 緑, 青)
pixels.show();//LED点灯
Serial.begin(115200);
Serial.println("BLE_Server_start");
// Create the BLE Device
BLEDevice::init(SERVER_NAME);
// Create the BLE Server
BLEServer *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) {
// BLEデータ受信時
if(receivedflg==true){
Serial.println("rev:" + rx_Str);
receivedflg=false;
}
// USBシリアルデータ送信
if (Serial.available() > 0) {
String serial_data = Serial.readStringUntil('\n');
tx_Str = serial_data + "\n";//終端文字追加
pTxCharacteristic->setValue(tx_Str.c_str());
pTxCharacteristic->notify();
}
}
// 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;
}
delay(10);
}
コード(Client側)
#include <Arduino.h>
#include "BLEDevice.h"
#include <Adafruit_NeoPixel.h>
#define SERVICE_UUID "e942c8e4-1a8e-11ef-9262-0242ac120002"
#define CHARACTERISTIC_UUID_TX "e942cbbe-1a8e-11ef-9262-0242ac120002"
#define CHARACTERISTIC_UUID_RX "e942cdee-1a8e-11ef-9262-0242ac120002"
#define SERVER_NAME "esp32ble"
static BLEUUID serviceUUID(SERVICE_UUID);
static BLEUUID charUUID_RX(CHARACTERISTIC_UUID_RX);
static BLEUUID charUUID_TX(CHARACTERISTIC_UUID_TX);
static BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristicRX;
static BLERemoteCharacteristic* pRemoteCharacteristicTX;
bool receivedflg=false;//受信フラグ
String rx_Str;//受信文字列
String tx_Str;//送信文字列
//LED設定
#define LED_PIN 2
Adafruit_NeoPixel pixels(1, LED_PIN, NEO_GRB + NEO_KHZ800);
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
rx_Str = (char*)pData;// BLEデータ取得
receivedflg = true;//受信フラグセット
}
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
// BLE接続でLED青点灯
pixels.setPixelColor(0, pixels.Color(0, 0, 50));
pixels.show();
}
void onDisconnect(BLEClient* pclient) {
connected = false;
Serial.println("onDisconnect");
// BLE接続でLED赤点灯
pixels.setPixelColor(0, pixels.Color(50, 0, 0));
pixels.show();
}
};
bool connectToServer(BLEAddress pAddress) {
Serial.print("Forming a connection to ");
Serial.println(pAddress.toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(pAddress);
Serial.println(" - Connected to server");
pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
Serial.print(" - Connected to server :");
Serial.println(serviceUUID.toString().c_str());
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
pRemoteCharacteristicRX = pRemoteService->getCharacteristic(charUUID_RX);
if (pRemoteCharacteristicRX == nullptr) {
Serial.print("Failed to find characteristic RX ID: ");
Serial.println(charUUID_RX.toString().c_str());
pClient->disconnect();
return false;
}
Serial.print(" - Found characteristic RX ID: ");
Serial.println(charUUID_RX.toString().c_str());
// Send用キャラクタリスティックの参照を取得する
pRemoteCharacteristicTX = pRemoteService->getCharacteristic(charUUID_TX);
if (pRemoteCharacteristicTX == nullptr) {
Serial.print("Failed to find characteristic TX ID ");
Serial.println(charUUID_TX.toString().c_str());
pClient->disconnect();
return false;
}
Serial.print(" - Found characteristic TX ID: ");
Serial.println(charUUID_TX.toString().c_str());
// Read the value of the characteristic.
if(pRemoteCharacteristicRX->canRead()) {
std::string value = pRemoteCharacteristicRX->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
if(pRemoteCharacteristicRX->canNotify())
pRemoteCharacteristicRX->registerForNotify(notifyCallback);
Serial.println("End of notify");
return true;
}
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
Serial.println(advertisedDevice.getName().c_str());
if(advertisedDevice.getName()==SERVER_NAME){
Serial.println(advertisedDevice.getAddress().toString().c_str());
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
doConnect = true;
}
}
};
void get_scan(){
BLEScan* pBLEScan = BLEDevice::getScan();
Serial.println("getScan");
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
Serial.println("setAdvertisedDeviceCallbacks");
pBLEScan->setActiveScan(true);
pBLEScan->start(10);
Serial.println("");
Serial.println("End of scan");
}
void setup() {
// 起動時LED緑点灯
pixels.begin();//NeoPixel制御開始
pixels.setPixelColor(0, pixels.Color(0, 50, 0));//LED設定(赤, 緑, 青)
pixels.show();//LED点灯
Serial.begin(115200);
delay(10000);
Serial.println("BLE_Cliant_start");
BLEDevice::init("");
get_scan();
Serial.println("End of setup");
}
void loop() {
if (doConnect == true) {
if (connectToServer(*pServerAddress)) {
Serial.println("We are now connected to the BLE Server.");
connected = true;
} else {
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
connected = false;
}
doConnect = false;
}
if (connected) {
// BLEデータ受信時
if(receivedflg==true){
Serial.println("rev:"+rx_Str);
receivedflg = false;
}
// USBシリアルデータ送信
if (Serial.available() > 0) {
String serial_data = Serial.readStringUntil('\n');
tx_Str = serial_data + "\n";//終端文字追加
pRemoteCharacteristicTX->writeValue(tx_Str.c_str());
}
} else{
Serial.println("Not connected");
//conectできないときにsscanループさせておくため
doConnect = false;
get_scan();
}
delay(10);
}
plathomeio.ini設定
[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
monitor_speed = 115200
build_flags =
-DARDUINO_USB_CDC_ON_BOOT
-DARDUINO_USB_MODE
board_build.partitions = no_ota.csv
lib_deps =
m5stack/M5Unified@^0.1.14
adafruit/Adafruit NeoPixel@^1.12.2
参考サイト