NRF52832学习笔记(36)——iBeacon

一、简介

NRF52832学习笔记(36)——iBeacon

iBeacon 是苹果公司2013年9月发布的移动设备用 OS(iOS7)上配备的新功能。其工作方式是,配备有 **低功耗蓝牙(BLE)**通信功能的设备使用 BLE 技术向周围发送自己特有的 ID,接收到该 ID 的应用软件会根据该 ID 采取一些行动。比如,在店铺里设置 iBeacon 通信模块的话,便可让 iPhone 和 iPad 上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。此外,还可以在家电发生故障或停止工作时使用 iBeacon 向应用软件发送资讯。

二、iBeacon格式

iBeacon 使用的是 BLE 技术,具体而言,利用的是 BLE 中名为“通告帧”(Advertising)的广播帧。通告帧是定期发送的帧,只要是支持 BLE 的设备就可以接收到。iBeacon 通过在这种通告帧的有效负载部分嵌入苹果自主格式的数据来实现。

AD Field Length Type Company ID iBeacon Type iBeacon Length UUID Major Minor TX Power

AD Field Length: Advertisement Data 的长度,表示有用的广播信息长度
Type: 广播类型
Company ID: 数据字段以两字节的公司 ID 码开始。SIG 将这些 ID 码发放给公司,其中 0x004C 代表的是Apple id(只有这个 ID,设备才会叫 iBeacon)
iBeacon Type: 字节 0x02 代表这个设备是 Beacon
iBeacon Length: 剩下字段的长度
UUID: 规定为 ISO/IEC11578:1996 标准的 128 位标识符
Major、Minor: 由 iBeacon 发布者自行设定,都是 16 位的标识符。比如,连锁店可以在 Major 写入区域资讯,可在 Minor 中写入个别店铺的 ID 等。另外,在家电中嵌入 iBeacon 功能时,可以用 Major 表示产品型号,用 Minor 表示错误代码,用来向外部通知故障
TX Power: APP 通过 iBeacon 发送信号强度估算出的在 1 米的时候 RSSI 强度

三、修改代码

打开工程 SDK\examples\ble_peripheral\ble_app_beacon

首先我们先定义 beacon 相关的数据,其中我们用户需要关注的主要有3个参数,UUID、Major 以及 Minor,其他的参数大家可以理解为固定的格式(格式固定,但数据内容不固定,可能有不同的厂商信息)。另外还有一个值得我们关注的数据,那就是 APP_COMPANY_IDENTIFIER,如果我们定义此参数为 0x004C(也就是 Apple id),那么我们的基站设备就被成为 iBeacon。

// BEACON数据
#define APP_BEACON_INFO_LENGTH          0x17                     // BEACON数据总长度
#define APP_ADV_DATA_LENGTH             0x15                     // BEACON特殊字节的长度
#define APP_DEVICE_TYPE                 0x02                     // 字节0x02代表这个设备是BEACON
#define APP_MEASURED_RSSI               0xC3                     // BEACON在1米距离处的信号强度
#define APP_COMPANY_IDENTIFIER          0x004C                   // 004C代表的是Apple id(只有这个ID,设备才会叫iBeacon)
#define APP_MAJOR_VALUE                 0x01, 0x02               // major
#define APP_MINOR_VALUE                 0x03, 0x04               // minor
#define APP_BEACON_UUID                 0x01, 0x12, 0x23, 0x34, \
                                        0x45, 0x56, 0x67, 0x78, \
                                        0x89, 0x9a, 0xab, 0xbc, \
                                        0xcd, 0xde, 0xef, 0xf0   /**< Proprietary UUID for Beacon. */

// BEACON数据数组,用于初始化广播数据内容
static uint8_t m_beacon_info[APP_BEACON_INFO_LENGTH] = 
{
    APP_DEVICE_TYPE,
    APP_ADV_DATA_LENGTH, 
    APP_BEACON_UUID,
    APP_MAJOR_VALUE,
    APP_MINOR_VALUE,
    APP_MEASURED_RSSI
};

对于 iBeacon 的数据,通过广播形式广播出去,那么其主要设置就是主函数里广播初始化部分(查看NRF52832学习笔记(9)——GAP从机端广播),所有定义的参数必须在广播初始化的时候进行配置。

static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;
    uint8_t       flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;  // 广播类型

    ble_advdata_manuf_data_t manuf_specific_data;

    manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;  // 公司ID号

#if defined(USE_UICR_FOR_MAJ_MIN_VALUES)
    // If USE_UICR_FOR_MAJ_MIN_VALUES is defined, the major and minor values will be read from the
    // UICR instead of using the default values. The major and minor values obtained from the UICR
    // are encoded into advertising data in big endian order (MSB First).
    // To set the UICR used by this example to a desired value, write to the address 0x10001080
    // using the nrfjprog tool. The command to be used is as follows.
    // nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val <your major/minor value>
    // For example, for a major value and minor value of 0xabcd and 0x0102 respectively, the
    // the following command should be used.
    // nrfjprog --snr <Segger-chip-Serial-Number> --memwr 0x10001080 --val 0xabcd0102
    uint16_t major_value = ((*(uint32_t *)UICR_ADDRESS) & 0xFFFF0000) >> 16;
    uint16_t minor_value = ((*(uint32_t *)UICR_ADDRESS) & 0x0000FFFF);

    uint8_t index = MAJ_VAL_OFFSET_IN_BEACON_INFO;

    m_beacon_info[index++] = MSB_16(major_value);
    m_beacon_info[index++] = LSB_16(major_value);

    m_beacon_info[index++] = MSB_16(minor_value);
    m_beacon_info[index++] = LSB_16(minor_value);
#endif

    manuf_specific_data.data.p_data = (uint8_t *) m_beacon_info;  // 数据结构体
    manuf_specific_data.data.size   = APP_BEACON_INFO_LENGTH;  // 数据长度

    // Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));

    advdata.name_type             = BLE_ADVDATA_NO_NAME;
    advdata.flags                 = flags;
    advdata.p_manuf_specific_data = &manuf_specific_data;

    // Initialize advertising parameters (used when starting advertising).
    memset(&m_adv_params, 0, sizeof(m_adv_params));

    m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
    m_adv_params.p_peer_addr     = NULL;    // Undirected advertisement.
    m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
    m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
    m_adv_params.duration        = 0;       // Never time out.

    err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
    APP_ERROR_CHECK(err_code);

    err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
    APP_ERROR_CHECK(err_code);
}

在主函数中,调用初始化广播函数 advertising_init(),当函数 advertising_start() 启动广播后,就可以实现广播信息的发出,也就是信标的广播包的广播

int main(void)
{
    // Initialize.
    log_init();
    timers_init();
    leds_init();
    power_management_init();
    ble_stack_init();  // 协议栈初始化
    advertising_init();  // 广播初始化

    // Start execution.
    NRF_LOG_INFO("Beacon example started.");
    advertising_start();  // 开始广播

    // Enter main loop.
    for (;; )
    {
        idle_state_handle();
    }
}

• 由 Leung 写于 2021 年 1 月 6 日

• 参考:青风电子社区

上一篇:Python pandas.DataFrame.sort_index函数方法的使用


下一篇:iBeacon 初探