NRF51822实例代码说明

说在前面:此说明用于nrf51822的主从机的实例代码解析,通过讲解主从机的双向通讯来说明如何添加自己的服务及特征。此说明为个人理解,可能与原意不同。


目录
主机模块... 3
从main说起... 3
app_trace_init() 3
ble_stack_init(); 4
client_handling_init() 6
device_manager_init7
scan_start7
从机模块... 7
从main说起... 7
gap_params_init(); 8
advertising_init(); 8
services_init();... 8
advertising_start(); 10
以串口的收发为例... 10
从机端:... 10
主机端:... 11


主机模块 从main说起 以\nrf51822\Board\nrf6310\s120\experimental\ble_app_multilink_central为例。工作流程(从main看起):初始化了参数之后,开启扫描,然后就进入循环。其中led,buttons的内容非开发所需,此处忽略。此外,需要说明的是,所有的sd_开头的函数均为nrf51822系统函数,具体的使用可以参考官网sdk的文档说明。
--------------------------------main-------------------------------------------------------------------------
int main(void)
{
    //Initialization of various modules.
   app_trace_init();
   leds_init();
   buttons_init();
    ble_stack_init();
   client_handling_init();
   device_manager_init();

    // Startscanning for devices.
   scan_start();

    for (;;)
    {
       power_manage();
    }
}
--------------------------------main-------------------------------------------------------------------------
接下来,具体看看各函数
app_trace_init() 初始化追踪应用,既初始化串口。
具体就一条函数,设置相应的引脚。

simple_uart_config(RTS_PIN_NUMBER,TX_PIN_NUMBER,CTS_PIN_NUMBER,RX_PIN_NUMBER,HWFC);

如果需要在串口设置输入中断,需要添加如下代码:

NRF_UART0->INTENSET= UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos;

NVIC_SetPriority(UART0_IRQn,APP_IRQ_PRIORITY_LOW);// APP_IRQ_PRIORITY_HIGH

     NVIC_EnableIRQ(UART0_IRQn);

并在main函数中添加中断处理函数的实现:void UART0_IRQHandler(void){}
注意:名字必须是这个。这个底层系统调用时已经定义好名字了。无须申明,只需要具体实现即可。  
值得注意的是 simple_uart_config 具体函数实现中有可以设置串口波特率,所有的波特率均有宏定义,只需直接更改宏即可。
NRF_UART0->BAUDRATE=(UART_BAUDRATE_BAUDRATE_Baud38400<<UART_BAUDRATE_BAUDRATE_Pos);
ble_stack_init(); 蓝牙协议栈的初始化
--------------------------------ble_stack_init()-------------------------------------------------------------------------
uint32_t err_code;
    // Initialize the SoftDevicehandler module.
    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,false);
    // Register with theSoftDevice handler module for BLE events.
    err_code =softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);
    // Register with theSoftDevice handler module for System events.
    err_code =softdevice_sys_evt_handler_set(sys_evt_dispatch);
    APP_ERROR_CHECK(err_code);
--------------------------------ble_stack_init()-------------------------------------------------------------------------
根据注释可以知道大概每个函数是做什么的。
2.1)SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
初始化SD处理模块,用于初始化时钟,内存等信息。需要关注的是
NRF_CLOCK_LFCLKSRC_XTAL_20_PPM 这是时钟参数,跟设置波特率一样,换相应的宏即可。
2.2) softdevice_ble_evt_handler_set(ble_evt_dispatch);
设置蓝牙事件处理,后面细讲。
2.3)softdevice_sys_evt_handler_set(sys_evt_dispatch);
设置系统事件处理。
接下来,看下 ble_evt_dispatch 具体的内容:

2.2.1)dm_ble_evt_handler(p_ble_evt);<----模块管理

        2.2.2)client_handling_ble_evt_handler(p_ble_evt); <---注册的服务处理
         2.2.3) on_ble_evt(p_ble_evt); <--蓝牙事件处理
大概的流程基本一致,就是事件处理,只是不同函数关注和处理的数据不同。以 on_ble_evt(p_ble_evt) 为例。
--------------------------------on_ble_evt(p_ble_evt)-----------------------------------------------------------------
switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_ADV_REPORT:
        {
            data_t adv_data;
            data_t type_data;
            // Initializeadvertisement report for parsing.
            adv_data.p_data =p_ble_evt->evt.gap_evt.params.adv_report.data;
            adv_data.data_len =p_ble_evt->evt.gap_evt.params.adv_report.dlen;
            err_code =adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
                                     &adv_data,
                                     &type_data);
            if (err_code != NRF_SUCCESS)
            {
                // Compare shortlocal name in case complete name does not match.
                err_code =adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME,
                                         &adv_data,
                                         &type_data);
            }
            // Verify if short orcomplete name matches target.
            if ((err_code ==NRF_SUCCESS) &&
               (0 ==memcmp(TARGET_DEV_NAME,type_data.p_data,type_data.data_len)))
            {
                err_code =sd_ble_gap_scan_stop();
                if (err_code !=NRF_SUCCESS)
                {
                   APPL_LOG("[APPL]: Scan stop failed, reason %d\r\n", err_code);
                }
                err_code =sd_ble_gap_connect(&p_ble_evt->evt.gap_evt.params.adv_report.\
                                             peer_addr,
                                             &m_scan_param,
                                             &m_connection_param);
                if (err_code !=NRF_SUCCESS)
                {
                   APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n",err_code);
                }
            }
            break;
        }
        case BLE_GAP_EVT_TIMEOUT:
           if(p_ble_evt->evt.gap_evt.params.timeout.src ==BLE_GAP_TIMEOUT_SRC_SCAN)
            {
               APPL_LOG("[APPL]: Scan Timedout.\r\n");
            }
            else if(p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
            {
               APPL_LOG("[APPL]: Connection Request Timedout.\r\n");
            }
            break;
        default:
            break;
    }
--------------------------------on_ble_evt(p_ble_evt)-----------------------------------------------------------------
就是一个switch事件,根据不同的事件类型处理做不同的事情。
如: BLE_GAP_EVT_ADV_REPORT
只要有设备进行广播,并且广播是可见的,而自身是扫描状态的话,就会进入这个事件。具体是将接收到的数据进行匹配,一旦匹配成功就关闭扫描并发送连接请求。其中,需要关注的是: BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 这个宏。这是主从设备广播的数据匹配类型,在主从两端都需要进行设置。
此处再列举几个常见的宏定义,并加以大致的解释。(详细可以参考协议栈初始化中的其他函数。)
BLE_GAP_EVT_TIMEOUT 超时处理。
BLE_GATTC_EVT_WRITE_RSP 写请求回复。每当主机发送一次数据给从机,从机会回一个写事件的回复,当主机收到写事件的回复之后才能再次发送数据。
BLE_GATTC_EVT_HVX 收到数据。这个事件表示从机发送了数据到主机。
          BLE_GAP_EVT_CONNECTED 连接成功。
          BLE_GAP_EVT_DISCONNECTED 断开连接。
BLE_GAP_EVT_SEC_PARAMS_REQUEST 从机请求连接参数
BLE_GAP_EVT_CONN_SEC_UPDATE: 从机请求更改连接参数
client_handling_init() 初始化客户端处理
--------------------------------client_handling_init()-----------------------------------------------------------------
uint32_t err_code;
    uint32_t i;
    ble_uuid128_t base_uuid = MULTILINK_PERIPHERAL_BASE_UUID;

    err_code =sd_ble_uuid_vs_add(&base_uuid, &m_base_uuid_type);

    APP_ERROR_CHECK(err_code);
    nrf_gpio_range_cfg_output(8, 15);
    for (i = 0; i < MAX_CLIENTS; i++)
    {
        m_client.state  = IDLE;
    }
    m_client_count = 0;
    db_discovery_init();

    // Register with discovery module for thediscovery of the service.

    ble_uuid_t uuid;
    uuid.type = m_base_uuid_type;

    uuid.uuid =MULTILINK_PERIPHERAL_SERVICE_UUID;

    err_code =ble_db_discovery_register(&uuid,

                                        db_discovery_evt_handler);

    APP_ERROR_CHECK(err_code);
--------------------------------client_handling_init()-----------------------------------------------------------------
这个函数用于注册服务以及特征,以及服务的处理。
其中 sd_ble_uuid_vs_add(&base_uuid, &m_base_uuid_type);用于16bit注册服务。
SIG规定了一套标准的uuid的规则,具体的uuid的规则和类型可以参考实例代码。

uuid.uuid= MULTILINK_PERIPHERAL_SERVICE_UUID;添加4bit服务,相当于起别名。

ble_db_discovery_register(&uuid,db_discovery_evt_handler);注册服务发现处理函数。

device_manager_init 设备管理处理化
这个函数用于初始化一些设备参数,如(扫描时间,扫描间隔,接收数据的大小等);不需要手动更改,相应的参数修改请在main中的宏定义中修改。
scan_start   启动扫描
         这函数用于将前一个函数初始化的数据填入扫描函数中,并开始扫描,不需要手动更改。

至此,全部准备工作完毕,接来下主机就会进入循环的监听模式,当有相应的事件到来就会自动调用协议栈中相应的模块进行调度。
从机模块 从main说起以\nrf51822\Board\nrf6310\s120\experimental\ble_app_multilink_peripheral为例。与主机的工作流程类似(从main看起):初始化了参数之后,开启广播,然后就进入循环。只是从机需要初始化的东西有部分与主机会有些不同,其中led,buttons,gpio的内容非开发所需,此处忽略。此外,由于主从设备是配合使用的。ble_stack_init(); device_manager_init();这两个的初始化与主机的初始化基本一致,只是相应的处理方式和参数名定义会不同。需要查看差异的话,可以对比查看。(比如,从机会有广播包的事情处理,而主机则没有。)这里只对其他函数进行说明。
--------------------------------main-------------------------------------------------------------------------
int main(void)
{
   ble_stack_init();
   leds_init();
   timers_init();
   gpiote_init();
   buttons_init();
   device_manager_init();
   gap_params_init();
   advertising_init();
   services_init();

   advertising_start();

   for (;;)
    {
       power_manage();
}
--------------------------------main-------------------------------------------------------------------------
接下来,具体看看各函数
gap_params_init();这个函数用于初始化所有的需要的GAP参数,如(设备名称,连接时间,超时时间等)。同样的,这个函数不需要修改,相应的参数需要在宏定义中修改。
advertising_init();这个函数用于初始化广播包。需要注意的有如下参数:
Flag:设备广播的可见范围,如有限可见,常可见等设置,详见宏定义的说明。
advdata.name_type:广播包中包含的设备名称类型,与主机端配套设置。如全名称,短名称,和不显示名称。
services_init();这个函数用于初始化服务,与主机端的client_handing对应。
--------------------------------  services_init()-----------------------------------------------------------
uint32_t            err_code;
    ble_uuid_t          uuid;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_t    attr;
    ble_gatts_attr_md_t attr_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_md_t char_ud_md;
    uint16_t            svc_test;
    static uint8_t multilink_peripheral_data;
    static uint8_t multilink_peripheral_ud[] ="Modifiable multilink_peripheral Data";
    ble_uuid128_t base_uuid =MULTILINK_PERIPHERAL_BASE_UUID;
    err_code =sd_ble_uuid_vs_add(&base_uuid, &m_base_uuid_type);
    APP_ERROR_CHECK(err_code);
    uuid.type = m_base_uuid_type;
    uuid.uuid = MULTILINK_PERIPHERAL_SERVICE_UUID;
    err_code =sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &uuid,&svc_test);
    APP_ERROR_CHECK(err_code);
    uuid.uuid = MULTILINK_PERIPHERAL_CHAR_UUID;
    memset(&attr, 0,sizeof(ble_gatts_attr_t));
    attr.p_uuid    = &uuid;
    attr.p_attr_md = &attr_md;
    attr.max_len   = 1;
    attr.p_value   = &multilink_peripheral_data;
    attr.init_len  = sizeof(multilink_peripheral_data);

    memset(&attr_md, 0,sizeof(ble_gatts_attr_md_t));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
   BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
    attr_md.vloc = BLE_GATTS_VLOC_STACK;
    attr_md.vlen = 0;
    memset(&cccd_md, 0,sizeof(ble_gatts_attr_md_t));
   BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);
    cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    memset(&char_md, 0,sizeof(ble_gatts_char_md_t));
    char_md.p_cccd_md               = &cccd_md;
    char_md.char_props.notify       = 1;
    char_md.char_props.indicate     = 1;
    char_md.char_props.read         = 1;
    char_md.char_props.write        = 1;
    char_md.char_ext_props.wr_aux   = 1;
    char_md.p_user_desc_md          = &char_ud_md;
    char_md.p_char_user_desc        = multilink_peripheral_ud;
    char_md.char_user_desc_size     = (uint8_t)strlen((char*)multilink_peripheral_ud);
    char_md.char_user_desc_max_size =(uint8_t)strlen((char *)multilink_peripheral_ud);
    memset(&char_ud_md, 0,sizeof(ble_gatts_attr_md_t));
    char_ud_md.vloc = BLE_GATTS_VLOC_STACK;
    char_ud_md.vlen = 1;
   BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_ud_md.read_perm);
   BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_ud_md.write_perm);
    err_code =sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID,
                                               &char_md,
                                              &attr,
                                              &m_char_handles);
    APP_ERROR_CHECK(err_code);
--------------------------------  services_init()-----------------------------------------------------------
需要注意如何添加一个服务,特征。
首先,添加一个服务到服务表中。这于主机的是一样的。

sd_ble_uuid_vs_add(&base_uuid,&m_base_uuid_type);

其次,将该服务设置为主服务列表当中。

sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,&uuid, &svc_test);

再者,设置服务之后,需要在这个服务中添加相应的特征。
sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID,
                                              &char_md,
                                              &attr,
                                              &m_char_handles);
需要说明的是,无论是服务,还是特征都有自己对应的属性,在注册之前都需要设置其对应的属性,这点在实例代码中已经有了很好的模板。有需要添加自己的服务或者特征都可以通过这个模板进行修改。
advertising_start();开始广播,这与主机的开始扫描是相对应的。设置广播类型,时间,超时时间等参数后开始广播。同样的,这个函数也不需要修改,修改的部分都在宏定义处修改。


至此,全部准备工作完毕,接来下从机就会进入循环的广播模式,当有相应的事件到来就会自动调用协议栈中相应的模块进行调度。

以串口的收发为例接下来,将以串口的收发为例。讲述具体数据的发送和接收。
Nrf51822的实例代码优点就是所有的函数均是模块化的。因此可以不加修改整个拷贝即可使用。
从机端:从机端的代码需要参考\Board\pca10001\s110\experimental\ble_app_uart的代码。
1)      调通串口。
发现从机端是没有设置串口代码的。因此需要先在从机端添加相应的串口初始化代码。这里需要用到的uart_init()代码。直接复制即可。
2)      串口中断函数
直接复制串口中断处理函数的代码void UART0_IRQHandler(void)。
看下中断处理函数做了些什么事情

-------------------------------- voidUART0_IRQHandler(void)---- -------------------------------------

{

    static uint8_tdata_array[BLE_NUS_MAX_DATA_LEN];

    static uint8_t index = 0;
    uint32_t err_code;

    /**@snippet [Handling the data receivedover UART] */

    data_array[index] = simple_uart_get();
    index++;

    if ((data_array[index - 1] == '\n') ||(index >= (BLE_NUS_MAX_DATA_LEN - 1)))

    {

        err_code = ble_nus_send_string(&m_nus,data_array, index + 1);

        if (err_code !=NRF_ERROR_INVALID_STATE)

        {
            APP_ERROR_CHECK(err_code);

        }      

        index = 0;
    }

    /**@snippet [Handling the data receivedover UART] */

}

-------------------------------- voidUART0_IRQHandler(void)---- -------------------------------------

接收串口中的消息,当遇到回车或者字符数够了之后,将数据发送出去。

ble_nus_send_string(&m_nus,data_array, index + 1);这条语句中的m_nus的参数就是数据发送的句柄。会发现根本就没有对这个参数进行任何的设置,数据是发不出去的。因此要对这个参数进行相应的处理。这里就需要用到services_init()


3)      services_init()
看下参考代码和从机的代码中services_init()的差异,会发现参考代码对该函数又进行了进一步的封装。其中就有对m_nus的操作。同样的。整个复制过来。(包括内部实现的函数)
这里需要记住注册了的服务的uuid和BLE_UUID_NUS_SERVICE。
同时注册的特征id:BLE_UUID_NUS_TX_CHARACTERISTIC,
                                       BLE_UUID_NUS_RX_CHARACTERISTIC也需要记住。
这样发送的部分就已经做完了。
那么接收函数呢?
其实也已经做好了。在复制services_init()函数时,   nus_init.data_handler = nus_data_handler;  
把接收数据的处理函数也已经添加进来了。这里只是把数据通过串口打印出来而已。并未做其他操作。

主机端:主机端的代码需要参考\Board\nrf6310\s120\experimental\ble_app_hrs_c的代码

串口中断函数。同样的。将参考代码的串口中断函数复制过来。同样是缺乏m_nus这个发送的句柄,因此这里也同样需要添加服务。此外,由于主从机发送数据所调用的函数不同。这里还需要修改ble_nus_send_string(&m_nus,data_array, index + 1)这个函数。修改后的内容如下,(参考\Board\nrf6310\s120\experimental\ble_app_uart_c中的tx_send()的代码。)

----------tx_send(ble_ecg_c_t* p_ble_ecg_c,char *str ,unsigned char len)------------

void tx_send(ble_ecg_c_t *p_ble_ecg_c,char *str ,unsigned char len){

    tx_message_t * p_msg;
    if (len > WRITE_MESSAGE_LENGTH) {
        return ;
    }           

    p_msg              =&m_tx_buffer[m_tx_insert_index++];

    m_tx_insert_index &= TX_BUFFER_MASK;

    strncpy(p_msg->req.write_req.gattc_value,str,len);

    p_msg->req.write_req.gattc_params.handle   = p_ble_ecg_c->ecg_rx_handle;

   p_msg->req.write_req.gattc_params.len      = len;

   p_msg->req.write_req.gattc_params.p_value = (uint8_t*)p_msg->req.write_req.gattc_value;

    p_msg->req.write_req.gattc_params.offset   = 0;

   p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;

    p_msg->conn_handle                         =p_ble_ecg_c->conn_handle;

    p_msg->type                                = WRITE_REQ;
    tx_buffer_process();
}

----------tx_send(ble_ecg_c_t* p_ble_ecg_c,char *str ,unsigned char len)------------



1)      参考hrs_c_init()函数添加新的服务。
-------------------------------- hrs_c_init()-----------------------------------------

static voidhrs_c_init(void)

{
    ble_hrs_c_init_t hrs_c_init_obj;

    hrs_c_init_obj.evt_handler =hrs_c_evt_handler;


    uint32_t err_code = ble_hrs_c_init(&m_ble_hrs_c,&hrs_c_init_obj);

    APP_ERROR_CHECK(err_code);
}
-------------------------------- hrs_c_init()-----------------------------------------

修改部分:
1.(建议,非必须)将所有hrs相关的单词(包括文件名,宏定义,函数名,变量名等)改掉。
2. hrs_c_evt_handler这个函数是数据接收的实现函数。
3. ble_hrs_c_init(&m_ble_hrs_c, &hrs_c_init_obj)中m_ble_hrs_c这个参数的名称必须与串口中断中的m_nus这个参数必须是同一参数,具体起什么名字自己定一个全局变量即可。
4.修改ble_hrs_c_init()
---------------------------------- ble_hrs_c_init()------------------------------------------------

uint32_tble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)

{

    if ((p_ble_hrs_c == NULL) ||(p_ble_hrs_c_init == NULL))

    {
        return NRF_ERROR_NULL;
    }
    ble_uuid_t hrs_uuid;
    hrs_uuid.type                 = BLE_UUID_TYPE_BLE;
    hrs_uuid.uuid                 = BLE_UUID_HEART_RATE_SERVICE;
    mp_ble_hrs_c                  = p_ble_hrs_c;
    mp_ble_hrs_c->evt_handler     = p_ble_hrs_c_init->evt_handler;
    mp_ble_hrs_c->conn_handle     = BLE_CONN_HANDLE_INVALID;

    mp_ble_hrs_c->hrm_cccd_handle =BLE_GATT_HANDLE_INVALID;

    returnble_db_discovery_register(&hrs_uuid,

                                     db_discover_evt_handler);
}
-------------------------------- ble_hrs_c_init()-----------------------------------------

会发现,这里并没有添加服务到服务表中。这里因为心率服务在SIG中已经定义好了。无需用户再进行添加。只需要根据需要再添加特征即可。
这里需要添加一个服务uuid。添加或修改如下代码:

ble_uuid128_t   nus_base_uuid = {0x9E, 0xCA, 0xDC, 0x24,0x0E, 0xE5, 0xA9, 0xE0,

                         0x93,0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E};

             mp_ble_hrs_c                  = p_ble_hrs_c;         

             err_code =sd_ble_uuid_vs_add(&nus_base_uuid, &m_base_uuid_type);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    ble_uuid_t hrs_uuid;
    hrs_uuid.type                 = m_base_uuid_type;
          hrs_uuid.uuid                 = BLE_UUID_NUS_SERVICE;
需要注意的是,uuid必须与从机的uuid一致。BLE_UUID_NUS_SERVICE与从机的一致。这样才能确保主机能找到从机的服务。

再修改 db_discover_evt_handler 服务发现处理函数。
-------------------------------- db_discover_evt_handler-----------------------------------------

static voiddb_discover_evt_handler(ble_db_discovery_evt_t * p_evt)

{

    // Check if the Heart Rate Service wasdiscovered.

    if (p_evt->evt_type ==BLE_DB_DISCOVERY_COMPLETE

        &&

       p_evt->params.discovered_db.srv_uuid.uuid ==BLE_UUID_HEART_RATE_SERVICE

        &&

       p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)

    {

        mp_ble_hrs_c->conn_handle =p_evt->conn_handle;

        // Find the CCCD Handle of the HeartRate Measurement characteristic.

        uint8_t i;

        for (i = 0; i <p_evt->params.discovered_db.char_count; i++)

        {

            if(p_evt->params.discovered_db.charateristics.characteristic.uuid.uuid

                ==

               BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)

            {

                // Found Heart Ratecharacteristic. Store CCCD handle and break.

               mp_ble_hrs_c->hrm_cccd_handle =

                         p_evt->params.discovered_db.charateristics.cccd_handle;

               mp_ble_hrs_c->hrm_handle=                 p_evt->params.discovered_db.charateristics.characteristic.handle_value;

                break;
            }
        }

        LOG("[HRS_C]: Heart Rate Servicediscovered at peer.\r\n");

        ble_hrs_c_evt_t evt;

        evt.evt_type =BLE_HRS_C_EVT_DISCOVERY_COMPLETE;

       mp_ble_hrs_c->evt_handler(mp_ble_hrs_c, &evt);

    }
}
-------------------------------- db_discover_evt_handler-----------------------------------------
这里是发现服务后的处理函数。先确保找到的是正确的服务。然后将服务里的特征与主机定义的特征进行匹配,匹配成功后获取相应的参数值。具体修改如下:
BLE_UUID_HEART_RATE_SERVICE换成 BLE_UUID_NUS_SERVICE
BLE_UUID_TYPE_BLE换成 m_base_uuid_type
BLE_UUID_HEART_RATE_MEASUREMENT_CHAR换成 BLE_UUID_NUS_TX_CHARACTERISTIC,并仿照这块代码,添加一个 BLE_UUID_NUS_RX_CHARACTERISTIC的特征发现。

最后在蓝牙协议栈的初始化中,添加服务的处理事件。这里可以参考串口服务ble_nus_on_ble_evt中的代码。
--------------------------------ble_nus_on_ble_evt-----------------------------------------

void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
    if ((p_nus == NULL) ||(p_ble_evt == NULL))
    {
        return;
    }
    switch(p_ble_evt->header.evt_id)
    {
        caseBLE_GAP_EVT_CONNECTED:
            on_connect(p_nus,p_ble_evt);
            break;
        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_nus,p_ble_evt);
            break;
        case BLE_GATTS_EVT_WRITE:
            on_write(p_nus,p_ble_evt);
            break;
           caseBLE_GATTC_EVT_WRITE_RSP:                                                         
                     on_write_rsp(p_nus, p_ble_evt);
            break;  
       default:
            // No implementationneeded.
            break;
    }
}-------------------------------ble_nus_on_ble_evt-----------------------------------------

当有通知到来时,将会触发BLE_GATTS_EVT_WRITE,可以在这里将收到的数据通过串口打印出来。



至此,nrf51822的实例代码解析,以及如何添加自己的一个服务及特征,主从机的双向通讯全部解释完毕。当中的参数定义并没有加以补充。复制不同模块的函数时,要同时将参数、申明、宏定义等相关内容也一块复制过来。当然复制代码并不是直接复制,黏贴。而是在理解后参考着原代码修改成为自己的内容。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
nrf51822中文参考手册,nRF51822 是一款集成nRF51x系列无线收发器的超低功耗的片上系统 (Soc) , 包含一个32位ARM Cortex-M0 CPU , flash 存储器和模拟、数字外设。NORDIC SEMICONDUCTOR nRF51822 Product Specification v1.3 Liability disclaimer Nordic Semiconductor ASa reserves the right to make changes without further notice to the product to improve reliability, function or design. Nordic Semiconductor asa does not assume any liability arising out of the application or use of any product or circuits described herein ife support applications Nordic Semiconductor's products are not designed for use in life support appliances, devices, or systems where malfunction of these products can reasonably be expected to result in personal injury. Nordic Semiconductor ASa customers using or selling these products for use in such applications do so at their own risk and agree to fully indemnify Nordic Semiconductor ASA for any damages resulting from such improper use or sale Contact details Foryournearestdistributorpleasevisitwww.nordicsemi.com Information regarding product updates, downloads, and technical support can be accessed through your My Page account on our home page Main office: Otto Nielsens veg 12 Mailing address: Nordic Semiconductor 7052 Trondheim P.O. Box 2336 Norway 7004 Trondhe Phone:+4772898900 Norway 4772898989 画N远 NS-EN ISO 9001 CERTIFICATEDFIRM RoHS and reach statement Nordic semiconductor's products meet the requirements of Directive 2002/95/EC of the European Parliament and of the Council on the restriction of Hazardous Substances(roHS)and the requirements of the reach regulation(EC 1907/2006)on Registration, Evaluation, Authorization and Restriction of Chemicals. The SvHC(Substances of Very High Concern) candidate list is continually being updated Complete hazardous substance reports material composition reports and latest version of nordics reach statementcanbefoundonourwebsitewww.nordicsemicom Page 2 of 67 NORDIC SEMICONDUCTOR nRF51822 Product Specification v1.3 Datasheet status Status Description Objective Pro

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值