ESP32作为从机实现BLE蓝牙功能浅析

引言

去年11月份,自己接到的第一个任务就是蓝牙,二维码任务结束后自己又开始做这一个任务,由于还没有定好应用场景,自己先根据自己的理解,介绍一下如何用ESP32实现BLE蓝牙。

开发环境

本工程将ESP32芯片作为从机,使用其他MCU来驱动ESP32,开发的操作系统还是阿里的物联网系统Alios。ESP32可以使用多种方式与主MCU进行通信,例如串口,SPI以及SDIO,但是官方好像说只能同时支持一种通信方式,在本项目中使用SDIO通信作为主MCU与ESP32芯片的通信方式。

开发过程

开发过程其实没什么好说的,在开始的时候我一直认为要写很复杂的程序才能使用蓝牙,其实自己想错了,ESP32提供了一整套较为完整的AT命令,乐鑫公司已经把驱动代码封装到固件中了,开发者只需要使用与BLE蓝牙相关的AT命令,编写业务逻辑就可以了,这里提供3个我自己经常查看的教程。
1、BLE 命令介绍和使用
2、ESP32 常用蓝牙AT指令使用例程
3、ESP32官方AT命令文档

我认为使用ESP32的AT命令开发蓝牙重点在于自己产品的业务逻辑,如蓝牙是做server还是client,获得的数据怎么处理,应用场景等。我自己的项目执行这几个命令就可以了。

AT+BLEINIT=2 //初始化BLE为server
AT+BLEGATTSSRVCRE //GATTS 创建服务
AT+BLEGATTSSRVSTART //GATTS 开启服务
AT+BLEADVSTART //开启BLE广播

难点
1、主MCU怎么与ESP32使用SDIO进行通信。(驱动工程师编写)
2、在操作系统中怎么进行逻辑编写,在这个项目中使用了消息队列搭建框架。(自己还是新手,架构是其他大佬搭建的)

开发结果

蓝牙客户端使用iphone,由于iphone会将BLE蓝牙过滤,使用LightBlue软件进行开发。可以看到软件可以搜索到自己打开的ESP32低功耗蓝牙。
在这里插入图片描述
进行连接发现可以连接,并且GATT服务以及开启
在这里插入图片描述
ESP32打印
在这里插入图片描述
到此手机与ESP32的BLE蓝牙成功进行连接,下面的等业务逻辑确定后再进一步编写,

知识总结

AT命令

ESP-AT 是乐鑫开发的可直接用于量产的物联网应用固件,旨在降低客户开发成本,快速形成产品。通过 ESP-AT 指令,您可以快速加入无线网络、连接云平台、实现数据通信以及远程控制等功能,真正的通过无线通讯实现万物互联。
AT 命令以 “AT” 开始,代表 Attention,以新的一行 (CR LF) 为结尾。输入的每条命令都会返回 OK 或 ERROR 的响应,表示当前命令的最终执行结果。注意,所有 AT 命令均为串行执行,每次只能执行一条命令。因此,在使用 AT 命令时,应等待上一条命令执行完毕后,再发送下一条命令。

BLE蓝牙协议栈

推荐听一下这个课「物联网」- 蓝牙4.0 BLE开发入门到精通
在这里插入图片描述

GATT服务

GATT服务我看了一些还是感觉有点蒙蒙的,在我的理解里,GATT在BLE协议栈里相当于串口一类通信模块的意思,要想使用BLE蓝牙进行数据传输,就必须打开GATT服务,GATT是通用的,客户端和服务器都遵循这个协议。(欢迎指正)

消息队列

消息队列是一种任务间传递数据的有效方式。消息队列使用环形缓冲池(ring buffer)来管理消息的队列缓冲区,并使用类似信号量的机制进行任务间的同步。任务通过消息队列可以发送消息,也可以通过它接收消息,从而实现数据的同步及通信。任务发送的消息会暂存在消息队列中,当接收任务来读时,将暂存的数据传递给接收任务;若接收任务在接收数据时,消息队列中无可读数据,则任务会阻塞,直到有消息到来解除阻塞而进入就绪状态。
在这个项目,大佬将所有的AT命令执行函数抽象成了一个,将AT推入消息队列。

static int at_exec_command(netm_msg_t *cmd, netm_msg_t *resp)
{
    int ret;

    csi_kernel_mutex_lock(g_cmd_mutex, -1);

    cmd->msg_src = SRC_APP;

    if (!cmd->timeout) {
        cmd->timeout = DEFAULT_CMD_TIMEOUT;
    }

    ret = csi_kernel_msgq_put(g_netm_queue, cmd, BACK, NO_WAIT);

    if (ret < 0) {
        printf("ree %d put g_netm_queue is error\r\n",ret);
        csi_kernel_mutex_unlock(g_cmd_mutex);
        return ret;
    }

    ret = at_wait_cmd_done(resp, cmd->cmd);

    csi_kernel_mutex_unlock(g_cmd_mutex);

    return ret;
}

在执行命令的时候,从消息队列不断向外取就可以了。

static void netm_task(void *arg)
{
    netm_msg_t msgbuf;
    int  ret = 0;

    while (1) {
        memset(&msgbuf, 0, sizeof(msgbuf));
        ret = csi_kernel_msgq_get(g_netm_queue, (void *)&msgbuf, -1);

        if (ret < 0) {
            LOG_E("recv msg fail,error:%d\n", ret);
            continue;
        }
        //printf("msgsrc 0x%x\r\n",msgbuf.msg_src);
        switch (msgbuf.msg_src) {
            case SRC_APP:
                handle_at_response(&msgbuf);
                handle_at_cmd(&msgbuf);
                break;

            case SRC_DRIVER:
                handle_at_response(&msgbuf);
                break;

            default:
                LOG_E("error msg type\n");
                break;
        }
    }/* while */
}

结尾

在这个任务中学到了BLE蓝牙的知识,困难部分大佬已经做过了,自己在架构上缝缝补补的同时也要不断学习,如果让自己全部写的话自己能不能写出来一个完整且易于拓展的业务框架。整体来说要做蓝牙的话使用乐鑫的ESP32还是可以省事很多,在不要求深度定制的情况下,使用AT命令进行开发以及可以满足大部分要求,同理ESP32也支持wifi,思路是一样的。

在等待蓝牙使用场景的这段时间,自己准备做这3件事情。
1、把自己的C语言和操作系统再精进一下,跟着B站上的视频走一遍,查漏补缺一下,顺便刷一些题,练练手感。(现在读懂是没问题了,要向写的方向上发展,不要眼高手低)
2、把之前买的野火的STM32开发板,跟着视频,再把例子重新自己写一下,把SDIO,I2C,SPI等再好好熟悉一下。(感觉经过之前的任务历练后,这些对我来说应该没那么难了)
3、如果有时间的话,把韦东山的Linux也好好学一学,在Linux上主要学内核的知识,如多线程编程,信号量,事件等知识好好专研一下。(把这3个做完后自己应该就可以完全入行了,之前的任务让我感觉基础太不扎实了)

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 非常感谢您的提问,以下是一个简单的 Arduino ESP32 蓝牙从机程序: #include <BLEDevice.h> #include <BLEServer.h> #include <BLEUtils.h> #include <BLE2902.h> BLECharacteristic *pCharacteristic; bool deviceConnected = false; bool oldDeviceConnected = false; uint8_t txValue = 0; class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; } }; void setup() { Serial.begin(115200); BLEDevice::init("MyESP32"); BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(BLEUUID((uint16_t)0x180F)); pCharacteristic = pService->createCharacteristic( BLEUUID((uint16_t)0x2A19), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE ); pCharacteristic->addDescriptor(new BLE2902()); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->addServiceUUID(BLEUUID((uint16_t)0x180F)); pAdvertising->setScanResponse(true); pAdvertising->setMinPreferred(0x06); pAdvertising->setMaxPreferred(0x12); BLEDevice::startAdvertising(); Serial.println("Waiting for a client connection to notify..."); } void loop() { if (deviceConnected) { pCharacteristic->setValue(&txValue, 1); pCharacteristic->notify(); txValue++; delay(10); } if (!deviceConnected && oldDeviceConnected) { delay(500); pServer->startAdvertising(); Serial.println("start advertising"); oldDeviceConnected = deviceConnected; } if (deviceConnected && !oldDeviceConnected) { oldDeviceConnected = deviceConnected; } } 希望这个程序能够帮助到您! ### 回答2: 如下是一个简单的Arduino ESP32蓝牙从机程序示例: ```c++ #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> BLECharacteristic* pCharacteristic; bool deviceConnected = false; bool oldDeviceConnected = false; #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; } }; void setup() { Serial.begin(115200); BLEDevice::init("MyESP32"); BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); } void loop() { if (deviceConnected) { pCharacteristic->setValue("Hello from ESP32"); pCharacteristic->notify(); delay(1000); } if (!deviceConnected && oldDeviceConnected) { delay(500); BLEDevice::startAdvertising(); oldDeviceConnected = deviceConnected; } if (deviceConnected && !oldDeviceConnected) { oldDeviceConnected = deviceConnected; } } ``` 这是一个简单的蓝牙从机程序,在ESP32设备上创建了一个蓝牙广播器和服务。当有一个蓝牙主设备连接时,从机会发送"Hello from ESP32"的消息,并进行周期性通知。在没有连接时,从机会继续以间隔500ms重新开始广播。这段程序使用了ESP32BLE库,需要事先安装该库。 ### 回答3: Arduino ESP32 是一款功能强大的开发板,它带有蓝牙功能,可以作为蓝牙从机进行通信。下面是一个简单的蓝牙从机程序,使用Arduino IDE编写: 1. 引入必要的库文件 ```cpp #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> ``` 2. 定义蓝牙服务和特征 ```cpp #define SERVICE_UUID "0000180D-0000-1000-8000-00805F9B34FB" // 通用蓝牙服务UUID #define CHARACTERISTIC_UUID "00002A37-0000-1000-8000-00805F9B34FB" // 通用特征UUID BLEServer* pServer = nullptr; BLECharacteristic* pCharacteristic = nullptr; ``` 3. 初始化蓝牙从机 ```cpp void setup() { // 初始化蓝牙设备 BLEDevice::init("ESP32"); // 创建蓝牙服务 pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // 创建蓝牙特征 BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); // 开启蓝牙服务 pService->start(); // 启动广播 BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); } ``` 4. 处理蓝牙数据 ```cpp class MyServerCallbacks: public BLEServerCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { // 接收到蓝牙数据 Serial.println("Received data: "); for (int i = 0; i < value.length(); i++) { Serial.print(value[i]); } Serial.println(); } } }; ``` 5. 主循环 ```cpp void loop() {} ``` 以上是一个简单的蓝牙从机程序,它创建了一个蓝牙服务和一个可读写的特征,并通过回调函数处理收到的蓝牙数据。你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值