手把手教你玩转蓝牙模块(原理+驱动)

2024-02-07  本文已影响0人  良许Linux

head:
title: 手把手教你玩转蓝牙模块(原理+驱动)
description:


手把手教你玩转蓝牙模块(原理+驱动)

作为嵌入式开发工程师,蓝牙模块怎能少呢?

蓝牙模块广泛应用在各种电子器件,比如手机、蓝牙耳机/音箱、蓝牙手环、扫地机器人,等等。大家在学嵌入式的时候,玩过的智能家居、智能小车、无人机,都有蓝牙模块的应用。

所以,蓝牙模块的学习势在必行。

蓝牙模块的学习其实也没大家想的那么难,只需要你玩好串口就行了,再加上会一些 AT 指令,你就可以称得上蓝牙高手了。但关于蓝牙协议栈,那学起来估计没一年半载下不来。

对于初学者来讲,只需要懂得如何使用这个蓝牙模块,就已经绰绰有余了。

1. 源码下载及前置阅读

本文首发 良许嵌入式网https://www.lxlinux.net/e/ ,欢迎关注!

本文所涉及的源码及安装包如下(由于平台限制,请点击以下链接阅读原文下载):

https://www.lxlinux.net/e/stm32/bluetooth-turorial.html

如前面所述,玩蓝牙模块就是玩串口,所以大家一定要先把串口玩好。如果你不懂得如何玩串口,可以看下面这篇文章:

STM32串口接收不定长数据(接收中断+超时判断):https://www.lxlinux.net/e/stm32/stm32-usart-receive-data-using-rxne-time-out.html

如果你是个零基础的小白,连 STM32 都没见过,我也给你准备了一个保姆级教程,手把手教你搭建好 STM32 开发环境,并教你如何下载程序,简直业界良心!

零基础快速上手STM32开发(手把手保姆级教程):https://www.lxlinux.net/e/stm32/stm32-quick-start-for-beginner.html

如果你连代码都不知道怎么烧录到 STM32 的,可以参考下文,提供了 5 种代码烧录方式:

STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html

2. 蓝牙模块介绍

2.1 型号介绍

现在市面上流行的蓝牙模块有很多,例如广州汇承公司的蓝牙模块应用非常的广泛,它们公司生产的 HC 系列的蓝牙模块如下图所示:

型号 主/从机 通信协议 工作频段 通信距离 嵌入方式 空中速率 尺寸
HC-02 从机 蓝牙2.0 / 蓝牙4.0 2.4G 10米 贴片 2Mbps 26.9 * 13 * 2 mm
HC-04 从机 蓝牙2.0 / 蓝牙4.0 2.4G 10米 贴片 60KB/s 18.5 * 13 * 2 mm
HC-05 主从机一体 蓝牙2.0 2.4G 10米 贴片 2Mbps 27.0 * 13 * 2 mm
HC-06 主从机一体 蓝牙2.0 2.4G 10米 贴片 2Mbps 27.0 * 13 * 2 mm
HC-08 主从机一体 蓝牙4.0 2.4G 80米 贴片 / 焊接 1Mbps 26.9 * 13 * 2 mm
HC-09 主从机一体 蓝牙4.0 2.4G 60米 贴片 / 焊接 3KB/s 18.5 * 13 * 2 mm
HC-42 主从机一体 蓝牙5.0 2.4G 40米 贴片 / 焊接 1Mbps / 2Mbps 26.9 * 13 * 2 mm

这些蓝牙模块,在主/机、工作频段、通信距离、空中速率等方面都存在差异,大家可以根据自己的业务需求进行选择。

对于初学者而言,HC-08 是一款非常适合入门的蓝牙模块,本文就是以 HC-08 作为对象,介绍蓝牙模块的玩法。

HC-08 采用 TI CC25540 芯片方案,蓝牙 BLE4.0 主从一体,通过 BLE 的软件连接,传输速率 1Mbps ,传输距离 80m ,低功耗,详细参数如下:

2.2 引脚介绍

HC-08 蓝牙模块是通过串口与单片机进行通信,这个模块既可以作为主机也可以作为从机(通过 AT 指令配置)。有些蓝牙模块不支持主机(如 HC-02 、HC-04),所以在使用时需要注意区分。

HC-08 蓝牙模块实物图如下所示:

可以看到,HC-08 模块一共有 6 个引脚,下面详细介绍各个引脚的作用。

上面的「连接」是指模块通过蓝牙协议连接上主机或从机,并非物理意义上的连接。下同。

正常通信下,只需接 RXD、TXD、GND、VCC 四条线就够了。

蓝牙模块上还有一个 LED灯和一个小按键 (按键控制着引脚 KEY )。默认情况下,当 LED灯闪烁时表示蓝牙模块当前为从机,正在等待连接。而长亮的时候就代表已经有主机连接上该模块,可以正常进行透传通讯了。

当按键按下后,主机将清除已被记录的从机地址。另外,也可使用 AT+CLEAR 指令,实现「主机清除已记录的从机地址」的功能。

注意,在硬件接线的时候蓝牙模块的 TXD 要和单片机的 RXD 相连接,蓝牙模块的 RXD 要和单片机的 TXD 相连接,也就是所谓的「交叉接线」。

3. 基本玩法

3.1 主/从机模式

3.1.1 主机模式

当蓝牙模块处于主机模式的时候,可以与一个从机进行连接。在此模式下可以对周围设备进行搜索并选择需要连接的从机进行连接。理论上,一个蓝牙主端设备,可同时与 7 个蓝牙从端设备进行通讯。

一个具备蓝牙通讯功能的设备,可以在两个角色之间进行切换。比如:平时工作在从机模式,等待其它主机来连接;在需要时,可转换为主机模式,向其它设备发起连接。一个蓝牙设备以主机模式发起连接时,需要知道对方的蓝牙地址,配对密码等信息,配对完成之后,可直接发起连接。

3.1.2 从机模式

当蓝牙模块处于从机模式的时候,只能被主机搜索,不能主动搜索。从机与主机连接以后,也可以和主机进行发送和接收数据。

3.3.3 两种工作模式有什么区别呢?

主机是指能够搜索别人并主动建立连接的一方,从机则不能主动建立连接,只能等待主机连接自己。

HC-08 上电之后,默认情况下就是从机模式。如果需要手动配置,可以使用 AT+ROLE=S 指令。

我们需要通过 AT 指令 AT+ROLE=M 来设置蓝牙模块为主机模式。

3.2 什么是AT指令?

AT 指令(AT Commands)最早是由发明拨号调制解调器的贺氏公司为了控制拨号调制解调器而发明的控制协议。后来随着网络带宽的升级,速度很低的拨号调制解调器基本退出市场,但是 AT 指令被保留了下来。

在嵌入式开发中,经常是使用 AT 命令去控制各种通讯模块,比如 WiFi 模块、蓝牙模块、GPRS 模块等等。一般就是主芯片通过硬件接口(比如串口、SPI)发送 AT 指令给通讯模块,模块接收到数据之后回应响应的数据。

3.3 常用的AT指令

AT 指令分为四种类型:

类型 格式 功能
测试指令 AT + < X > = ? 查询设置命令或内部程序设置的参数及其取值范围
查询指令 AT + < X > ? 返回参数的当前值
设置指令 AT + < X > = < ... > 设置用户自定义的参数值
执行指令 AT + < X > 执行受模块内部程序控制的变参数不可变

蓝牙模块的 AT 指令相较于 ESP8266 要少非常多,后者有近百条。现在举例一些常用指令,并使用这些指令一步一步的通过串口实现蓝牙模块的收发数据。

序号 AT指令(小写 x 表示参数) 作用 默认状态 主/从生效
1 AT 检测串口是否正常工作 - M/S
2 AT+RX 查看模块基本参数 - M/S
3 AT+DEFAULT 恢复出厂设置 - M/S
4 AT+RESET 模块重启 - M/S
5 AT+VERSION 获取模块版本、 日期 - M/S
6 AT+ROLE=x 主/从角色切换 S M/S
7 AT+NAME=xxx 修改蓝牙名称 HC-08 M/S
8 AT+ADDR=xxxxxxxxxxxx 修改蓝牙地址 硬件地址 M/S
9 AT+RFPM=x 更改无线射频功率 0(4dBm) M/S
10 AT+BAUD=xx,y 修改串口波特率 9600,N M/S
11 AT+CONT=x 是否可连接 0(可连) M/S
12 AT+AVDA=xxx 更改广播数据 - S
13 AT+MODE=x 更改功耗模式 0 S
14 AT+AINT=xx 更改广播间隔 320 M/S
15 AT+CINT=xx,yy 更改连接间隔 6,12 M/S
16 AT+CTOUT=xx 更改连接超时时间 200 M/S
17 AT+CLEAR 主机清除已记录的从机地址 - M
18 AT+LED=x LED 开/关 1 M/S
19 AT+LUUID=xxxx 搜索 UUID FFF0 M/S
20 AT+SUUID=xxxx 服务 UUID FFE0 M/S
21 AT+TUUID=xxxx 透传数据 UUID FFE1 M/S
22 AT+AUST=x 设置自动进入睡眠的时间 20 S

常用AT指令说明

请注意,只有当蓝牙模块未连接上主/从机,通过串口发送的数据才会被识别为 AT 指令。否则一旦连接上主/从机,则发送的字符串则被视为普通数据,直接透传给对方。

当模块连接上 MCU 之后,我们不知道模块是否连接到位、是否有虚连、模块是否正常工作,我们可以发送 AT 这条指令进行测试,如果接收到 OK 响应,则代表模块一切正常,可以进行后续的操作了。

节能模式说明:

一级节能模式是模块最主要的低功耗模式,可为透传提供低功耗待机,也可以作为低功耗的广播数据;

二级节能模式是睡眠模式,在睡眠下时不可发现、不可连接,串口唤醒后可发现、可连接。

两种节能模式都可以通过串口发送 1 个字节以上的数据来唤醒,但唤醒后前面几个字节的数据可能会乱码。

使用指令关闭LED后再打开,需要重启蓝牙模块才能生效

3.4 通信示意图

4. 项目实战

4.1 硬件准备

本文使用的是 STM32F103C8T6 最小系统板,价格很便宜,普遍 5~8 元。

<img src="https://lxlinux.superbed.verylink.top/item/656d4d04c458853aef905452.jpg" style="zoom:50%;" />

ST-Link 是一种用于 STM32 微控制器的调试和编程工具,它可以通过 SWD 或 JTAG 接口与开发板进行通信。一般价格在 6~8 元左右。

<img src="https://lxlinux.superbed.verylink.top/item/65222a41c458853aefb2ce8a.jpg" style="zoom:50%;" />

这玩意儿大家应该非常熟悉了,通常我们用它来打印单片机 log。

当然,配合上位机(比如串口调试助手),我们也可以使用它对一些模组进行调试,比如:wifi模块、4G模组、蓝牙,等等。

当然价格也很便宜,普遍 5~8 元。

如果对这个工具使用不熟悉的小伙伴,可以阅读下文:

零基础快速上手STM32开发(手把手保姆级教程):https://www.lxlinux.net/e/stm32/stm32-quick-start-for-beginner.html

<img src="https://lxlinux.superbed.verylink.top/item/6523c525c458853aef551a73.jpg" style="zoom:67%;" />

本文使用的是 HC-08 蓝牙模块,价格普遍 5~20 元左右。

<img src="https://lxlinux.superbed.verylink.top/item/6576bf2ec458853aefd0c3b7.jpg" style="zoom: 25%;" />

4.2 PC串口助手调试

在项目开始前,我们需要使用 USB 转 TTL 工具对我们的蓝牙模块进行测试,确保蓝牙模块工作正常。

硬件接线如下表格所示:

HC-08 USB转TTL
RXD TXD
TXD RXD
GND GND
VCC 3V3

线路接好之后如下图所示:

线路接好之后,将 USB 转 TTL 工具插入电脑,在串口助手输入指令 AT ,模块正常情况下会返回 OK

<img src="https://lxlinux.superbed.verylink.top/item/6577c680c458853aef84dbf1.jpg" style="zoom: 50%;" />

接着我们输入 AT+VERSION ,获取蓝牙模块的版本信息,结果如下:

<img src="https://lxlinux.superbed.verylink.top/item/6577c72ec458853aef874003.jpg" style="zoom: 50%;" />

在使用串口调试蓝牙模块的过程中,有可能会出现波特率正常、驱动正常、蓝牙模块正常,且可以被手机连接上,但是输入 AT 指令,却没有返回的情况,出现这种情况可以试试换个串口助手。

4.3 硬件接线

蓝牙模块确认正常之后,我们就可以使用单片机通过编程的方式来操作蓝牙模块。

本文使用 串口2 连接蓝牙,串口1 连接 USB 转 TTL 来打印 log。

HC-08 STM32 USB转TTL
VCC 3.3V VCC
RXD A2
TXD A3
GND GND GND
A10 TXD
A9 RXD

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章 STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html

ST-Link V2 STM32
SWCLK SWCLK
SWDIO SWDIO
GND GND
3.3V 3V3

接好之后像这样,我这里使用了面包板,用公对母的杜邦线将他们串在了一起

4.4 蓝牙收发代码编写

蓝牙模块通过串口与 MCU 进行通讯,所以第一步需要先做好串口的配置。

关于串口的配置,我写过一篇文章手把手教你玩串口,大家可以移步下文查看:

STM32串口接收不定长数据(接收中断+超时判断):https://www.lxlinux.net/e/stm32/stm32-usart-receive-data-using-rxne-time-out.html

具体代码如下:

uint8_t bt_uart_rx_buf[BT_RX_BUF_SIZE];
uint8_t bt_uart_tx_buf[BT_TX_BUF_SIZE];
uint16_t bt_uart_rx_len = 0;

void bt_init(uint32_t baudrate)
{
    bt_uart_handle.Instance          = BT_INTERFACE;                 /* BT */
    bt_uart_handle.Init.BaudRate     = baudrate;                     /* 波特率 */
    bt_uart_handle.Init.WordLength   = UART_WORDLENGTH_8B;           /* 数据位 */
    bt_uart_handle.Init.StopBits     = UART_STOPBITS_1;              /* 停止位 */
    bt_uart_handle.Init.Parity       = UART_PARITY_NONE;             /* 校验位 */
    bt_uart_handle.Init.Mode         = UART_MODE_TX_RX;              /* 收发模式 */
    bt_uart_handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;          /* 无硬件流控 */
    bt_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;         /* 过采样 */
    HAL_UART_Init(&bt_uart_handle);                                  /* 使能BT */
}

void bt_rx_clear(void)
{
    memset(bt_uart_rx_buf, 0, sizeof(bt_uart_rx_buf));              //清空接收缓冲区
    bt_uart_rx_len = 0;                                             //接收计数器清零
}

void BT_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&bt_uart_handle, UART_FLAG_RXNE) != RESET){      //获取接收RXNE标志位是否被置位
        if(bt_uart_rx_len >= sizeof(bt_uart_rx_buf))                        //如果接收的字符数大于接收缓冲区大小,
            bt_uart_rx_len = 0;                                             //则将接收计数器清零
        HAL_UART_Receive(&bt_uart_handle, &receive_data, 1, 1000);          //接收一个字符
        bt_uart_rx_buf[bt_uart_rx_len++] = receive_data;                    //将接收到的字符保存在接收缓冲区
    }

    if (__HAL_UART_GET_FLAG(&bt_uart_handle, UART_FLAG_IDLE) != RESET)      //获取接收空闲中断标志位是否被置位
    {
        printf("recv: %s\r\n", bt_uart_rx_buf);                             //将接收到的数据打印出来
        bt_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&bt_uart_handle);                         //清除UART总线空闲中断
    }
}

通过这几个函数,我们就可以读取蓝牙返回的数据,并保存在数组 bt_uart_rx_buf 里。

如果需要通过串口向蓝牙模块发送数据,可以使用下面函数:

void bt_send(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    
    va_start(ap, fmt);
    vsprintf((char *)bt_uart_tx_buf, fmt, ap);
    va_end(ap);
    
    len = strlen((const char *)bt_uart_tx_buf);
    HAL_UART_Transmit(&bt_uart_handle, bt_uart_tx_buf, len, HAL_MAX_DELAY);
}

至此,蓝牙模块的初始化、发送、接收部分就做好了。

在 main 函数里,我们可以先调用 bt_init() 函数进行初始化,然后调用 bt_send() 函数发送数据,如下:

int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟,72M */
    delay_init(72);                             /* 初始化延时函数 */
    usart_init(115200);                         /* 串口1波特率设为115200 */
    bt_init(9600);                              /* 串口2波特率设为9600 */

    printf("蓝牙实验……\r\n");

    while(1)
    {
        bt_send("bt send\r\n");
        delay_ms(1000);
    }
}

4.5 通过手机蓝牙助手发送数据到电脑的串口助手

接着我们打开电脑串口软件。设置串口助手波特率 115200 (你们不一定要用我这款,随便的串口助手都可以),选择串口号,最后打开串口开始准备接收数据。

这个串口工具接收的是 MCU 串口 1 的数据,也就是 log 。蓝牙接收到数据后,我们使用串口 1 打印到下面的串口助手里。

<img src="https://lxlinux.superbed.verylink.top/item/6577caedc458853aef93c636.jpg" style="zoom:50%;" />

然后打开手机蓝牙助手准备开始调试,点击蓝牙模块开始连接。没有蓝牙助手的同学,可以在前文找到下载地址。

<img src="https://lxlinux.superbed.verylink.top/item/6577cbd2c458853aef969a92.jpg" style="zoom:33%;" />

<img src="https://lxlinux.superbed.verylink.top/item/6577cc42c458853aef980238.jpg" style="zoom:33%;" />

到这里,我们就完成了 MCU 通过蓝牙将数据透传到手机 APP (蓝牙助手)。

当然,我们也可以通过手机 APP 向蓝牙发送数据,MCU 接收到透传的数据之后通过串口助手打印在电脑上。比如我们给蓝牙模块发送数据 111 、aaa 、123123。

<img src="https://lxlinux.superbed.verylink.top/item/6577cdfdc458853aef9e08c0.jpg" style="zoom:50%;" />

可以看到串口助手成功接收到 111 、aaa 、123123,这些数据。

<img src="https://lxlinux.superbed.verylink.top/item/6577ce1ec458853aef9e6ba0.jpg" style="zoom:50%;" />

到此,蓝牙模块的调试就完成了。

5. 小结

通过学习和实践,希望大家都能够了解并掌握蓝牙模块的使用方法,从而更好地应用于嵌入式开发。无论是智能小车还是开发物联网设备,蓝牙模块都能成为您的得力助手,让我们一起玩转蓝牙模块吧!

另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。

刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

欢迎关注我的博客:良许嵌入式教程网,满满都是干货!

上一篇下一篇

猜你喜欢

热点阅读