目录
Ubuntu 系统使用 ESP32 作为蓝牙 adapter (适配器)
蓝牙可以通过 HCI 将 HOST 部分与 Controller 部分进行连接。
这篇文章说明了如何使用 ESP32-IDF 中包含的蓝牙示例应用程序 controller_hci_uart 通过主机控制器接口(Host Controller Interface)与 ESP32 蓝牙 controller 进行连接和通信。使用任何操作系统(Mac,Linux或Windows)的电脑都可以来编译此工程。
在此示例中使用的 Host 是 BlueZ 蓝牙协议栈。由于 BlueZ 是用于基于 Linux 内核的操作系统系列的蓝牙协议栈,因此本示例需要在一台运行 Linux OS 且安装了 BlueZ 的计算机与 ESP32 开发板进行通讯。
主机控制器接口(Host Controller Interface)可以使用 UART
连接 BlueZ
和 ESP32
蓝牙的 controller
。
使用 uart 串口作为 hci 接口
方法一:外部串口链接 uart
对应管脚
串口 | ESP32 |
---|---|
Tx | GPIO 18 (Rx) |
Rx | GPIO 05 (Tx) |
CTS | GPIO 19 (RTS) |
RTS | GPIO 22 (CTS) |
- 如果不使用硬件流控,
RTS
和CTS
引脚设置可以写-1
使用下面代码设置串口引脚
uart_set_pin(HCI_UART_PORT, HCI_UART_TXD, HCI_UART_RXD, HCI_UART_RTS, HCI_UART_CTS)
默认的波特率为 921600
方法二:使用自带的 USB 转 uart 接口作为 hci 接口
使用其他引脚作为串口链接到电脑需要额外链接一个串口设备,增加了成本还比较麻烦,所以我还考虑了使用 ESP 默认使用的 USB
串口,作为蓝牙链接串口的方案。
但是由于 UART0
是默认配置的串口,用作系统信息的打印,所以默认没有打开作为 HCI 串口的选项,这里我们可以通过修改 esp_bt_controller_config
来设置 hci 使用串口 0
。
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
/* set hci use uart number*/
bt_cfg.hci_uart_no = HCI_UART_PORT;
同样由于 UART0
是系统信息打印的串口,引脚(TX->GPIO1
,RX->GPIO3
)已经默认配置好了,不需要再次设置引脚。但是 ESP32 DevKitC
的 USB
转 UART
没有接 RTS
和 CTS
,所以需要使用 uart_set_hw_flow_ctrl
关闭硬件流控。
如果使用 uart_set_sw_flow_ctrl
开启软件流控,需要修改 XON
和 XOFF
的值,有些数据会被软件流控截断,不建议使用。
使用 Ubuntu 系统连接 ESP32 蓝牙适配器
将串口链接到电脑上,会出现对应串口的设备。如: /dev/ttyUSB1
- 将串行设备 (serial devices) 连接到 BlueZ 蓝牙协议栈
sudo btattach -B /dev/ttyUSB1 -S 921600
可以添加 -N 关闭 BlueZ 的硬件流控
sudo btattach -N -B /dev/ttyUSB1 -S 921600
成功执行后会显示配置信息和连接设备的编号(index)
Attaching Primary controller to /dev/ttyUSB0
Switched line discipline from 0 to 15
Device index 1 attached
注意:这个窗口不要关闭!
到这里,系统就已经连接了 ESP32 的 adapter ,可以在系统设置中找到蓝牙选项卡,并且使用系统中的蓝牙功能了。
~~~
测试命令
我们还可以使用以下命令行工具进行调试。
- 使用 BlueZ 管理工具 btmgmt
btmgmt: - A command-line interface of BlueZ for management Usage:
根据 btattach
连接上设备的 index
,使用下面命令连接设备。
sudo btmgmt --index 1
power on 打开电源
find 搜索设备
stop-find 停止搜索
power off 关闭电源
示例:
$ sudo btmgmt --index 1
[hci1]# power on
hci1 Set Powered complete, settings: powered bondable ssp br/edr le secure-conn
[hci1]# find
Discovery started
hci1 type 7 discovering on
hci1 dev_found: 6F:E6:68:BD:41:05 type LE Random rssi -94 flags 0x0000
AD flags 0x1a
eir_len 18
hci1 dev_found: 0C:E9:99:CE:F5:7D type LE Random rssi -69 flags 0x0004
AD flags 0x00
eir_len 31
[hci1]# stop-find
Discovery stopped
hci1 type 7 discovering off
[hci1]# power off
hci1 Set Powered complete, settings: bondable ssp br/edr le secure-conn
hci1 class of device changed: 0x000000
[hci1]#
代码
#include <stdio.h>
#include <string.h>
#include "nvs_flash.h"
#include "esp_bt.h"
#include "soc/uhci_periph.h"
#include "driver/uart.h"
#include "driver/periph_ctrl.h"
#include "esp_log.h"
static const char *tag = "CONTROLLER_UART_HCI";
#define HCI_UART_PORT (0)
#define BUF_SIZE (1024*4)
#if HCI_UART_PORT == 0
#define HCI_UART_TXD (1)
#define HCI_UART_RXD (3)
#define HCI_UART_RTS (-1)
#define HCI_UART_CTS (-1)
#elif HCI_UART_PORT == 1
#define HCI_UART_TXD (5)
#define HCI_UART_RXD (18)
#define HCI_UART_RTS (19)
#define HCI_UART_CTS (23)
#endif
void reconfig_hci_uart()
{
/* Configure parameters of an UART driver,
* communication pins and install the driver */
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
int intr_alloc_flags = 0;
ESP_ERROR_CHECK(uart_driver_delete(HCI_UART_PORT));
ESP_ERROR_CHECK(uart_driver_install(HCI_UART_PORT, BUF_SIZE, 0, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(HCI_UART_PORT, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(HCI_UART_PORT, HCI_UART_TXD, HCI_UART_RXD, HCI_UART_RTS, HCI_UART_CTS));
#if ((HCI_UART_RTS == -1) || (HCI_UART_CTS == -1))
ESP_ERROR_CHECK(uart_set_hw_flow_ctrl(HCI_UART_PORT, UART_HW_FLOWCTRL_DISABLE, UART_FIFO_LEN - 8));
#endif
}
void app_main(void)
{
esp_err_t ret;
/* Initialize NVS — it is used to store PHY calibration data */
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
// HCI_UART_PORT == 0 had been enabled
#if HCI_UART_PORT == 1
periph_module_enable(PERIPH_UART1_MODULE);
#elif HCI_UART_PORT == 2
periph_module_enable(PERIPH_UART2_MODULE);
#endif
periph_module_enable(PERIPH_UHCI0_MODULE);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
/* Set the uart number used by hci*/
bt_cfg.hci_uart_no = HCI_UART_PORT;
ret = esp_bt_controller_init(&bt_cfg);
if (ret != ESP_OK) {
ESP_LOGE(tag, "Bluetooth Controller initialize failed: %s", esp_err_to_name(ret));
return;
}
reconfig_hci_uart();
ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (ret != ESP_OK) {
ESP_LOGE(tag, "Bluetooth Controller initialize failed: %s", esp_err_to_name(ret));
return;
}
}