STM32+ESP32-C3蓝牙开发测试案例

1.准备

BLE通讯原理

使用的ESP32芯片 包含有WIFI和BLE模块 => 把ESP32当做BLE的外设模块使用

(1) 使用官方提供的AT固件 => 烧录进ESP32中

(2) 采用USART2通信 => 发送AT指令给ESP32 => 做出对应的响应

硬件原理图

(1) USART2 => ESP32

项目准备

(1) 使用cube 构建代码

(2) 修改系统时钟 => 打开USART1 用于printf输出 => 打开USART2 用于和ESP32通信

(3) 修改项目名称 => 创建代码

(4) 添加Int_ESP32.c和Int_ESP32.h文件

(5) 修改keil => 勾选lib => 修改debug => 添加对应的文件和目录

项目开发

1. 初始化ESP32

(1) 初始化底层驱动 usart2

(2) 调用接收ESP32信息的函数

(3) 重置ESP32即可 => 延时3s

2. 初始化BLE

(1) 选择作为服务端

(2) 创建对应的服务

(3) 启动服务

(4) 设置广播参数

(5) 设置广播数据 => 使用自动方式设置

(6) 开始广播

(7) 配置透传参数

(8) 设置打印连接变更的信息 SYSMSG

3. 处理连接状态变化的方法

Inf_BLE_Handle_Change

(1) 如果接收到的信息包含 +BLECONN 连接成功信息

开启透传 (会自动生成1字节的信息 需要消耗掉)

(2) 如果接收到的信息包含 "+BLEDISCONN 断开连接信息

关闭透传 重新广播

4. 接收数据的函数

Inf_BLE_ReadData => BLE_DATA

只有当前接收的数据是透传模式之后的数据 才需要完成接收响应

进入透传模式之后 ESP32使用USART2和STM32交互的信息全部都是 纯净的数据信息

5. 发送数据的函数

Inf_BLE_SendData

只有在透传模式下 => 才能使用USART2发数据给ESP32中 => 当做数据回复给另外一个蓝牙设备

2. 简介

2.1 蓝牙技术类型

  • 经典蓝牙(BR/EDR)

  • 低功耗蓝牙(BLE)

2.2 市场上常见的蓝牙架构

  • SOC单芯片

  • SOC蓝牙芯片 + MCU

  • 蓝牙 host 和 Controller 分开方案(HC)

2.3 数据传输

  • 普通模式,加一些头尾信息

  • 透传模式,不加其他信息

2.4 BLE 角色划分

LL:设备可以划分为 主机 和 从机,从机广播,主机可以发起连接。

GAP:定义了 4 种特定角色:广播者、观察者、外围设备 和 中心设备。

GATT:设备可以分为 服务端 和 客户端

2.5 蓝牙通信的动作

  • 广播:当从机处于广播状态时,主机(客户端)才能发现该从机(服务端)。在每个广播事件中,广播包会分别在37、38和39三个信道上依次广播

  • 扫描:扫描是主机监听从机广播数据包和发送扫描请求的过程

  • 通讯:主机作为GATT的Client端,用来发现和获取从机的Service和Characteristic,从而与之通信。

3.案例

2.1 透传模式下收发数据

  • Inf_ESP32.c

(1)AT指令的发送及返回数据的处理

#include "Inf_ESP32.h"

uint8_t rBuff[128];
uint16_t rDataLength;

uint8_t resPonseBuff[1024];
uint16_t resDataLength;

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    // 健壮性判断
    if (huart->Instance == USART2)
    {
        // 此时是ESP32回复的消息
        rDataLength = Size;
        // 一次调用HAL_UARTEx_ReceiveToIdle_IT中断只触发一次回调
        HAL_UARTEx_ReceiveToIdle_IT(&huart2, rBuff, 128);

        // 打印收到的数据
        //  原则性问题:不能在中断处理中使用运行时间过长的函数
        //  printf("接收到的ESP32收到的数据为%s\n",rBuff);
    }
}

void Inf_Handle_Response(void)
{
    // 循环·等待接收多次5消息  ==> 一直到接收完成 或者收到OK或ERROR
    uint8_t count = 2;
    /* 1. 初始化responseBuff */
    memset(resPonseBuff, 0, 1024);
    resDataLength = 0;
    do
    {
        // 单次接收到的数据存放到resPonseBuff中
        while (rDataLength == 0)
            ;

        // 直到数据过来,存放在大的缓存中
        memcpy(&resPonseBuff[resDataLength], rBuff, rDataLength);
        resDataLength += rDataLength;
        rDataLength = 0;
        memset(rBuff, 0, 128);
    } while (count-- && (strstr((char *)resPonseBuff, "OK") == NULL) && (strstr((char *)resPonseBuff, "ERROR") == NULL));
    printf("%s\n", resPonseBuff);
    printf("--------------\n");
}

void Inf_ESP32_SendCmd(uint8_t *cmd)
{
    // 直接使用USART2发送命令就是发送指令
    HAL_UART_Transmit(&huart2, cmd, strlen((char *)cmd), 1000);

    // 由于不能一次执行多条指令  ==> 挂起等待执行响应
    Inf_Handle_Response();
}

(2)ESP32初始化

void Inf_ESP32_Init(void)
{
    /*1. 初始化usart2 */
    MX_USART2_UART_Init();
    /*2. 提前调用接收ESP32返回消息的函数*/
    HAL_UARTEx_ReceiveToIdle_IT(&huart2, rBuff, 128);
    /*3. 让ESP32发送初始化消息*/
    uint8_t *cmd = "AT+RST=0\r\n";
    Inf_ESP32_SendCmd(cmd);
    // 延时3s,等待ESP32重启
    HAL_Delay(3000);
}

(3)蓝牙初始化

void Inf_ESP32_BLE_Init(void)
{
    /*0. 初始化ESP32*/
    Inf_ESP32_Init();

    /*1. 初始化BLE, 选择作为服务端*/
    uint8_t *cmd = "AT+BLEINIT=2\r\n";
    Inf_ESP32_SendCmd(cmd);

    /*2. 创建BLE服务端服务。*/
    cmd = "AT+BLEGATTSSRVCRE\r\n";
    Inf_ESP32_SendCmd(cmd);

    /*3. BLE服务端开启服务*/
    cmd = "AT+BLEGATTSSRVSTART\r\n";
    Inf_ESP32_SendCmd(cmd);

    /*4. 设置广播参数*/
    // 50ms,50ms 最小和最大广播间隔;
    // 7:广播信道,7表示使用37,38,39三个信道
    cmd = "AT+BLEADVPARAM=50,50,0,0,7,0,,\r\n";
    Inf_ESP32_SendCmd(cmd);

    /* 5. 设置广播数据  -> 使用自动档 */
    // 第一个参数:设备名称; 第二个参数:UUID;
    cmd = "AT+BLEADVDATAEX=\"test-10086\",\"A123\",\"1122334455\",1\r\n";
    Inf_ESP32_SendCmd(cmd);

    /*6. 开始广播*/
    cmd = "AT+BLEADVSTART\r\n";
    Inf_ESP32_SendCmd(cmd);

    /*7. 配置透传模式SPP*/
    // 第一个参数 “1”:0表示重置,1才能填写后面
    // 第二个参数“1”:tx服务序号  第三个参数 “7”:tx服务特征序号 对应306
    // 第四个参数“1”:rx服务序号  第三个参数 “5”:rx服务特征序号 对应304
    cmd = "AT+BLESPPCFG=1,1,7,1,5\r\n";
    Inf_ESP32_SendCmd(cmd);

    // 不能直接使能透传模式  =>  需要等待手机连接完成才能开透传

    /* 8. 打开连接状态信息  =>  方便判断什么时候进入透传模式 */
    // bit2为1,及其值为4
    cmd = "AT+SYSMSG=4\r\n";
    Inf_ESP32_SendCmd(cmd);
}

(4)根据ESP32返回消息判断处于什么状态

ESP32State Inf_BLE_Handle_Change(void)
{
    /*根据ESP32返回的消息来判断处于什么状态*/
    // 1. +BLECONN 处于连接状态
    if (strstr((char *)rBuff, "+BLECONN") != NULL)
    {
        // 清空数据
        rDataLength = 0;
        memset(rBuff, 0, sizeof(rBuff));
        // 进入透传模式
        printf("连接BLE成功 准备进入透传模式\n");
        uint8_t *cmd = "AT+BLESPP\r\n";
        Inf_ESP32_SendCmd(cmd);

        // 将额外返回的一个字节 '>' 给消耗掉 => 不影响后续的透传收发的数据
        uint8_t tmp;
        HAL_UART_Receive(&huart2, &tmp, 1, 1000);
        return BLE_SPP;
    }

    // 2. +BLEDISCONN 处于关闭连接状态
    if (strstr((char *)rBuff, "+BLEDISCONN") != NULL)
    {
        // 清空数据
        rDataLength = 0;
        memset(rBuff, 0, sizeof(rBuff));
        // 断开连接
        printf("BLE断开连接 关闭透传  重新广播\n");
        // 2.1 关闭透传
        // 当系统收到只含有 +++ 的包时,设备返回到普通命令模式,请至少等待一秒再发送下一个 AT 命令。
        HAL_UART_Transmit(&huart2, "+++", 3, 1000);
        HAL_Delay(2000);
        // 2.2 重新广播
        uint8_t *cmd = "AT+BLEADVSTART\r\n";
        Inf_ESP32_SendCmd(cmd);
        return BLE_DIS;
    }
    return BLE_DATA;
}

(5)数据收发

void Inf_BLE_ReadData(uint8_t data[], uint16_t *rxDataSize)
{
    if (rDataLength == 0)
    {
        return;
    }
    // 此时的数据不是透传收发的数据  属于状态变更数据
    if (Inf_BLE_Handle_Change() != BLE_DATA)
    {
        return;
    }

    // 健壮性处理
    memset(data, 0, sizeof(data));

    // 将rBuff中接收到的数据 赋值到 data
    memcpy(data, rBuff, rDataLength);
    *rxDataSize = rDataLength;
    rDataLength = 0;
}
void Inf_BLE_SendData(uint8_t data[], uint16_t size)
{
    // 处于透传模式  =>  直接使用USART2发送数据即是传输给BLE
    HAL_UART_Transmit(&huart2, data, size, 1000);
}

- Inf_ESP32.h

#ifndef __INF_ESP32_H__
#define __INF_ESP32_H__

#include "main.h"
#include "usart.h"
#include "string.h"

typedef enum
{
    BLE_SPP,     // 连接状态   =>  指令进入透传模式
    BLE_DIS,     // 关闭连接   =>  关闭SPP透传模式  =>  正常发送接收AT指令
    BLE_DATA,    // 稳定连接可以传输数据的状态   =>  接收和发送的所有数据都当做纯净的数据收发
    WIFI_CHANGE, // WIFI的变更信息

}ESP32State;

void Inf_ESP32_Init(void);
void Inf_ESP32_SendCmd(uint8_t *cmd);
void Inf_Handle_Response(void);

void Inf_ESP32_BLE_Init(void);

ESP32State Inf_BLE_Handle_Change(void);

void Inf_BLE_ReadData(uint8_t data[],uint16_t * rxDataSize);
void Inf_BLE_SendData(uint8_t data[],uint16_t size );
#endif /* __INF_ESP32_H__ */

- main.c

  /* USER CODE BEGIN 2 */
  printf("hello BLE...\n");
  // 初始化蓝牙
  Inf_ESP32_BLE_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  uint8_t rxBuff[128];
  uint16_t rxDataSize;
  while (1)
  {
    Inf_BLE_ReadData(rxBuff, &rxDataSize);
    if (rxDataSize != 0)
    {
      printf("BLE接收到数据%s\n", rxBuff);

      // 将数据返回
      Inf_BLE_SendData(rxBuff, rxDataSize);
      rxDataSize = 0;
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值