慕容雪花

  • 2024-07-09
  • 回复了主题帖: 颁奖:嵌入式工程师AI挑战营(初阶),致敬敢于将边缘AI收入统治领域的你们

    感谢诸位大佬的无私分享!

  • 2024-06-20
  • 回复了主题帖: 以旧换新!100套TI MSPM0整装待发,升级你的装备!第一波替换名单来啦

    感谢论坛和TI提供的土豪活动!!

  • 2024-06-13
  • 回复了主题帖: #AI挑战营终点站#将模型部署到RV1106中通过摄像头采集进行手写数字识别

    谢谢谢谢,感谢分享!受益匪浅

  • 2024-06-12
  • 回复了主题帖: 【AI挑战营终点站】应用落地:部署手写数字识别应用到幸狐RV1106开发板

    本来打算寄回板卡的,后面在管理员的鼓励下决定重新开始,也参考了大佬们无私分享的帖子,这是第一次体验使用硬件板卡来进行识别,后面要好好消化一下。   #AI挑战营终点站# 部署手写数字识别应用到幸狐RV1106开发板 https://bbs.eeworld.com.cn/thread-1284698-1-1.html

  • 发表了主题帖: #AI挑战营终点站# 部署手写数字识别应用到幸狐RV1106开发板

    本帖最后由 慕容雪花 于 2024-6-12 19:16 编辑 #AI挑战营第一站#基于PyTorch,在PC上完成MNIST手写数字识别模型训练 https://bbs.eeworld.com.cn/thread-1278408-1-1.html #AI挑战营第二站# onnx转rknn https://bbs.eeworld.com.cn/thread-1284692-1-1.html 首先参考官方Wiki进行SDK的部署:https://wiki.luckfox.com/zh/Luckfox-Pico/Luckfox-Pico-SDK  sudo apt update sudo apt-get install -y git ssh make gcc gcc-multilib g++-multilib module-assistant expect g++ gawk texinfo libssl-dev bison flex fakeroot cmake unzip gperf autoconf device-tree-compiler libncurses5-dev pkg-config bc python-is-python3 passwd openssl openssh-server openssh-client vim file cpio rsync 遇到了如下错误:   上面的错误是在WSL2 Ubuntu里面遇到的,折腾一段时间后参考 (https://blog.csdn.net/hhhlizhao/article/details/127176989)。 接下来就是在Ubuntu虚拟机里面接着部署SDK了。 git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git 安装交叉编译工具链: cd ./luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/ source env_install_toolchain.sh 设置环境变量: export LUCKFOX_SDK_PATH=/home/你的用户名/Luckfox/luckfox-pico 接下来直接克隆论坛这位大佬的仓库抄作业 https://bbs.eeworld.com.cn/thread-1282745-1-1.html 克隆仓库  git clone https://gitee.com/luyism/luckfox_rtsp_mnist 接下来根据readme进行编译:   通过SSH把文件上传到开发板     纸上写数字,识别验证: 电脑上写数字验证:   [localvideo]4eed3c4ecd2b73c684fb6d6cd108d4c9[/localvideo]       附件:      

  • 发表了主题帖: #AI挑战营第二站# onnx转rknn

    本帖最后由 慕容雪花 于 2024-6-12 13:06 编辑 #AI挑战营第一站# 基于PyTorch,在PC上完成MNIST手写数字识别模型训练 https://bbs.eeworld.com.cn/thread-1278408-1-1.html    为了使用 RKNPU,用户需要首先在计算机上运行 RKNN-Toolkit2 工具,将训练好的模型转换为 RKNN 格式模型。RKNN-Toolkit2 工具在 PC 平台上提供 C 或 Python 接口,简化模型的部署和运行。用户可以通过该工具轻松完成以下功能:模型转换、量化、推理、性能和内存评估、量化精度分析以及模型加密。RKNN 软件栈可以帮助用户快速的将 AI 模型部署到 Rockchip 芯片。整体的框架如下     RV1106 需要使用rknn-toolkit2: git clone https://github.com/airockchip/rknn-toolkit2 接下来根据Python版本选择合适的whl: pip install ./rknn-toolkit2/rknn-toolkit2/packages/rknn_toolkit2-2.0.0b0+9bab5682-cp38-cp38-linux_x86_64.whl     接下来验证rknn toolkit是否安装成功:     之后可以通过Python脚本来进行模型转换,参考大佬:https://bbs.eeworld.com.cn/thread-1280156-1-1.html from rknn.api import RKNN # Create RKNN object rknn = RKNN(verbose=True) # pre-process config print('--> config model') rknn.config(target_platform='rv1106', mean_values=[[28]], std_values=[[28]]) print('done') # Load model print('--> Loading model') ret = rknn.load_onnx(model='./mnist_101_model.onnx') if ret != 0: print('Load model failed!') exit(ret) print('done') rknn.build(do_quantization=True, dataset='./data.txt') # 构建RKNN模型,可选参数量化 if ret != 0: print('Build model failed!') exit(ret) print('done') ret = rknn.export_rknn('./mnist.rknn') # 导出RKNN模型文件 if ret != 0: print('Export rknn model failed!') exit(ret) print('done') # 释放 RKNN 对象 rknn.release() 有个步骤是新建一个data.txt,指向其中一个测试数据:   最后运行脚本:     附件:  

  • 回复了主题帖: 【AI挑战营第二站】算法工程化部署打包成SDK

    本帖最后由 慕容雪花 于 2024-6-12 11:48 编辑 ONNX(Open Neural Network Exchange)是一种开放的神经网络交换格式,它可以在不同的深度学习框架之间进行模型转换和共享。   RKNN(Rockchip Neural Network)是一种专为Rockchip系列芯片设计的神经网络推理引擎,它提供了高效的神经网络推理能力。   链接: #AI挑战营第二站# onnx转rknn https://bbs.eeworld.com.cn/thread-1284692-1-1.html

  • 2024-05-19
  • 回复了主题帖: 参会赢京东卡:2024上海国际嵌入式展报名通道开启!

    eeworld竟然有站位,牛!

  • 2024-05-09
  • 回复了主题帖: 入围名单公布:嵌入式工程师AI挑战营(初阶),获RV1106 Linux 板+摄像头的名单

    个人信息已确认,领取板卡,可继续完成&分享挑战营第二站和第三站任务

  • 2024-05-06
  • 发表了主题帖: 【FireBeetle 2 ESP32 C6开发板】-5- ESP32C6 BLE主从一体

    本帖最后由 慕容雪花 于 2024-5-6 13:12 编辑 往期测评: 【FireBeetle 2 ESP32 C6开发板】-1- 开发环境搭建 https://bbs.eeworld.com.cn/thread-1279979-1-1.html 【FireBeetle 2 ESP32 C6开发板】-2- BLE server创建 https://bbs.eeworld.com.cn/thread-1280292-1-1.html 【FireBeetle 2 ESP32 C6开发板】-3- C6获取小米温湿度计2数据 https://bbs.eeworld.com.cn/thread-1280293-1-1.html 【FireBeetle 2 ESP32 C6开发板】-4- 关于读取温湿度Characteristic值的一些问题记录 https://bbs.eeworld.com.cn/thread-1280318-1-1.html   根据测评计划,C6获取到的温湿度数据要显示在屏幕上。考虑到自己焊接技术太烂,手上刚好有之前使用的FireBeetle 2 ESP32-E并且连接了OLED。于是想把C6同时作为BLE的客户端与服务器,FireBeetle 2 ESP32-E作为客户端,然后把获取到的BLE数据显示在OLED屏幕上。   主要的框图:     C6同时实现BLE CLIENT与BLE SERVER的代码: /* 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. */ /* 该示例演示了蓝牙数据透传,烧录代码,打开串口监视器,打开手机的BLE调试助手 * 1.即可看见ESP32发送的数据--见APP使用图 * 2.通过BLE调试助手的输入框可向ESP32发送数据--见APP使用图 * 该示例由BLE_uart示例更改而来 */ #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> /* 该部分定义了C6作为BLE Server的一些定义 */ BLEServer *pServer = NULL; BLECharacteristic * pTxCharacteristic; bool otherClientConnectedToServerC6 = 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" uint8_t TempHumidData[5] = {0}; /* 该部分定义了C6作为BLE Client来获取小米温湿度计2的传感器数据 */ static String XiaomiDeviceName = "LYWSD03MMC"; static BLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"); // The characteristic of the remote service we are interested in. // In this case, it's Xiaomi Temp and Humidity Sensor Version 2. static BLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"); static boolean doConnect = false; static boolean connected = false; static boolean doScan = true; static BLERemoteCharacteristic* pRemoteCharacteristic; static BLEAdvertisedDevice* myDevice; static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); Serial.print(" of data length "); Serial.println(length); for(uint8_t i = 0; i < length; i++){ Serial.println("pData[" + String(i) + "] = " + String(pData[i])); } uint16_t TempVal = pData[1]*256 + pData[0]; Serial.println("Temperature is: "+ String(TempVal/100) + "." + String(TempVal%100) + " degree"); float temperature = TempVal*1.0/100; uint8_t HumidityVal = pData[2]; Serial.println("Humidity is: " + String(pData[2]) + "% "); uint16_t BatteryVal = pData[4]*256 + pData[3]; Serial.println("Battery Voltage is: "+ String(BatteryVal/100) + "." + String(BatteryVal%100) + " mV"); Serial.println(); char buffer[12]; snprintf(buffer, sizeof(buffer), "%.1f C, %d%%", temperature, HumidityVal); Serial.println(buffer); /****************数据发送部分*************/ /****************************************/ if (otherClientConnectedToServerC6) { //如果有蓝牙连接,就发送数据 //pTxCharacteristic->setValue("Hello"); //发送字符串 pTxCharacteristic->setValue(buffer); pTxCharacteristic->notify(); delay(10); // bluetooth stack will go into congestion, if too many packets are sent } } 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"); pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise) // 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()) { String value = pRemoteCharacteristic->readValue(); uint8_t* test = pRemoteCharacteristic->readRawData(); uint8_t i; uint8_t TempHumidData[5]={0}; for(i = 0; i < 5; i++){ if(test != nullptr){ Serial.print("The characteristic value using readRawData was: "); Serial.println(*test); TempHumidData[i] = *test; }else{ Serial.println("pRemoteCharacteristic->readRawData() returns NULL PTR"); } test++; } static uint16_t Test_TempVal = TempHumidData[1]*256 + TempHumidData[0]; Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree"); static uint8_t Test_HumidityVal = TempHumidData[2]; Serial.println("Test Humidity is: " + String(TempHumidData[2]) + "% "); static uint16_t Test_BatteryVal = TempHumidData[4]*256 + TempHumidData[3]; Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV"); } if(pRemoteCharacteristic->canNotify()) pRemoteCharacteristic->registerForNotify(notifyCallback); connected = true; return 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.println("*-------------------------------------------------------------------*"); 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. Serial.println(advertisedDevice.getServiceUUID().toString().c_str()); Serial.println(advertisedDevice.getName().c_str()); if(0 == advertisedDevice.getName().compareTo(XiaomiDeviceName)){ Serial.println("Great, Found " + advertisedDevice.getName()); Serial.println("advertisedDevice.getServiceUUIDCount() = " + String(advertisedDevice.getServiceUUIDCount())); BLEDevice::getScan()->stop(); myDevice = new BLEAdvertisedDevice(advertisedDevice); doConnect = true; doScan = true; } } // onResult }; // MyAdvertisedDeviceCallbacks /* 该部分定义了C6作为BLE Server把获取到的小米温湿度计2的传感器数据发给另外一块ESP开发板 */ //蓝牙连接/断开处理。当有连接/断开事件发生时自动触发 class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { //当蓝牙连接时会执行该函数 Serial.println("蓝牙已连接"); otherClientConnectedToServerC6 = true; }; void onDisconnect(BLEServer* pServer) { //当蓝牙断开连接时会执行该函数 Serial.println("蓝牙已断开"); otherClientConnectedToServerC6 = false; delay(500); // give the bluetooth stack the chance to get things ready pServer->startAdvertising(); // restart advertising } }; /****************数据接收部分*************/ /****************************************/ //蓝牙接收数据处理。当收到数据时自动触发 class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = (pCharacteristic->getValue()).c_str();//接收数据,并赋给rxValue //if(rxValue == "ON"){Serial.println("开灯");} //判断接收的字符是否为"ON" 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); 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->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); pBLEScan->start(5, false); //Start BLE Server BLEServerBegin(); //初始化蓝牙 } void loop() { // 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-Xiaomi Temp-Humid Device."); } 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) { }else if(doScan){ BLEDevice::getScan()->start(5); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino } /****************************************/ /****************************************/ delay(1000); // Delay a second between loops. } void BLEServerBegin(){ // Create the BLE Device BLEDevice::init(/*BLE名称*/"BLE ROUTE 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(); //pService->stop(); // Start advertising pServer->getAdvertising()->addServiceUUID(SERVICE_UUID); pServer->getAdvertising()->start(); Serial.println("Waiting a client connection to notify..."); }   FireBeetle 2 ESP32-E实现BLE客户端与OLED相关代码: /** * A BLE client example that is rich in capabilities. * There is a lot new capabilities implemented. * author unknown * updated by chegewara * 2024/5/2 update by sy: using readRawData 5 times to get the real temperature and humidity value. works. */ #include "BLEDevice.h" //#include "BLEScan.h" // The remote service of Xiaomi Temp and Humidity Sensor we wish to connect to. static BLEUUID serviceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); // The characteristic of the remote service we are interested in. // In this case, it's Xiaomi Temp and Humidity Sensor Version 2. static BLEUUID charUUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"); static boolean doConnect = false; static boolean connected = false; static boolean doScan = true; static BLERemoteCharacteristic* pRemoteCharacteristic; static BLEAdvertisedDevice* myDevice; /*oled related*/ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // The pins for I2C are defined by the Wire-library. // On an arduino UNO: A4(SDA), A5(SCL) // On an arduino MEGA 2560: 20(SDA), 21(SCL) // On an arduino LEONARDO: 2(SDA), 3(SCL), ... #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32. SensorYoung: 2024/1/29 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); #define NUMFLAKES 10 // Number of snowflakes in the animation example #define LOGO_HEIGHT 16 #define LOGO_WIDTH 16 static const unsigned char PROGMEM logo_bmp[] = { 0b00000000, 0b11000000, 0b00000001, 0b11000000, 0b00000001, 0b11000000, 0b00000011, 0b11100000, 0b11110011, 0b11100000, 0b11111110, 0b11111000, 0b01111110, 0b11111111, 0b00110011, 0b10011111, 0b00011111, 0b11111100, 0b00001101, 0b01110000, 0b00011011, 0b10100000, 0b00111111, 0b11100000, 0b00111111, 0b11110000, 0b01111100, 0b11110000, 0b01110000, 0b01110000, 0b00000000, 0b00110000 }; static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); Serial.print(" of data length "); Serial.println(length); Serial.write(pData, length); Serial.println(); display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); // Start at top-left corner display.println(F("Temperature,Humidity")); //display.display(); display.println(F(pData)); //display.display(); display.display(); } 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"); pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise) // 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()) { String value = pRemoteCharacteristic->readValue(); Serial.print("FireBeetle ESP32-E read The characteristic value was: "); Serial.println(value.c_str()); } if(pRemoteCharacteristic->canNotify()) pRemoteCharacteristic->registerForNotify(notifyCallback); connected = true; return 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.println("*-------------------------------------------------------------------*"); 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. Serial.println(advertisedDevice.getServiceUUID().toString().c_str()); Serial.println(advertisedDevice.getName().c_str()); // if(0 == advertisedDevice.getName().compareTo(XiaomiDeviceName)){ // Serial.println("Great, Found " + advertisedDevice.getName()); // Serial.println("advertisedDevice.getServiceUUIDCount() = " + String(advertisedDevice.getServiceUUIDCount())); // BLEDevice::getScan()->stop(); // myDevice = new BLEAdvertisedDevice(advertisedDevice); // doConnect = true; // doScan = true; // } if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) { if(advertisedDevice.haveName() && advertisedDevice.getName().c_str()) BLEDevice::getScan()->stop(); myDevice = new BLEAdvertisedDevice(advertisedDevice); doConnect = true; doScan = true; } // Found our server } // onResult }; // MyAdvertisedDeviceCallbacks void setup() { Serial.begin(115200); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever }else{ Serial.println("SSD1306 Init Successfully"); } // Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(2000); // Pause for 2 seconds 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->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); pBLEScan->start(5, false); } // End of setup. // This is the Arduino main loop function. void loop() { // 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("Time since boot: " + 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(5); // this is just example 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   ESP32-E与C6的串口日志:   实物照片     总结: 非常感谢论坛提供的体验c6的机会,本次的体验主要围绕在BLE方面,从熟悉基础知识,到搭建简单的Server,client,到获取小米温湿度计2的数据,最后在c6上部署了BLE主从一体固件,从而实现了把采集到的温湿度数据进行二次转发给别的设备,并最终在oled屏幕上显示了正确结果。 在此也感谢论坛朋友的热情帮助,一起进步!

  • 2024-05-05
  • 回复了主题帖: 【FireBeetle 2 ESP32 C6】AP节点测试与WIFI配网

    之前搞wifi配网,好像区分了一下2.4g wifi还有什么wifi 5G?

  • 2024-05-04
  • 回复了主题帖: 【FireBeetle 2 ESP32 C6开发板】-2- BLE server创建

    补充一下BLE CLIENT的创建:   C6作为BLE central设备,通过扫描来发现提供服务的设备。nrf52 usb dongle作为BLE  peripheral设备,通过广播,把自己提供温湿度数据的服务给广播出去。 C6作为central设备的代码: #include "BLEDevice.h" // The remote service of Xiaomi Temp and Humidity Sensor we wish to connect to. static BLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a8"); // The characteristic of the remote service we are interested in. // In this case, it's Xiaomi Temp and Humidity Sensor Version 2. static BLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a8"); static boolean doConnect = false; static boolean connected = false; static boolean doScan = true; static BLERemoteCharacteristic* pRemoteCharacteristic; static BLEAdvertisedDevice* myDevice; static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); Serial.print(" of data length "); Serial.println(length); for(uint8_t i = 0; i < length; i++){ Serial.println("pData[" + String(i) + "] = " + String(pData[i])); } uint16_t TempVal = pData[1]*256 + pData[0]; Serial.println("Temperature is: "+ String(TempVal/100) + "." + String(TempVal%100) + " degree"); uint8_t HumidityVal = pData[2]; Serial.println("Humidity is: " + String(pData[2]) + "% "); uint16_t BatteryVal = pData[4]*256 + pData[3]; Serial.println("Battery Voltage is: "+ String(BatteryVal/100) + "." + String(BatteryVal%100) + " mV"); Serial.println(); } 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"); pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise) // 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()) { String value = pRemoteCharacteristic->readValue(); uint8_t* test = pRemoteCharacteristic->readRawData(); uint8_t i; uint8_t test_temp_val[5]={0}; for(i = 0; i < 5; i++){ if(test != nullptr){ Serial.print("The characteristic value using readRawData was: "); Serial.println(*test); test_temp_val[i] = *test; }else{ Serial.println("pRemoteCharacteristic->readRawData() returns NULL PTR"); } test++; } static uint16_t Test_TempVal = test_temp_val[1]*256 + test_temp_val[0]; Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree"); static uint8_t Test_HumidityVal = test_temp_val[2]; Serial.println("Test Humidity is: " + String(test_temp_val[2]) + "% "); static uint16_t Test_BatteryVal = test_temp_val[4]*256 + test_temp_val[3]; Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV"); } if(pRemoteCharacteristic->canNotify()) pRemoteCharacteristic->registerForNotify(notifyCallback); connected = true; return 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.println("*-------------------------------------------------------------------*"); 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. Serial.println(advertisedDevice.getServiceUUID().toString().c_str()); Serial.println(advertisedDevice.getName().c_str()); if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) { BLEDevice::getScan()->stop(); myDevice = new BLEAdvertisedDevice(advertisedDevice); doConnect = true; doScan = true; } // Found our server } // onResult }; // MyAdvertisedDeviceCallbacks void setup() { Serial.begin(115200); 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->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); pBLEScan->start(5, false); } // End of setup. // This is the Arduino main loop function. void loop() { // 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("Time since boot: " + 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(5); // this is just example 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   nrf52 usb dongle作为BLE 外设的配置: 首先点击SERVER SETUP,添加SERVICE   添加一个Characteristic:     使能了notify,需要添加CCCD即UUID为2902的Attribute。     点击“Apply to device”,重启usb dongle:   回到首页,点击小齿轮,选择“Advertising setup”, 注意提供温湿度数据的服务的UUID已经被加入广播数据。   点击“Start advertising”     串口输出:    

  • 2024-05-03
  • 回复了主题帖: 【FireBeetle 2 ESP32 C6开发板】-4- 关于读取温湿度Characteristic值的一些问题记录

    在此贴,请教一下Arduino大佬, https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/, 查看了里面的解释,还是不太理解m_value = String((char*) evtParam->read.value, evtParam->read.value_len); 比如,小米温湿度计2的返回数据是5个byte,那么m_value = String((char *) 数据地址,5); 这个m_value就是使用readValue()直接读取Characteristic值的时候返回值。 // ESP_GATTC_READ_CHAR_EVT // This event indicates that the server has responded to the read request. // // read: // - esp_gatt_status_t status // - uint16_t conn_id // - uint16_t handle // - uint8_t* value // - uint16_t value_len case ESP_GATTC_READ_CHAR_EVT: { // If this event is not for us, then nothing further to do. if (evtParam->read.handle != getHandle()) break; // At this point, we have determined that the event is for us, so now we save the value // and unlock the semaphore to ensure that the requestor of the data can continue. if (evtParam->read.status == ESP_GATT_OK) { m_value = String((char*) evtParam->read.value, evtParam->read.value_len); if(m_rawData != nullptr) free(m_rawData); m_rawData = (uint8_t*) calloc(evtParam->read.value_len, sizeof(uint8_t)); memcpy(m_rawData, evtParam->read.value, evtParam->read.value_len); } else { m_value = ""; } m_semaphoreReadCharEvt.give(); break; } // ESP_GATTC_READ_CHAR_EVT

  • 2024-05-02
  • 回复了主题帖: 【FireBeetle 2 ESP32 C6开发板】-4- 关于读取温湿度Characteristic值的一些问题记录

    秦天qintian0303 发表于 2024-5-2 19:49 每次读取都要先使用readValue(),再使用readRawData()吗?  我试着注释掉readValue(), 只调用readRawData()然后设备会不停的重启。

  • 回复了主题帖: 【FireBeetle 2 ESP32 C6开发板】-4- 关于读取温湿度Characteristic值的一些问题记录

    BLERemoteCharacteristic::readValue() does not return the correct value #20 https://github.com/h2zero/NimBLE-Arduino/issues/20

  • 发表了主题帖: 【FireBeetle 2 ESP32 C6开发板】-4- 关于读取温湿度Characteristic值的一些问题记录

    当前主动读取温湿度计2的Characteristic使用的代码如下: // 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()) { #if 1 String value = pRemoteCharacteristic->readValue(); //Serial.println("The characteristic value using readValue was: " + value+ " Length of value is: " + String(value.length())); #endif #if 1 uint8_t* test = pRemoteCharacteristic->readRawData(); uint8_t i; uint8_t test_temp_val[5]={0}; for(i = 0; i < 5; i++){ if(test != nullptr){ Serial.print("The characteristic value using readRawData was: "); Serial.println(*test); test_temp_val[i] = *test; }else{ Serial.println("pRemoteCharacteristic->readRawData() returns NULL PTR"); } test++; } static uint16_t Test_TempVal = test_temp_val[1]*256 + test_temp_val[0]; Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree"); static uint8_t Test_HumidityVal = test_temp_val[2]; Serial.println("Test Humidity is: " + String(test_temp_val[2]) + "% "); static uint16_t Test_BatteryVal = test_temp_val[4]*256 + test_temp_val[3]; Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV"); #endif 可以看到需要先调用: String value = pRemoteCharacteristic->readValue(); 然后再调用: uint8_t* test = pRemoteCharacteristic->readRawData(); 实验发现,如果不调用上面的readValue()系统就会Reset。接下来从底层代码来看一下readValue()的代码实现。 /** * [url=home.php?mod=space&uid=159083]@brief[/url] Read the value of the remote characteristic. * [url=home.php?mod=space&uid=784970]@return[/url] The value of the remote characteristic. */ String BLERemoteCharacteristic::readValue() { log_v(">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle()); // Check to see that we are connected. if (!getRemoteService()->getClient()->isConnected()) { log_e("Disconnected"); return String(); } m_semaphoreReadCharEvt.take("readValue"); // Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. // This is an asynchronous request which means that we must block waiting for the response // to become available. esp_err_t errRc = ::esp_ble_gattc_read_char( m_pRemoteService->getClient()->getGattcIf(), m_pRemoteService->getClient()->getConnId(), // The connection ID to the BLE server getHandle(), // The handle of this characteristic m_auth ); // Security if (errRc != ESP_OK) { log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return ""; } // Block waiting for the event that indicates that the read has completed. When it has, the String found // in m_value will contain our data. m_semaphoreReadCharEvt.wait("readValue"); log_v("<< readValue(): length: %d", m_value.length()); return m_value; } // readValue 可以看到,调用readValue()后,会通知底层的蓝牙协议栈去等待读取事件EVT是否完成。接下来读取事件完成后,接着处理ESP_GATTC_READ_CHAR_EVT: /** * @brief Handle GATT Client events. * When an event arrives for a GATT client we give this characteristic the opportunity to * take a look at it to see if there is interest in it. * @param [in] event The type of event. * @param [in] gattc_if The interface on which the event was received. * @param [in] evtParam Payload data for the event. * @returns N/A */ void BLERemoteCharacteristic::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *evtParam) { switch (event) { // ESP_GATTC_NOTIFY_EVT // // notify // - uint16_t conn_id - The connection identifier of the server. // - esp_bd_addr_t remote_bda - The device address of the BLE server. // - uint16_t handle - The handle of the characteristic for which the event is being received. // - uint16_t value_len - The length of the received data. // - uint8_t* value - The received data. // - bool is_notify - True if this is a notify, false if it is an indicate. // // We have received a notification event which means that the server wishes us to know about a notification // piece of data. What we must now do is find the characteristic with the associated handle and then // invoke its notification callback (if it has one). case ESP_GATTC_NOTIFY_EVT: { if (evtParam->notify.handle != getHandle()) { break; } if (m_notifyCallback != nullptr) { log_d("Invoking callback for notification on characteristic %s", toString().c_str()); m_notifyCallback(this, evtParam->notify.value, evtParam->notify.value_len, evtParam->notify.is_notify); } // End we have a callback function ... break; } // ESP_GATTC_NOTIFY_EVT // ESP_GATTC_READ_CHAR_EVT // This event indicates that the server has responded to the read request. // // read: // - esp_gatt_status_t status // - uint16_t conn_id // - uint16_t handle // - uint8_t* value // - uint16_t value_len case ESP_GATTC_READ_CHAR_EVT: { // If this event is not for us, then nothing further to do. if (evtParam->read.handle != getHandle()) { break; } // At this point, we have determined that the event is for us, so now we save the value // and unlock the semaphore to ensure that the requestor of the data can continue. if (evtParam->read.status == ESP_GATT_OK) { m_value = String((char *)evtParam->read.value, evtParam->read.value_len); if (m_rawData != nullptr) { free(m_rawData); } m_rawData = (uint8_t *)calloc(evtParam->read.value_len, sizeof(uint8_t)); memcpy(m_rawData, evtParam->read.value, evtParam->read.value_len); } else { m_value = ""; } m_semaphoreReadCharEvt.give(); break; } // ESP_GATTC_READ_CHAR_EVT // ESP_GATTC_REG_FOR_NOTIFY_EVT // // reg_for_notify: // - esp_gatt_status_t status // - uint16_t handle case ESP_GATTC_REG_FOR_NOTIFY_EVT: { // If the request is not for this BLERemoteCharacteristic then move on to the next. if (evtParam->reg_for_notify.handle != getHandle()) { break; } // We have processed the notify registration and can unlock the semaphore. m_semaphoreRegForNotifyEvt.give(); break; } // ESP_GATTC_REG_FOR_NOTIFY_EVT // ESP_GATTC_UNREG_FOR_NOTIFY_EVT // // unreg_for_notify: // - esp_gatt_status_t status // - uint16_t handle case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { if (evtParam->unreg_for_notify.handle != getHandle()) { break; } // We have processed the notify un-registration and can unlock the semaphore. m_semaphoreRegForNotifyEvt.give(); break; } // ESP_GATTC_UNREG_FOR_NOTIFY_EVT: // ESP_GATTC_WRITE_CHAR_EVT // // write: // - esp_gatt_status_t status // - uint16_t conn_id // - uint16_t handle case ESP_GATTC_WRITE_CHAR_EVT: { // Determine if this event is for us and, if not, pass onwards. if (evtParam->write.handle != getHandle()) { break; } // There is nothing further we need to do here. This is merely an indication // that the write has completed and we can unlock the caller. m_semaphoreWriteCharEvt.give(); break; } // ESP_GATTC_WRITE_CHAR_EVT case ESP_GATTC_READ_DESCR_EVT: case ESP_GATTC_WRITE_DESCR_EVT: for (auto &myPair : m_descriptorMap) { myPair.second->gattClientEventHandler(event, gattc_if, evtParam); } break; case ESP_GATTC_DISCONNECT_EVT: // Cleanup semaphores to avoid deadlocks. m_semaphoreReadCharEvt.give(1); m_semaphoreWriteCharEvt.give(1); break; default: break; } // End switch }; // gattClientEventHandler 接着调用readRawValue(),返回5 Bytes数据的首字节指针。 /** * @brief Read raw data from remote characteristic as hex bytes * @return return pointer data read */ uint8_t *BLERemoteCharacteristic::readRawData() { return m_rawData; } 以上可见,对于想读取小米温湿度计2的温湿度数据,有两种方式: 方式1:直接读取,先使用readValue(),再使用readRawData() 方式2:通过notify事件来处理   演示视频: [localvideo]ba198d9520a58be8bf1056f4ca78b2fb[/localvideo]   完整代码:

  • 回复了主题帖: 【FireBeetle 2 ESP32 C6开发板】-3- C6获取小米温湿度计2数据

    lugl4313820 发表于 2024-5-1 22:49 C6启动后,会开始扫描周围的BLE设备,此时进行一个判断,设备名称是否为XiaomiDeviceName = "LYWSD03MMC ... 可以的大佬,是我太菜了。我尝试扫描周围设备,想直接根据SERVICE UUID来锁定小米温湿度度计2,但可能小米设备的广播报文里面并没有包含serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6")。所以才直接根据设备名称来锁定小米设备。

  • 2024-05-01
  • 发表了主题帖: 【FireBeetle 2 ESP32 C6开发板】-3- C6获取小米温湿度计2数据

    本帖最后由 慕容雪花 于 2024-5-2 12:36 编辑 小米温湿度计2 是从设备,同时也是BLE SERVER,部署了多个sevice,其中serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6")里面的charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6")就是温湿度数据。   esp32c6是主设备,同时也是BLE CLIENT,通过BLE的协议来访问Server上的Characteristic,从而获取到温湿度数据。 C6启动后,会开始扫描周围的BLE设备,此时进行一个判断,设备名称是否为XiaomiDeviceName = "LYWSD03MMC" /** * Called for each advertising BLE server. */ void onResult(BLEAdvertisedDevice advertisedDevice) { Serial.println("*-------------------------------------------------------------------*"); 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. Serial.println(advertisedDevice.getServiceUUID().toString().c_str()); Serial.println(advertisedDevice.getName().c_str()); if(0 == advertisedDevice.getName().compareTo(XiaomiDeviceName)){ Serial.println("Great, Found " + advertisedDevice.getName()); Serial.println("advertisedDevice.getServiceUUIDCount() = " + String(advertisedDevice.getServiceUUIDCount())); BLEDevice::getScan()->stop(); myDevice = new BLEAdvertisedDevice(advertisedDevice); doConnect = true; doScan = true; } } // onResult 找到小米设备后,进行连接: 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"); pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise) // 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()) { String value = pRemoteCharacteristic->readValue(); Serial.print("The characteristic value was: "); Serial.println(value.c_str()); } if(pRemoteCharacteristic->canNotify()) pRemoteCharacteristic->registerForNotify(notifyCallback); connected = true; return true; } 从小米设备获取到数据,共有5个字节。 static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); Serial.print(" of data length "); Serial.println(length); uint16_t TempVal = pData[1]*256 + pData[0]; Serial.println("Temperature is: "+ String(TempVal/100) + "." + String(TempVal%100) + " degree"); uint8_t HumidityVal = pData[2]; Serial.println("Humidity is: " + String(pData[2]) + "% "); uint16_t BatteryVal = pData[4]*256 + pData[3]; Serial.println("Battery Voltage is: "+ String(BatteryVal/100) + "." + String(BatteryVal%100) + " mV"); Serial.println(); } 注意数据为小端模式存储。      ------------------------------------------------------------------------------------------------------------------- 5.2日更新: 上文中BLE SERVER notify上来的数据是没有问题的,温湿度值跟实际设备对比也是OK的,但是仔细观察设备启动,首次连接小米设备成功后,直接读取Characteristic的值,竟然是4??   这个肯定是读取的姿势不对,我接下来一番笨丁解牛。 小米温湿度数据格式为:F2 07 4A C3 0A。也就是5个十六进制数据。仔细看当前的直接读取Characteristic值代码: // Read the value of the characteristic. if(pRemoteCharacteristic->canRead()) { String value = pRemoteCharacteristic->readValue(); Serial.print("The characteristic value was: "); Serial.println(value.c_str()); } readValue()方法返回的是String类型变量,更合适的应该是: uint8_t* test = pRemoteCharacteristic->readRawData();   计算一下使用直接读取数据所对应的温湿度:     代码: uint8_t* test = pRemoteCharacteristic->readRawData(); uint8_t i; uint8_t test_temp_val[5]={0}; for(i = 0; i < 5; i++){ if(test != nullptr){ Serial.print("The characteristic value using readRawData was: "); Serial.println(*test); test_temp_val = *test; }else{ Serial.println("pRemoteCharacteristic->readRawData() returns NULL PTR"); } test++; } static uint16_t Test_TempVal = test_temp_val[1]*256 + test_temp_val[0]; Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree"); static uint8_t Test_HumidityVal = test_temp_val[2]; Serial.println("Test Humidity is: " + String(test_temp_val[2]) + "% "); static uint16_t Test_BatteryVal = test_temp_val[4]*256 + test_temp_val[3]; Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV"); 参考: 读取小米蓝牙温湿度计2数据 https://www.cnblogs.com/qsbye/p/15913753.html

  • 发表了主题帖: 【FireBeetle 2 ESP32 C6开发板】-2- BLE server创建

    BLE的Server通常是提供多种Service的设备,每个Service底下包含了多个Characteristic,每个Characteristic的值通常都代表一定的意义。这种设备通常需要通过广播来告诉别的设备自己是谁,能提供什么样的数据,所以也成为“从设备”。   BLE的Client通常Scan周围的BLE设备,然后发现了自己感兴趣的设备,并且匹配到了相应的Service UUId和Characteristic UUID后,即可获取上述BLE Server提供的数据。 下面的例子中:ESP32-C6是BLE SERVER,是从设备,把自己广播给周围的设备。 #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" void BLEBegin(){ // Create the BLE Device BLEDevice::init(/*BLE名称*/"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()->addServiceUUID(SERVICE_UUID); pServer->getAdvertising()->start(); Serial.println("Waiting a client connection to notify..."); } 上述代码中,启动广播之前,把自己能提供的SERVICE UUID也广播出去。接下来是手机BLE助手上看一下。     通过BLE助手向CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 写入数据:          完整代码如下: /* 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. */ /* 该示例演示了蓝牙数据透传,烧录代码,打开串口监视器,打开手机的BLE调试助手 * 1.即可看见ESP32发送的数据--见APP使用图 * 2.通过BLE调试助手的输入框可向ESP32发送数据--见APP使用图 * 该示例由BLE_uart示例更改而来 */ #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> BLEServer *pServer = NULL; BLECharacteristic * pTxCharacteristic; bool deviceConnected = 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) { //当蓝牙连接时会执行该函数 Serial.println("蓝牙已连接"); deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { //当蓝牙断开连接时会执行该函数 Serial.println("蓝牙已断开"); deviceConnected = false; delay(500); // give the bluetooth stack the chance to get things ready pServer->startAdvertising(); // restart advertising } }; /****************数据接收部分*************/ /****************************************/ //蓝牙接收数据处理。当收到数据时自动触发 class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = (pCharacteristic->getValue()).c_str();//接收数据,并赋给rxValue //if(rxValue == "ON"){Serial.println("开灯");} //判断接收的字符是否为"ON" 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); BLEBegin(); //初始化蓝牙 } void loop() { /****************数据发送部分*************/ /****************************************/ if (deviceConnected) { //如果有蓝牙连接,就发送数据 pTxCharacteristic->setValue("Hello"); //发送字符串 pTxCharacteristic->notify(); delay(10); // bluetooth stack will go into congestion, if too many packets are sent pTxCharacteristic->setValue("DFRobot"); //发送字符串 pTxCharacteristic->notify(); delay(10); // bluetooth stack will go into congestion, if too many packets are sent } /****************************************/ /****************************************/ } void BLEBegin(){ // Create the BLE Device BLEDevice::init(/*BLE名称*/"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()->addServiceUUID(SERVICE_UUID); pServer->getAdvertising()->start(); Serial.println("Waiting a client connection to notify..."); }  

  • 2024-04-28
  • 发表了主题帖: 【FireBeetle 2 ESP32 C6开发板】-1- 开发环境搭建

    本帖最后由 慕容雪花 于 2024-4-28 09:42 编辑 FireBeetle 2 ESP32C6 是开源硬件公司DFROBOT推出的基于乐鑫最新的C6芯片的快速原型设备。它主打低功耗物联网,适用于智能家居项目。ESP32-C6支持Wi-Fi 6、Bluetooth 5、Zigbee 3.0、Thread 1.3通讯协议,可接入多种通讯协议的物联网网络。FireBeetle 2 ESP32-C6支持Type-C、5V DC、太阳能供电,部署时有更多的供电方式选择。 开发板做工优良,实物图如下:         引脚概述 Power: 电源引脚 VIN: 5V DC输入或4.5-6V太阳能板 3V3: 3.3V稳压电源输出 GND:公共地引脚 GPIO:ESP32默认GPIO号 Arduino:FirebBeetle 2 ESP32-C6在Arduino中的GPIO映射 ADC:ESP32默认模数转换引脚 I2C:I2C接口 SDA/SCL: FirebBeetle 2 ESP32-C6在Arduino中的I2C映射 LP_SDA/SCL: 低功耗I2C引脚 UART:UART接口 LP_TX/RX: 低功耗UART引脚 SPI: FirebBeetle 2 ESP32-C6在Arduino中的SPI映射 SDIO: ESP32默认SDIO引脚 JTAG:调试接口 开发环境使用Arduino,根据乐鑫之前发布的文章【乐鑫发布 Arduino ESP32 v3.0.0】: 现在是时候发布 Arduino ESP32 v3.0.0 了,增加对 ESP32-C6 和 ESP32-H2 的支持,以及对 API 的改进和一些重大改动   在Arduino里面找到File -> Preference-> Additional boards manager,添加: http://download.dfrobot.top/FireBeetle/package_DFRobot_index.json https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json   在Arduino里面找到Board Manager,找到v3.0     然后编写一个最简单的闪烁LED: int led = 15; void setup() { pinMode(led,OUTPUT); } void loop() { digitalWrite(led,HIGH); delay(1000); digitalWrite(led,LOW); delay(1000); }     实物:     参考: FireBeetle 2 Board ESP32 C6  https://wiki.dfrobot.com.cn/_SKU_DFR1075_FireBeetle_2_Board_ESP32_C6#target_0

最近访客

< 1/3 >

统计信息

已有65人来访过

  • 芯积分:305
  • 好友:--
  • 主题:33
  • 回复:48

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言