本文将和大家一起编写我们的第一个BLE应用程序:Blinky(闪灯程序),哪怕你之前没有任何BLE开发经验,也不用担心,只要跟着文中所述步骤,你就可以一步步搭建自己的第一个BLE应用程序。通过这个Blinky程序的搭建,你将体会到BLE的一些基本概念,对BLE将会有一个非常直观的认识,为后续自己的BLE应用程序开发打下一个坚实的基础。
1. 开发准备
1) nRF52或者nRF51开发板1块。请参考“Nordic nRF51/nRF52开发流程说明”,购买相应开发板(DK)。
2) 开发环境搭建。简述如下(详细说明请参考“Nordic nRF51/nRF52开发环境搭建”):
- 安装Keil5 MDK
- 安装SDK。如果你使用的是nRF52开发板,请安装nRF5 SDK15.0.0,下载链接:https://www.nordicsemi.com/eng/nordic/download_resource/59012/70/52858981/116085。如果你手上是nRF51开发板,请下载nRF5 SDK12.3.0:https://www.nordicsemi.com/eng/nordic/download_resource/54280/56/38442131/32925 (nRF51最高SDK版本只能到12.3.0,后续SDK就不再支持nRF51了)
- 安装ARM CMSIS4.5.0,下载链接:https://github.com/ARM-software/CMSIS/releases/download/v4.5.0/ARM.CMSIS.4.5.0.pack。
- 安装Keil5 Device Family Pack,下载链接:https://www.nordicsemi.com/eng/nordic/download_resource/58865/28/26535159/87790。
- 安装nRF5 Command Line Tools,下载链接(Windows版):https://www.nordicsemi.com/eng/nordic/download_resource/58850/47/60411125/53210。
- 安装安卓版或者iOS版nRF connect。iOS版nRF connect请到苹果app store下载,搜索“nRF”即可以找到。安卓版nRF connect可以到Nordic Github官网上下载,下载链接为:https://github.com/NordicSemiconductor/Android-nRF-Connect/releases
- 安装PC版nRF connect或者nRFgo studio。PC版nRF connect下载链接(Windows版):https://www.nordicsemi.com/eng/nordic/download_resource/58847/15/21277021/108233。
注:如果你使用的是Linux系统/Mac系统,或者你使用的不是Keil5-MDK,请参考“Nordic nRF51/nRF52开发环境搭建”来搭建你的开发环境。
2. 运行Blinky程序
请按照如下步骤运行SDK自带的Blinky程序
1) 确认自己的芯片型号或者开发板。如果采用Nordic官方开发板的话,芯片型号和开发板编号对应关系如下:
- nRF51系列对应开发板编号为PCA10028
- nRF52832和nRF52810对应开发板编号为PCA10040
- nRF52840对应开发板编号为PCA10056
这里我会以nRF52832开发板PCA10040为例阐述整个开发过程,其他开发板与之类似,大家自己可以举一反三来开始自己的开发之旅。
2) 将开发板与PC机通过USB线相连,同时打开开发板电源(将左下角的拨位开关打到“ON”位置),打开桌面版nRF Connect,选择启动“Programmer”应用,由于驱动之前已经安装好了,设备可以立即识别成功。执行“full erase”操作,以擦除芯片原始内容。
3) 打开SDK中的Blinky程序。对于blinky程序,如果是52832开发板,请打开:nRF5_SDK_15.0.0_a53641a\examples\ble_peripheral\ble_app_blinky\pca10040\s132\arm5_no_packs;如果是51822开发板,请打开:nRF5_SDK_12.3.0_d7731ad\examples\ble_peripheral\experimental_ble_app_blinky\pca10028\s130\arm5_no_packs
后续将以52832开发板为例来阐述,51822与之类似就不再阐述了。
注:Nordic SDK例程目录结构为:SDK版本/ examples /协议角色/例子名称/开发板型号/协议栈型号/工具链类型/具体工程,比如下面例子:
Nordic每一个例子都支持5种工具链:Keil5/Keil4/IAR/GCC/SES,如下所示:
4) 编译上面的blinky程序。如果你已经按照之前的说明配置好了开发环境,那么这里编译是不会报任何错的。(如果你遇到了编译错误,请重新按照前面说明去搭建你的开发环境,不要怀疑SDK例子代码有问题哦)
5) 程序下载。程序下载包括2步:先下载softdevice,再下载应用。Softdevice是Nordic蓝牙协议栈的名称,整个开发过程中只需下载一次。应用就是我们这里的blinky程序。
- 蓝牙协议栈下载(整个开发周期只下载一次)。在Keil ‘select target’下拉列表中,默认选择的是Keil工程对应的Target,即‘nrf52832_xxaa’。我们还可以选择另一个target ‘flash_s132_nrf52_6.0.0_softdevice’,即softdevice对应的target,然后点击“下载download”(不需要编译哦!),此时会把softdevice下载到开发板中。
- 应用下载。重新选择Target:‘nrf52832_xxaa’,点击“下载Download”,此时会把Blinky程序下载到开发板中。此时开发板的LED1常亮,表示程序运行正常。
6) 打开手机蓝牙和手机版nRF connect。在nRF connect中,你将看到一个广播设备:Nordic_Blinky,这个就是我们的开发板。
7) 连接设备。点击“CONNECT”,手机将与设备建立连接,并开始服务发现过程,连接成功后,LED1熄灭,LED2点亮,最后将得到如下界面。
由上图可见,Blinky程序包含三个service:Generic Access(GAP),Generic Attribute(GATT),以及Nordic LED Button Service,GAP和GATT都是标准的蓝牙service,Nordic LED Button Service是Blinky程序自定义的service,它又具体包括两个characteristic:Button和LED。
8) 测试Blinky程序。点击右上角的“Enable CCCDs”以使能notification,如下:
按下开发板上的Button1按键,你会发现nRF connect中的Button characteristic Value会实时显示按键状态:pressed或者released。
点击nRF connect中的LED characteristic右边的向上箭头,选择“ON”并“SEND”,你会发现开发板的LED3将点亮;选择“OFF”并“SEND”,LED3又将熄灭。
3. 定制你的Blinky程序
3.1 修改广播名称
如前所述,Blinky程序默认的广播名字是:Nordic_Blinky,我们现在将其修改为“My_Blinky”,怎么做呢?我们在Keil中全文搜索“Nordic_Blinky”,发现有如下宏定义:
#define DEVICE_NAME "Nordic_Blinky"
我们只需将这里的Nordic_Blinky换成My_Blinky,即
#define DEVICE_NAME "My_Blinky"
就可以实现我们的目标了。重新编译下载blinky程序,在nRF connect中,你将看到:
你再全文搜索一下“DEVICE_NAME”,你会发现广播名字其实是通过如下API来完成修改的:
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
注:Keil的搜索功能非常好用,很多问题都可以通过它来解决
3.2 修改广播间隔
如nRF connect界面所示,blinky程序的广播间隔大概为40ms左右,现在为了节省功耗,我们将其改为200ms,通过搜索,我们可以看到如下宏定义:
#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
因此为了将广播间隔改为200ms,只需将APP_ADV_INTERVAL改成200/0.625 = 320,即
#define APP_ADV_INTERVAL 320
重新编译下载blinky程序,在nRF connect中,你将发现广播间隔已改为200ms了:
3.3 修改Button characteristic行为 (设备发数据给手机)
现在的Blinky程序,只有按下开发板的Button1时,nRF connect的Button characteristic 值才会更新。我们现在新增一个功能:当按下开发板的Button 2时,让Button characteristic value更新为5(注: nRF connect把1当成按键按下,把0当成按键释放,为了更直观,我们没有选择0或者1,而是随便选择一个值:5)。我们先找到Button1按下的回调函数,如下所示:
case LEDBUTTON_BUTTON: NRF_LOG_INFO("Send button state change."); err_code = ble_lbs_on_button_change(m_conn_handle, &m_lbs, button_action); if (err_code != NRF_SUCCESS && err_code != BLE_ERROR_INVALID_CONN_HANDLE && err_code != NRF_ERROR_INVALID_STATE && err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING) { APP_ERROR_CHECK(err_code); } break;
可以看出,我们是通过ble_lbs_on_button_change来更新Button characteristic的值的,ble_lbs_on_button_change具体函数实现如下所示:
uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state) { ble_gatts_hvx_params_t params; uint16_t len = sizeof(button_state); memset(¶ms, 0, sizeof(params)); params.type = BLE_GATT_HVX_NOTIFICATION; params.handle = p_lbs->button_char_handles.value_handle; params.p_data = &button_state; params.p_len = &len; return sd_ble_gatts_hvx(conn_handle, ¶ms); }
我们可以仿照Button1的做法,来添加Button2的代码。首先初始化app_button模块,让button2按下事件可以被button_event_handler捕获,如下:
static app_button_cfg_t buttons[] = { {LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler}, {BSP_BUTTON_1, false, BUTTON_PULL, button_event_handler} };
然后在button_event_handler调用ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val),以更新Button characteristic的值,代码如下所示:
case BSP_BUTTON_1: NRF_LOG_INFO("Button2 pressed."); ble_button2_send(m_conn_handle, &m_lbs, 5); break;
ble_button2_send(m_conn_handle, &m_lbs, 5)实现代码如下所示:
uint32_t ble_button2_send(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t val) { ble_gatts_hvx_params_t params; uint16_t len = sizeof(val); memset(¶ms, 0, sizeof(params)); params.type = BLE_GATT_HVX_NOTIFICATION; params.handle = p_lbs->button_char_handles.value_handle; //Button characteristic value handle params.p_data = &val; params.p_len = &len; return sd_ble_gatts_hvx(conn_handle, ¶ms); }
重新编译下载blinky程序,连接设备,使能cccd,按下Button2,你会看到Button characteristic的值变为5:
3.4 修改LED characteristic行为(手机发数据给设备)
由于nRF connect把LED characteristic的值写死了,只能发送“ON”或者“OFF”,前面也测试过,发送“ON”之后,LED3将点亮,其实这里的“ON”,就是数值1。我们现在增加一个新的功能:在收到“ON”命令后,把LED4 toggle一下。
这个实现起来比较简单,我们只需在led_write_handler中添加bsp_board_led_invert(BSP_BOARD_LED_3),整体代码如下所示:
static void led_write_handler(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t led_state) { if (led_state) { bsp_board_led_on(LEDBUTTON_LED); NRF_LOG_INFO("Received LED ON!"); bsp_board_led_invert(BSP_BOARD_LED_3); } else { bsp_board_led_off(LEDBUTTON_LED); NRF_LOG_INFO("Received LED OFF!"); } }
重新编译下载blinky程序,连接设备,你会发现第一次发送“ON”,LED4点亮,第二次发送“ON”,LED4又将熄灭。
通过全文搜索“led_write_handler”,你会发现这个函数是被ble_lbs.c中的on_write调用,而on_write又被ble_lbs_on_ble_evt调用,而ble_lbs_on_ble_evt就是我们的BLE事件回调函数,每当softdevice收到LED characteristic的写操作时,都会调用它,这就是通过nRF connect操作设备的过程和原理。
这篇文章主要让大家对BLE有个大概的认识,后面我会专门写一篇文章来介绍上面提到的BLE service,characteristic,write,notify以及CCCD等,以帮助大家深刻理解这些概念。
原文地址:https://www.cnblogs.com/iini/p/8996025.html