M5Stack과 M5StickC 간의 arduino BLE 통신
1. 개요
M5Stack과 M5StickC를 구입했습니다.
Ultrasonic Ranger라고 하는 초음파로 거리를 측정하는 GROVE 모듈이 수중에 있었으므로, 이것을 우선 연결해 보자고 하는 곳으로부터 처음으로, BLE로 날려 보려고 생각했습니다.
라는 느낌으로 증축해간 것이 됩니다.
이미지도는 이쪽.
2. 환경
3. 사전 준비
참고 사이트 등에 있는, 음성 합성 데이터를 MP3로 다운로드할 수 있는 서비스를 이용해 적당한 음성 MP3 파일을 다운로드해, microSD 카드에 기입해 M5Stack에 세트 해 둡니다.
4. 프로그램
기본적으로 arduino 샘플 프로그램이나 참고하신 코드에서 잘라 붙여 desu.
4.1 BLE 주변 측(M5Stack)
※사전에 arduino IDE로 Partition Scheme을 No OTA로 하고 나서 빌드합니다. 현재 판매되고 있는 것이라면 메모리가 증량되고 있으므로 불필요할지도 모릅니다
//Make sure to install
#include <Arduino.h>
#include <M5Stack.h>
#include "Ultrasonic.h"
#include <WiFi.h>
#include "AudioFileSourceSD.h"
#include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
uint16_t Dvalue = 0;
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
//#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
//#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define SERVICE_UUID "7780" //適当なID(上のような長いUUIDだとうまく認識されなかったので適当に)
#define CHARACTERISTIC_UUID "7781" //適当なID
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
AudioGeneratorMP3 *mp3;
AudioFileSourceSD *file;
AudioOutputI2S *out;
AudioFileSourceID3 *id3;
Ultrasonic ultrasonic(22);
void setup()
{
M5.begin();
WiFi.mode(WIFI_OFF);
Serial.print("");
// Create the BLE Device
BLEDevice::init("M5STACK1G"); //適当な名前
// 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
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
// Create a BLE Descriptor
pCharacteristic->addDescriptor(new BLE2902());
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
BLEDevice::startAdvertising();
// Serial.println("Waiting a client connection to notify...");
}
void PlaySound(int fid){ //予めmicroSDにmp3ファイルを格納しておきます
switch(fid){
case 0: //under 5cm
file = new AudioFileSourceSD("/under5cm-jp-f.mp3");
break;
case 1: //about 10cm
file = new AudioFileSourceSD("/10cm-jp-f.mp3");
break;
case 2: //about 20cm
file = new AudioFileSourceSD("/20cm-jp-f.mp3");
break;
case 3: //about 30cm
file = new AudioFileSourceSD("/30cm-jp-f.mp3");
break;
case 4: //about 50cm
file = new AudioFileSourceSD("/50cm-jp-f.mp3");
break;
case 5: //about 1m
file = new AudioFileSourceSD("/1m-jp-f.mp3");
break;
case 6: //about 1.5m
file = new AudioFileSourceSD("/1_5m-jp-f.mp3");
break;
case 7: //about 2m
file = new AudioFileSourceSD("/2m-jp-f.mp3");
break;
case 8: //about 3m
file = new AudioFileSourceSD("/3m-jp-f.mp3");
break;
case 9: //over 3.5m
file = new AudioFileSourceSD("/over3m-jp-f.mp3");
break;
}
id3 = new AudioFileSourceID3(file);
out = new AudioOutputI2S(0, 1); // Output to builtInDAC
out->SetOutputModeMono(true);
mp3 = new AudioGeneratorMP3();
mp3->begin(id3, out);
while(mp3->isRunning()) {
if (!mp3->loop()) mp3->stop();
}
}
void pressAdisp(int fid,int rng){
M5.Lcd.clear(WHITE);
M5.Lcd.setTextSize(4);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.println("VOICE ON:");
M5.Lcd.println(rng);
}
void loop()
{
M5.update();
long RangeInInches;
long RangeInCentimeters;
int voicenum;
uint8_t buf[2]; //要素数2
RangeInCentimeters = ultrasonic.MeasureInCentimeters(); // two measurements should keep an interval
voicenum=99;
if (M5.BtnA.wasReleased()) { //Aボタン押下時に距離範囲毎にMp3ファイルを再生
if (RangeInCentimeters<5 ) { //距離範囲は適当
voicenum=0;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=5 && RangeInCentimeters<15) {
voicenum=1;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=15 && RangeInCentimeters<25) {
voicenum=2;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=25 && RangeInCentimeters<40) {
voicenum=3;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=40 && RangeInCentimeters<75) {
voicenum=4;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=75 && RangeInCentimeters<125) {
voicenum=5;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=125 && RangeInCentimeters<175) {
voicenum=6;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=175 && RangeInCentimeters<250) {
voicenum=7;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=251 && RangeInCentimeters<350) {
voicenum=8;
pressAdisp(voicenum,RangeInCentimeters);
}else if (RangeInCentimeters>=350) {
voicenum=9;
pressAdisp(voicenum,RangeInCentimeters);
}else{
voicenum=99;
}
PlaySound(voicenum);
}
M5.Lcd.clear(BLACK);
M5.Lcd.setCursor(10, 0);
M5.Lcd.setTextSize(5);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.println("DISTANCE:");
M5.Lcd.setTextColor(RED);
M5.Lcd.println(String(RangeInCentimeters)+ " cm");
Serial.println(RangeInCentimeters);
delay(300);
Dvalue=RangeInCentimeters; //distance value
// BT code
// notify changed value
if (deviceConnected) {
memset(buf,0,sizeof buf);
buf[0]=(uint8_t)(Dvalue & 0xff);
buf[1]=(uint8_t)((Dvalue >>8) & 0xff);
// 数値は0~500少しまであるので、2バイト使います
pCharacteristic->setValue(buf,sizeof buf);
pCharacteristic->notify();
value++;
delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
}
// 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;
}
}
4.2 BLE 중앙측(M5StickC)
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara
*/
#include <M5StickC.h>
#include "BLEDevice.h"
//#include "BLEScan.h"
// The remote service we wish to connect to.
//static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
static BLEUUID serviceUUID("7780");
// The characteristic of the remote service we are interested in.
//static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
static BLEUUID charUUID("7781");
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
uint16_t val; //安直にglobal...
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
val=0;
val=(uint16_t)(pData[1]<<8 | pData[0]); //ペリフェラルから受信した値(2バイト)を数値に変換
Serial.println(val);
}
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected = false;
Serial.println("onDisconnect");
}
};
bool connectToServer() {
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our characteristic");
// Read the value of the characteristic.
if(pRemoteCharacteristic->canRead()) {
//サンプルだと下の行を実行するタイミングでリブートかかるのでコメント化。
//notifyCallbackのほうでCharacteristicから取得するように変更
//std::string value = pRemoteCharacteristic->readValue();
//Serial.print("The characteristic value was: ");
//Serial.println(value.c_str());
}
if(pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback);
connected = true;
}
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
// if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
void setup() {
M5.begin();
Serial.begin(1500000);
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
// pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
} // End of setup.
// This is the Arduino main loop function.
void loop() {
M5.Lcd.fillScreen(BLACK); //この辺の表示は接続確認後、にしたほうがいいかも
M5.Lcd.setCursor(0, 10);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.println("DSTNC:"); //distanceの略w 画面小さいので
M5.Lcd.setTextSize(4);
M5.Lcd.setTextColor(RED);
M5.Lcd.println(val);
M5.Lcd.setTextColor(GREEN);
M5.Lcd.println("cm");
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
if (connectToServer()) {
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
}
doConnect = false;
}
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
// with the current time since boot.
if (connected) {
/*
String newValue = "Time since boot: " + String(millis()/1000);
Serial.println("Setting new characteristic value to \"" + newValue + "\"");
// Set the characteristic's value to be the array of bytes that is actually a string.
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
*/
}else if(doScan){
BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
}
delay(1000); // Delay a second between loops.
} // End of loop
5. 기타
6. 참고로 한 페이지
M5Stack에서 BLE 사용
htps : // m / nsawa / ms / 2 a fd4 꺾어 9c10 a f87d0133
BLE 환경 센서·게이트웨이(ESP32편)
htps : // 아메다였다. 이오/사 mpぇs/m5s타운 ck/bぇ_gw/
M5Stack으로 BLE 환경 센서 단말기 만들기
htps : // 아무도였다. 이오/사 mp㎇s/m5s ck/m5s ck_bぇ_전자 r/
M5Stack으로 SD 카드에서 mp3를 재생해보세요
htps : // 코 m / k 탄사이 / ms / f0096495 에 2 또는 7 38 에 b7
WEB 편리 노트(음성 MP3 생성)
htps : //에서. c 만. jp/오테ぇr/ゔぉ이세/
이상입니다. 고마워요.
Reference
이 문제에 관하여(M5Stack과 M5StickC 간의 arduino BLE 통신), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/mirawerra/items/d3d514cbdb3c2f4c20fb텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)