nrf52832--官方串口例程添加led特性

硬件:清风nrf52832开发板

软件:编译环境:keil4, SDK版本:nRF5_SDK_15.0.0_a53641a, 协议栈版本:s132_nrf52_6.0.0

简介:在官方串口例程的基础上添加一个特性,用于控制led,通过向此特性写1,控制led4亮,写0控制led灭

过程:

    在ble_nuc.c文件中有两个函数,tx_char_add和rx_char_add,他们分别是添加tx和rx的特性,仿照这两个函数,添加led的特性,代码如下:

static uint32_t led_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;
		
    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.write         = 1;
    char_md.char_props.write_wo_resp = 1;
    char_md.p_char_user_desc         = NULL;
    char_md.p_char_pf                = NULL;
    char_md.p_user_desc_md           = NULL;
    char_md.p_cccd_md                = NULL;
    char_md.p_sccd_md                = NULL;

    ble_uuid.type = p_nus->uuid_type;
    ble_uuid.uuid = BLE_UUID_NUS_LED_CHARACTERISTIC;//此处需要修改,定义自己的UUID

    memset(&attr_md, 0, sizeof(attr_md));

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);

    attr_md.vloc    = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth = 0;
    attr_md.wr_auth = 0;
    attr_md.vlen    = 1;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = 1;//数据长度为1个字节
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = BLE_NUS_MAX_LED_CHAR_LEN;

    return sd_ble_gatts_characteristic_add(p_nus->service_handle,//主服务的句柄
                                           &char_md,
                                           &attr_char_value,
                                           &p_nus->led_handles);//此处需要定义自己的句柄
}
 

此函数是仿照rx_char_add函数建立的。已上代码中需要定义BLE_UUID_NUS_LED_CHARACTERISTIC,修改ble_nus_s结构体

#define BLE_UUID_NUS_LED_CHARACTERISTIC 0x0004


struct ble_nus_s
{
    uint8_t                         uuid_type;          /**< UUID type for Nordic UART Service Base UUID. */
    uint16_t                        service_handle;     /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
    ble_gatts_char_handles_t        tx_handles;         /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
    ble_gatts_char_handles_t        rx_handles;         /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
    ble_gatts_char_handles_t                led_handles;//定义led的句柄
    blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
    ble_nus_data_handler_t          data_handler;       /**< Event handler to be called for handling received data. */
};

到此为止,led的特性已经添加完毕,接下来需要修改串口事件处理函数。

在ble_nus.c中,void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)此函数用于处理串口服务事件的处理函数,函数如下:

void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    if ((p_context == NULL) || (p_ble_evt == NULL))
    {
        return;
    }

    ble_nus_t * p_nus = (ble_nus_t *)p_context;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_nus, p_ble_evt);
            break;

        case BLE_GATTS_EVT_WRITE:
            on_write(p_nus, p_ble_evt);//执行写事件
            break;

        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            on_hvx_tx_complete(p_nus, p_ble_evt);
            break;

        default:
            // No implementation needed.
            break;
    }
}

当往蓝牙串口服务里写数据时,会跳到BLE_GATTS_EVT_WRITE:这个分支去执行on_write函数,

static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
    ret_code_t                    err_code;
    ble_nus_evt_t                 evt;
    ble_nus_client_context_t    * p_client;
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;//保存发生的事件

    err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
                                 p_ble_evt->evt.gatts_evt.conn_handle,
                                 (void *) &p_client);
    if (err_code != NRF_SUCCESS)
    {
        NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
                      p_ble_evt->evt.gatts_evt.conn_handle);
    }

    memset(&evt, 0, sizeof(ble_nus_evt_t));
    evt.p_nus       = p_nus;
    evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
    evt.p_link_ctx  = p_client;
    NRF_LOG_INFO("TEST\n");
    /*xujidong*/
    SEGGER_RTT_printf(0, "p_nus->rx_handles.value_handle = %d\n", p_nus->rx_handles.value_handle);
    SEGGER_RTT_printf(0, "%sp_nus->tx_handles.value_handle = %d%s\n", RTT_CTRL_BG_BRIGHT_RED,p_nus->tx_handles.value_handle,RTT_CTRL_RESET);
    SEGGER_RTT_printf(0, "%sp_nus->led_handles.value_handle = %d%s\n", RTT_CTRL_BG_BRIGHT_RED,p_nus->led_handles.value_handle,RTT_CTRL_RESET);
    if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
        (p_evt_write->len == 2))
    {
        if (p_client != NULL)
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                p_client->is_notification_enabled = true;
                evt.type                          = BLE_NUS_EVT_COMM_STARTED;
            }
            else
            {
                p_client->is_notification_enabled = false;
                evt.type                          = BLE_NUS_EVT_COMM_STOPPED;
            }

            if (p_nus->data_handler != NULL)
            {
                p_nus->data_handler(&evt);
            }

        }
    }
    else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&  //根据接收数据的句柄,处理接收数据
             (p_nus->data_handler != NULL))
    {
        evt.type                  = BLE_NUS_EVT_RX_DATA;//将事件标志置为接收数据事件
        evt.params.rx_data.p_data = p_evt_write->data;//保存接收的数据
        evt.params.rx_data.length = p_evt_write->len;   //爆出接收的数据长度

        p_nus->data_handler(&evt);
    }
    else if ((p_evt_write->handle == p_nus->led_handles.value_handle) &&//根据句柄判断是否是led事件
             (p_nus->data_handler != NULL))
    {
    	SEGGER_RTT_printf(0, "%shello world%s\n", RTT_CTRL_BG_BRIGHT_RED,RTT_CTRL_RESET);
	evt.type                  = BLE_NUS_EVT_LED_OPT;//将事件设置为led事件
        evt.params.led_data.p_data = p_evt_write->data;
        evt.params.led_data.length = p_evt_write->len;
        p_nus->data_handler(&evt);//执行事件处理函数,此处理函数为nus_data_handler
    }
    else
    {
        // Do Nothing. This event is not relevant for this service.
    }
}

已上代码中,因为添加了led事件,所以需要修改ble_nus_evt_t结构体

//事件的类型
typedef enum
{
    BLE_NUS_EVT_RX_DATA,      /**< Data received. */
    BLE_NUS_EVT_TX_RDY,       /**< Service is ready to accept new data to be transmitted. */
    BLE_NUS_EVT_LED_OPT,//添加led事件类型
    BLE_NUS_EVT_COMM_STARTED, /**< Notification has been enabled. */
    BLE_NUS_EVT_COMM_STOPPED, /**< Notification has been disabled. */
} ble_nus_evt_type_t;

typedef struct
{
    ble_nus_evt_type_t         type;        /**< Event type. */
    ble_nus_t                * p_nus;       /**< A pointer to the instance. */
    uint16_t                   conn_handle; /**< Connection handle. */
    ble_nus_client_context_t * p_link_ctx;  /**< A pointer to the link context. */
    union
    {
        ble_nus_evt_rx_data_t rx_data; /**< @ref BLE_NUS_EVT_RX_DATA event data. */
	ble_nus_evt_rx_data_t led_data;//保存led数据
    } params;
} ble_nus_evt_t;

在事件结构体中添加了led事件类型,添加了存储led数据的变量,接下来需要在事件回调函数中添加处理led事件的相关代码

事件回调函数位于main.c中,代码如下:

static void nus_data_handler(ble_nus_evt_t * p_evt)
{

    if (p_evt->type == BLE_NUS_EVT_RX_DATA)
    {
        uint32_t err_code;

        NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
        NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);

				if(p_evt->params.rx_data.p_data[0] == '1')
				{
							printf("recv passkey\n");
							static uint8_t passkey[] = "654321";
							//err_code=sd_ble_opt_set(BLE_GAP_OPT_PASSKEY,&m_static_pin_option);
							m_static_pin_option.gap_opt.passkey.p_passkey = passkey; 		
							err_code=sd_ble_opt_set(BLE_GAP_OPT_PASSKEY,&m_static_pin_option);																					
							APP_ERROR_CHECK(err_code);
							err_code = sd_ble_gap_disconnect(mp_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
							APP_ERROR_CHECK(err_code);
							//sd_ble_gap_connect_cancel();
							m_conn_handle = BLE_CONN_HANDLE_INVALID;
							
				}
        for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
        {
            do
            {
                err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                {
                    NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                    APP_ERROR_CHECK(err_code);
                }
            } while (err_code == NRF_ERROR_BUSY);
        }
        if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
        {
            while (app_uart_put('\n') == NRF_ERROR_BUSY);
        }
    }
		if(p_evt->type == BLE_NUS_EVT_LED_OPT)//处理led事件
		{
			SEGGER_RTT_printf(0, "%sBLE_NUS_EVT_LED_OPT%s\n", RTT_CTRL_BG_BRIGHT_RED,RTT_CTRL_RESET);
			SEGGER_RTT_printf(0, "%sp_data = %d%s\n", RTT_CTRL_BG_BRIGHT_RED,p_evt->params.led_data.p_data[0],RTT_CTRL_RESET);
			SEGGER_RTT_printf(0, "%slength = %d%s\n", RTT_CTRL_BG_BRIGHT_RED,p_evt->params.led_data.length,RTT_CTRL_RESET);
			if(p_evt->params.led_data.p_data[0] == 1)
			{
					SEGGER_RTT_printf(0, "LED ON\n");
					bsp_board_led_on(3);
			}
			else if (p_evt->params.led_data.p_data[0] == 0)
			{
					bsp_board_led_off(3);
					SEGGER_RTT_printf(0, "LED OFF\n");
			}
		}

}

最后总结一下创建一个服务需要具体做哪些工作:

1、创建服务初始化结构体,主要用来保存处理来自于串口服务的回调函数

    创建串口服务结构体,主要用来保存各种characteristic的相关句柄(需要创建此类型的全局变量,并将ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)串口服务事件处理函数添加到协议栈中)

    创建串口服务事件结构体,主要用来保存事件的类型和收到的数据

2、需要在services_init(void)函数中初始化串口服务

    在初始化服务中主要添加了两个Characteristic,以及初始化UUID

3、创建void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)函数用来处理串口服务事件

4、创建static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)函数用来处理具体的工作,此函数被ble_nus_on_ble_evt调用,此函数中根据事件的句柄来判断事件的类型,然后设置相应的事件,由nus_data_handler(ble_nus_evt_t * p_evt)去执行具体的动作


你可能感兴趣的:(低功耗蓝牙BLE)