Stm32t通讯——蓝牙通讯

蓝牙基础知识点

  1. 蓝牙:利用低功率无线电,支持设备短距离通信的无线电技术。特点:短距离、低功率。
  2. 第一代蓝牙:BR(Basic Rate)技术, 传输速率:721.2kbps。                                              第二代蓝牙:EDR(Enhanced Data Rate)技术,3Mbps;                                                第三代蓝牙:核心是AMP(Generic Alternate MAC/PHY),这是一种全新的交替射频技术,支持动态地选择正确射频,传输速率高达24Mbps。                                                              第四代蓝牙:主推Low Energy低功耗,BLE(Bluetooth Low Energy)低功耗功能。              第五代蓝牙:开启物联网时代大门,在低功耗模式下具备更快更远的传输能力。
  3. 蓝牙协议技术:BR 和 LE。分类:经典蓝牙和低功耗蓝牙。
  4.   蓝牙架构: soc蓝牙单芯片方案,可以作为MCU用,一般用于消费类电子,集成度很高。    soc蓝牙 + MCU方案:外设一个单芯片方案,发送自定义的命令达到想要的功能。                 蓝牙host + controller 分开方案:Host和Controller分开,集成更多的蓝牙协议,蓝牙电话、蓝牙音频、蓝牙音乐控制等等。
  5. 蓝牙协议栈:直接使用。
  6. 蓝牙芯片架构:

    蓝牙的核心系统,由一个Host和一个或多个Controller组成。

    1. BT Host:逻辑实体,在HCI(Host Controller Interface)的上层。

    2. BT Controller:逻辑实体,在HCI(Host Controller Interface)的下层。

  7. 单模蓝牙芯片:1 Host  结合 1 Controller;双模蓝牙芯片:1 Host 结合 多个 Controller。         

  8. BLE低功耗蓝牙协议栈框架:蓝牙协议:蓝牙核心协议(Bluetooth Core)和蓝牙应用层协议(Bluetooth Application)

   蓝牙协议栈:蓝牙核心协议中除了Radio 物理层。

  1. PHY物理层:在物理信道上发送和接收信息包,40个射频信道,2402MHz到 2480 MHz。
  2. LL链路层:控制链路层状态机处于准备、广播、监听/扫描、发起连接、已连接状态中的一种。
  3. HCI主机控制接口层:向主句和控制器提供一个标准化的接口。
  4. GAP通用访问配置文件层:代表所有蓝牙设备的通用功能。GAP服务:设备发现、连接模式、安全、身份验证、关联模式、服务发现。
  5. L2CAP逻辑链路控制及自适应协议层:对主机和协议栈之间交换的数据进行协议复用能力、分段和重组操作。
  6. SM:安全管理层:SMP层,生成加密密钥和身份密钥。
  7. ATT属性协议层:定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。
  8. GATT通用属性配置文件层:属性服务器和可选的属性客户端的功能。用于发现、读取、写入和指示服务特性和属性的接口。
  9. ESP32—C3中的蓝牙功能:先烧好固件然后通过AT指令操作蓝牙。
  10. LL:设备可以划分为主机和从机,从机广播,主机可以发起连接。
  11. GAP:定义4种特定角色:广播者、观察者、外围设备和中心设备。
  12. GATT:设备可以分为服务端和客户端。
  13. BLE地址:
    1. 公共地址:6字节,3个向IEEE购买,3个公司内部分配:               
    2. 随机地址:静态地址和私有地址,通过最高两位来区分。
      1. 静态地址:最高两位11,随机部分至少有一个位是0和1 。
      2. 私有地址:最高两位00/01,随机部分至少有一个位是0和1。
    3. 广播:从机每经过一个时间间隔发送一次广播数据包,时间间隔:广播间隔,广播动作:广播事件,只有当从机处于广播状态时,主机才能发现该从机。
    4. 扫描:主机监听从机广播数据包和发送扫描请求的过程,主机通过扫描,获取到从机的广播包以及扫描回应数据包,主机可以对已扫描到的从机设备发起连接请求,从而连接从机设备并通信。
    5. 通讯:通过GATT的Profile来完成,Profile 可以理解配置、数据格式等。

      从机作为GATT的Server端,用来定义和存储Profile。Profile包含一个或者多个Service,每个Service又包含一个或者多个Characteristic,Characteristic是主从通信的最小单元。

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

  14. 蓝牙透传模式:从一端输入数据,原封不动的传输到另一端,不需要对数据惊醒复杂的解析或者处理。

案例:蓝牙通讯—透传模式下收发数据

采用的蓝牙架构:soc + mcu 方案,通过串口向esp32—C3发送AT指令,实现功能。

提前完成ESP32-C3固件烧录,将ESP32作为从机—服务端,开启蓝牙服务,通过手机蓝牙调式助手连接,进行通讯。

代码实现:串口通讯通过Hal库实现。

esp32.h

#ifndef __ESP32_H
#define __ESP32_H

#include "usart.h"
#include <string.h>

// 初始化
void ESP32_Init(void);

// 发送命令
void ESP32_SendCmd(uint8_t *cmd, uint16_t cmdlen);

// 接收响应
void ESP32_ReadResp(uint8_t rBuff[], uint16_t *rDataLen);

#endif

esp32.c

#include "esp32.h"

// 定义接收的缓冲区和数据长度
uint8_t respBuff[1000];
uint16_t respDataLen;
// 初始化
void ESP32_Init(void)
{
    // 0. 初始化
    MX_USART2_UART_Init();
    // 1. 发送重启命令
    uint8_t *cmd = "AT+RST=0\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    HAL_Delay(3000);
}

// 发送命令
void ESP32_SendCmd(uint8_t *cmd, uint16_t cmdlen)
{
    // 通过串口2直接发送
    HAL_UART_Transmit(&huart2, cmd, cmdlen, 1000);
    // 每次发送完都接收数据, 循环等待,并判断包含OK
    memset(respBuff, 0, 1000);
    do
    {
        ESP32_ReadResp(respBuff, &respDataLen);
    } while (strstr((char *)respBuff, "OK") == NULL);
    
}

// 接收响应
void ESP32_ReadResp(uint8_t rBuff[], uint16_t *rDataLen)
{
    HAL_UARTEx_ReceiveToIdle(&huart2, rBuff, 1000, rDataLen, 1000);

}

bluetooth.h

#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H

#include "esp32.h"

// 初始化
void Bluetooth_Init(void);

// 接收数据:读取数据或者连接状态,返回值为0 - 正常数据
uint8_t Bluetooth_ReadDataAndStatus(uint8_t rxBuff[], uint16_t *rxLen);

// 处理连接改变情况的函数,返回值,表示是否有连接改变
uint8_t Bluetooth_HandleConnChange(void);

// 发送数据
void Bluetooth_SendData(uint8_t txBuff[], uint16_t txLen);

#endif

bluetooth.c

#include "bluetooth.h"

// 初始化
void Bluetooth_Init(void)
{
    // 1. 初始化 ESP32
    ESP32_Init();

    // 2. 设置角色 2 - server
    printf("设置蓝牙模块角色...\n");
    uint8_t *cmd = "AT+BLEINIT=2\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 3. 服务端创建服务
    printf("服务端创建服务!\n");
    cmd = "AT+BLEGATTSSRVCRE\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 4. 服务端开启服务
    printf("服务端开启服务!\n");
    cmd = "AT+BLEGATTSSRVSTART\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 5. 服务端设置Bluetooth 设备名称
    printf("服务端设置Bluetooth 设备名称!\n");
    cmd = "AT+BLENAME=\"BaiLu_BLE\"\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 6. 服务端设置广播参数
    printf("服务端设置广播参数!\n");
    cmd = "AT+BLEADVPARAM=50,50,0,0,7,0,,\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 7. 服务端设置广播数据
    printf("服务端设置广播数据!\n");
    cmd = "AT+BLEADVDATAEX=\"BaiLu_BLE\",\"A666\",\"0102030405\",1\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 8. 服务端开始广播
    printf("服务端开始广播!\n");
    cmd = "AT+BLEADVSTART\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 9. 配置 BLE 的透传模式,设置SPP参数
    printf("配置 BLE 的透传模式!\n");
    // 设置信道号和特征值
    cmd = "AT+BLESPPCFG=1,1,7,1,5\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));

    // 10. 设置透传模式下,连接状态改变打印系统提示信息
    printf("设置透传模式下,连接状态改变打印系统提示信息!\n");
    cmd = "AT+SYSMSG=4\r\n";
    ESP32_SendCmd(cmd, strlen((char *)cmd));
}

// 接收数据:读取数据或者连接状态,返回值为0 - 正常数据, 1 - 空数据,2 - 连接状态改变信息
uint8_t Bluetooth_ReadDataAndStatus(uint8_t rxBuff[], uint16_t *rxLen)
{
    // 直接从串口接收数据
    HAL_UARTEx_ReceiveToIdle(&huart2, rxBuff, 1000, rxLen, 10000);

    // 处理非正常数据的情况
    // 1 - 空数据
    if (*rxLen == 0)
    {
        return 1;
    }

    // 2 - 连接状态改变信息, 先根据函数返回值判断是否有连接改变
    if (Bluetooth_HandleConnChange())
    {
        return 2;
    }

    // 如果是透传模式下的正常数据,直接返回
    return 0;
}

// 引入外部变量,全局接收缓冲区
extern uint8_t rxBuff[1000];
// 处理连接改变情况的函数,返回值表示是否有连接改变
uint8_t Bluetooth_HandleConnChange(void)
{
    // 从缓冲区中提取信息,进行判断
    // 1. 如果是WiFi连接变化信息,不做处理,直接返回 1
    if (strstr((char *)rxBuff, "+STA_CONNECTED") != NULL ||
        strstr((char *)rxBuff, "+STA_DISCONNECTED") != NULL ||
        strstr((char *)rxBuff, "+DIST_STA_IP") != NULL )
    {
        printf("WiFi 连接状态发生改变!\n");
        return 1;
    }

    // 2. 如果是BLE连接变化信息,要进一步判断是建立连接还是断开连接
    if (strstr((char *)rxBuff, "+BLECONN") != NULL)
    {
        // 2.1 如果是建立连接,就进入透传(SPP)模式
        printf("有BLE客户端连接,即将开启 SPP模式!\n");
        uint8_t *cmd = "AT+BLESPP\r\n";
        ESP32_SendCmd(cmd, strlen((char *)cmd));
        // 额外读取一个字符 (>), 接下来就是真正的数据
        uint8_t tmp;
        HAL_UART_Receive(&huart2, &tmp, 1, 1000);
        return 1;
    }
    else if (strstr((char *)rxBuff, "+BLEDISCONN") != NULL)
    {
        // 2.2 如果是断开连接,接退出透传模式
        printf("BLE客户端断开连接,即将退出 SPP模式!\n");
        // 发送"+++",退出透传模式
        HAL_UART_Transmit(&huart2, "+++", 3, 1000);

        // 延时2s
        HAL_Delay(2000);
        return 1;
    }
    // 其他情况,默认返回0,(认为是数据)
    return 0;
}

// 发送数据
void Bluetooth_SendData(uint8_t txBuff[], uint16_t txLen)
{
    // 透传模式下,发送,直接串口发送
    HAL_UART_Transmit(&huart2, txBuff, txLen, 1000);
}

main.c


/* USER CODE BEGIN 0 */
// 全局接收缓冲区和数据长度
uint8_t rxBuff[1000];
uint16_t rxDataLen;
/* USER CODE END 0 */


// 1. 初始化
  Bluetooth_Init(); 
  printf("Bluetooth 初始化完成!\n");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // 从串口不停轮询读取数据或状态,只有返回值为0,才是真正的数据
    if (Bluetooth_ReadDataAndStatus(rxBuff, &rxDataLen) == 0)
    {
      printf("蓝牙模块接收到数据,长度为:%d, 内容为:%.*s\n", rxDataLen, rxDataLen, rxBuff);
      // 数据原样发回去
      Bluetooth_SendData(rxBuff, rxDataLen);

      rxDataLen = 0;
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

作者:嵌界游龙

物联沃分享整理
物联沃-IOTWORD物联网 » Stm32t通讯——蓝牙通讯

发表回复