Zephyr nRF52840开发

1. 开发环境和硬件平台

开发环境:

​ Ubuntu 18.04 + Zephyr‘s SDK and Tools

硬件平台:

​ PCA10056 DK (nRF52840)

2. 运行 Project

2.1 打开终端,运行 zephyr-env.sh

cd ~/git/zephyr/
source ./zephyr-env.sh

有时候会打开多个终端,每个终端都需要 source zephyr-env.sh , 这样比较繁琐。我们把该命令加入到 zshrc 或者 bashrc 中即可。

2.2 创建 build 文件夹

cd sample/bluetooth/peripheral
mkdir -p build/nrf52 && cd build/nrf52                # 创建文件夹

2.3 生成构建系统

cmake -GNinja -DBOARD=nrf52840_pca10056 ../..         # 利用 cmake 自动生成 build 系统。 依赖 CMakeLists.txt ,最后路径是当前目录与 CMakeLists.txt 的相对路径

如果出问题,请在检查:

  1. 在当前终端运行 source zephyr-env.sh
  2. 检查路径 ../.. 是否对

2.4 构建Build

ninja                                                 # ninja 或者 make             
ninja flash                                           # 烧录代码

2.5 验证

使用 nRF connect (Android) 可以观察到

设备名 Zephyr Peripheral Sample Long

复位重启硬件会发现MAC地址在变更。第一次: 44:3A:6B:C6:30:9A ; 第二次: 5C:0A:1D:CE:2D:38

3. Zephyr BLE 主流程

  1. bt_enable(bt_ready) 当初始化完成,调用bt_ready,在bt_ready中进行 service初始化,开启广播。

  2. bt_conn_cb_register 注册连接和断连的回调函数,我们可以在回调函数中处理相关事件。

    conn_callbacks = { .connected = connected, .disconnected = disconnected};

    static void connected(struct bt_conn *conn, u8_t err){ printk("Connected\n");}
    static void disconnected(struct bt_conn *conn, u8_t reason){ printk("Disconnected\n");}
    
  3. bt_conn_auth_cb_register(&auth_cb_display)

Created with Raphaël 2.2.0 开始 bt_enable(bt_ready) bt_conn_cb_register(&conn_callbacks) bt_conn_auth_cb_register(&auth_cb_display) End

4. bt_ready() 处理任务

在 bt_ready 函数里,可以初始化所需要的 service, 例如 BASDIS 或者自定义 service

Created with Raphaël 2.2.0 开始 bas_init() dis_int(CONFIG_SOC,"Manufacturer") 其他 gatt service 注册 End

5. 修改设备名

在 prj.conf 中修改设备名

CONFIG_BT_DEVICE_NAME="BLE_Zephyr"  # 设置设备名
# CONFIG_BT_DEVICE_NAME_DYNAMIC=y     # 注释掉该配置信息,取消动态设备名

6. 固定设备MAC

在 prj.conf 中修改

# CONFIG_BT_PRIVACY=y                  # 注释掉该配置信息,取消动态 MAC 地址

7. 广播参数修改

广播间隔,可否连接,显示设备名。

默认设备名是放在扫描响应包里。

// 在 bt_ready() 函数上方定义广播参数
#define BT_GAP_ADV_FAST_INT_MIN_3   0x00f0
#define BT_GAP_ADV_FAST_INT_MAX_3   0x00f0
#define BT_LE_ADV_CONN_NAME1  BT_LE_ADV_PARAM( BT_LE_OPT_CONNECTABLE  | \
                              BT_LE_ADV_OPT_USE_NAME,  \
                              BT_GAP_ADV_FAST_INT_MIN_2, \ //0x00a0=160 160*0.625=100ms
                              BT_GAP_ADV_FAST_INT_MAX_2)   //0x00f0=240 240*0.625=150ms
// 在 bt_ready() 函数中修改参数
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME1, ad, ARRAY_SIZE(ad), NULL, 0);
// ad   advertising data
// sd   scan response data

编译 & 烧录

ninja 
ninja flash

可以验证广播连接间隔变成了 150ms 左右。

8. Service 修改

8.1 gatt_attr 结构体赋值

static struct bt_gatt_attr vnd_attrs[] = {
    BT_GATT_PRIMARY_SERVICE(&vnd_uuid),
    BT_GATT_CHARACTERISTIC(&vnd_uuid.uuid,
    			BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE |
    			BT_GATT_CHRC_INDICATE,
    			BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
    			read_vnd, write_vnd, vnd_value),
    BT_GATT_CCC(vnd_ccc_cfg, vnd_ccc_cfg_changed),
}

8.2 gatt_service 结构体赋值

static struct bt_gatt_service vnd_svc = BT_GATT_SERVICE(vnd_attrs);

8.3 在 bt_ready 中注册 service

bt_gatt_service_register(&vnd_svc);

8.4 gatt_attr 结构体内容详解

8.4.1 Primary Service UUID

必须有该项

/* Custom Service Variables */
static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128(
        0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
        0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
BT_GATT_PRIMARY_SERVICE(&vnd_uuid)
8.4.2 Characteristic UUID

如果有多个特性,需要多个UUID

static struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128(
        0xf1, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
        0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
8.4.3 Notification or Indication characteristic

ccc 启动。

static struct bt_gatt_ccc_cfg blvl_ccc_cfg[BT_GATT_CCC_MAX] = {};
static void blvl_ccc_cfg_chaged(const struct bt_gatt_attr *attr, u16_t value){
    simulate_blvl = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
}
BT_GATT_CCC(blvl_ccc_cfg, blvl_ccc_cfg_changed);


// process
void bas_nofity()
{
    if (!simulate_blvl) {
        return;
    }
    
    battery--;
    if (!battery) {
        battery = 0;
    }
    // attrs[0] = primary service
    bt_gatt_notify(NULL, &attrs[1], &battery, sizeof(battery));
}

9. 配对

iOS 配对有问题,暂时不使用

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是nrf52840按键控制流水灯的代码实现: ```c #include <zephyr.h> #include <device.h> #include <devicetree.h> #include <drivers/gpio.h> #define LED0_NODE DT_ALIAS(led0) #define LED0 DT_GPIO_LABEL(LED0_NODE, gpios) #define PIN0 DT_GPIO_PIN(LED0_NODE, gpios) #define FLAGS0 DT_GPIO_FLAGS(LED0_NODE, gpios) #define LED1_NODE DT_ALIAS(led1) #define LED1 DT_GPIO_LABEL(LED1_NODE, gpios) #define PIN1 DT_GPIO_PIN(LED1_NODE, gpios) #define FLAGS1 DT_GPIO_FLAGS(LED1_NODE, gpios) #define SW0_NODE DT_ALIAS(sw0) #define SW0 DT_GPIO_LABEL(SW0_NODE, gpios) #define PIN_SW0 DT_GPIO_PIN(SW0_NODE, gpios) #define FLAGS_SW0 DT_GPIO_FLAGS(SW0_NODE, gpios) #define SLEEP_TIME_MS 100 void main(void) { const struct device *dev_led0; const struct device *dev_led1; const struct device *dev_sw0; bool led0_is_on = true; bool led1_is_on = false; bool sw0_is_pressed = false; dev_led0 = device_get_binding(LED0); dev_led1 = device_get_binding(LED1); dev_sw0 = device_get_binding(SW0); gpio_pin_configure(dev_led0, PIN0, GPIO_OUTPUT_ACTIVE | FLAGS0); gpio_pin_configure(dev_led1, PIN1, GPIO_OUTPUT_ACTIVE | FLAGS1); gpio_pin_configure(dev_sw0, PIN_SW0, GPIO_INPUT | FLAGS_SW0); while (1) { gpio_pin_set(dev_led0, PIN0, (int)led0_is_on); gpio_pin_set(dev_led1, PIN1, (int)led1_is_on); sw0_is_pressed = !gpio_pin_get(dev_sw0, PIN_SW0); if (sw0_is_pressed) { led0_is_on = !led0_is_on; led1_is_on = !led1_is_on; k_msleep(SLEEP_TIME_MS); } } } ``` 该代码使用了Zephyr RTOS,通过按下nrf52840开发板上的按键,可以控制两个LED灯的状态,从而实现流水灯的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值