本文基于pc-ble-driver v4.1.1,介绍如何在Windows上搭建开发环境。
以前写过一个入门教程(链接),最近的版本更新改动很大,那篇文章中介绍的方法已经过时。我仍然建议预先读它,然后再看本文。
pc-ble-driver是什么
它是一个PC端的BLE开发平台。

我们在开发板中烧录一个中间层固件,通过PC给固件发指令,与外部BLE设备(比如手机或一个BLE从设备)进行通信。
PC端可以用C/C++、Python、Javascript 语言进行编程。本文介绍的方案是基于C语言。
pc-ble-driver 部署在github中,可以从该页面获得它的全部信息。
生成静态库文件
首先要安装Visual Studio 2019,它有多个开发语言,我们这里只需要C++。
安装好以后,我们能够打开VS的项目文件(.sln)和工程文件(.vcxproj),同时也得到了一个编译工具MSBuild.exe,它的路径应该在:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe
然后安装cmake工具。
下载pc-ble-driver的源文件:https://github.com/NordicSemiconductor/pc-ble-driver/releases
页面中有多个选项:
- nrf-ble-driver-4.1.1-win_x86_32.zip
- nrf-ble-driver-4.1.1-win_x86_64.zip
- Source code (zip)
- Source code (tar.gz)
需要下载Source Code (zip)那一项。
将源文件解压到一个开发目录下,我这里是:C:\repo\pc-ble-driver-repos\pbd
开始之前需要明确我们要干什么!
pc-ble-driver 在PC端实现了一个库,这个库可以调用softdevice,实现BLE的功能。我们写的代码直接调用这个库文件暴露的接口。
在上面的下载页面,下载nrf-ble-driver-4.1.1-win_x86_64.zip文件,里面就包含了这个库,理想情况是我们能够拿它直接使用,但奇怪的是我这里使用它的库会报错。无奈只能自己生成一个库来用。
所以我们的目标是,编译源文件,生成一个静态库文件(.lib)。
下载必要的第三方VC库:
- asio
- catch2 (只有一个catch.hpp文件)
- spdlog
将它们放在目录:C:\repo\pc-ble-driver-repos\pbd\ext
注意,官方页面上使用vcpkg来下载它们,还要设置一堆环境变量,把问题复杂化,这里我们直接下需要的库,不管vcpkg。
在pbd下面创建一个build文件夹: C:\repo\pc-ble-driver-repos\pbd\build。打开cmd窗口,cd到该文件夹,然后执行:
cmake -DASIO_INCLUDE_DIR=C:\repo\pc-ble-driver-repos\source\ext\asio-1.12.2\include -DCatch2_DIR=C:\repo\pc-ble-driver-repos\source\ext\catch-2.10.0 -DCONNECTIVITY_VERSION=4.1.1 -DNRF_BLE_DRIVER_VERSION=6.1.1 -G "Visual Studio 16 2019" -A Win32 ..
值得看一下各个参数:
- -DXXX表示增加一个变量,也可以通过设置环境变量的方式进行(有坑,不推荐)
- CONNECTIVITY_VERSION和NRF_BLE_DRIVER_VERISON 按实际版本进行配置,因为可能过几天又有新版本了
- -G “Visual Studio 16 2019″,这个跟官方页面上的-G Ninja不同,我发现用Ninja有坑
- -A Win32表示生成Win32的库,可选项还包括:x64, ARM, ARM64。(链接)如果这里使用了Win32,后面创建VS工程时候,也得使用Win32。
命令执行完毕,会在build下生成大量文件,我们关心的是:项目文件(nrf-ble-driver.sln) 和好几个工程文件(*.vcxproj)。
这时候可以双击打开sln项目文件,或者用命令:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" nrf-ble-driver.sln
编译完毕,在pbd\build\Debug目录下就能看到多个lib文件,找到:nrf-ble-driver-sd_api_v6-mt-static-gd-6_1_1.lib,它就是我们生成的静态库文件,后面我们利用它来编写代码。
搭建开发环境
在C:\repo\pc-ble-driver-repos目录下新建几个目录:
- include
- lib
- project\hrs和project\hrs_c
- hex
将pbd\include文件夹下的东西复制到这个include中。其实只复制common和sd_api_v6两个文件夹即可。
将刚才生成的 nrf-ble-driver-sd_api_v6-mt-static-gd-6_1_1.lib 复制到lib中。
将pbd\hex\sd_api_v6下的connectivity_4.1.1_1m_with_s132_6.1.1.hex和connectivity_4.1.1_1m_with_s140_6.1.1.hex复制到hex中,二者分别用于nRF52832和nRF52840芯片。
project\hrs用于放HRS示例工程,project\hrs_c用于放HRS_C示例工程。将 pbd\examples\heart_rate_monitor\main.c 复制到hrs目录下,将 pbd\examples\heart_rate_collector\main.c 复制到hrs_c目录下。
下面介绍如何制作一个HRS工程。
在Visual Studio 2019中,新建一个空白工程,执行以下操作:
先添加main.c到工程。
在工程设置C/C++ -> Additional Include Directories中,添加
- C:\repo\pc-ble-driver-repos\include\sd_api_v6
- C:\repo\pc-ble-driver-repos\include\common
- C:\repo\pc-ble-driver-repos\include\common\config
- C:\repo\pc-ble-driver-repos\include\common\internal
- C:\repo\pc-ble-driver-repos\include\common\internal\transport
- C:\repo\pc-ble-driver-repos\include\common\sdk_compat
C/C++ -> Compile AS设置为Compile As C Code。
C/C++ -> Precompiled Header File设置为Not Using Precompiled Headers
C/C++ -> Process Definitions添加:
- WIN32
- _WINDOWS
- NRF_SD_BLE_API=6
- _WIN32_WINNT=0x0502
- NOMINMAX
- ASIO_STANDALONE
- SD_RPC_EXPORTS
- HCI_LINK_CONTROL
- _CRT_SECURE_NO_WARNINGS
- PC_BLE_DRIVER_STATIC
- CMAKE_INTDIR=”Debug”
- _DEBUG
- _CONSOLE
Linker -> Additional Dependencies添加:C:\repo\pc-ble-driver-repos\lib\nrf-ble-driver-sd_api_v6-mt-static-gd-6_1_1.lib
Linker -> Generate Debug Info改成:Debug Information optimized for faster links (/DEBUG:FASTLINK)
保存好后打开main.c,按F7编译一下,如果不报错就说明一切完好,可以连上开发板测试了。
hrs_c工程设置过程与之一模一样。
可以从这里下载我配置好的工程作为参考:https://gitee.com/isyq/pc-ble-driver-demo
测试HRS工程
准备一个52开发板,连上电脑。擦除并烧录C:\repo\pc-ble-driver-repos\hex\connectivity_4.1.1_1m_with_s132_6.1.1.hex
查看开发板的串口号,比如是COM58,那么在main.c中,找到DEFAULT_UART_PORT_NAME定义,将其修改为COM58。
然后在VS中按F5进行调试,就会打开有一个cmd窗口,通过打印的内容可以看到它正在广播,如下:

这时候用手机与它连接,发现可以连接但是无法正常发现服务。这是因为这个main.c没有处理Data Length Update事件,导致超时断开。
解决办法是,找到ble_evt_dispatch()函数,增加处理该事件,代码如下:
case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
{
ble_gap_data_length_params_t dl_params;
memset(&dl_params, 0, sizeof(ble_gap_data_length_params_t));
err_code = sd_ble_gap_data_length_update(adapter, p_ble_evt->evt.gap_evt.conn_handle,
&dl_params, NULL);
if (err_code != NRF_SUCCESS)
{
printf("Data len update error: %x\n", err_code);
fflush(stdout);
}
} break;
然后手机就可以跟它进行连接和通信了。
值得注意的是,pc-ble-driver与nRF5 SDK 同根同源,这个版本直接使用SDK 15.3的softdevice,但是二者的编程模型不同,SDK 中使用了大量的XXX_DEF 和XXX_OBSERVER 的编程模型,许多BLE库也都是基于这个实现的,在pc-ble-driver中则完全无法使用,所有的扫描、连接、发现操作都得用最原始的API去实现,给使用带来了不少难度。
另外,pc-ble-driver 与PC 之间使用串口进行通信,尽管采用了1M的比特率,但是仍然不同于单芯片方案,有诸多限制。pc-ble-driver 不支持data length extension, data length只能使用27, 意味着它的通信速度跑不起来。
(完)
大神你好,想请教你一个问题。我用了你的这个demo,但是VS调试的时候出现一个错误,返回的错误值是0x0D(13),请问这是个什么错误。。在你的代码里有error_code的信息吗
Serial port used: COM4
Baud rate used: 1000000
Info: Successfully opened COM4. Baud rate: 1000000. Flow control: none. Parity: none.
Status: 6, message: Target Reset performed
Status: 0, message: No response from device. Tried to send packet 6 times.
Failed to open nRF BLE Driver. Error code: 0x0D
F:\Study\pc-ble-driver\isyq-pc-ble-driver-demo-master\pc-ble-driver-demo\project\hrs\Debug\hrs.exe (进程 2724)已退出,返回代码为: 13。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口…
报错说串口上没有响应,估计是串口速度不够。这个程序用1M的串口,DK板子上的JLink芯片串口速度达不到,你得用个USB-UART的转换头连到IO上通信。