11
=== NUS通信实验 === ==== 实验简介 ====上一章节,我们已经学习过了如何注册和发现一个服务,那么这一章节,我们将给大家介绍,如何利用这个服务去完成通信。 服务中的特征值的属性分为如下4种:Write写、Read读、Notify通知、Indicate暗示。 这边我们只给大家介绍Write与Notify,Write属性是主机向从机写,Notify属性是从机通知主机(通知属性的作用与否,需要由主机获取服务后使能)。 ==== 实验现象 ====这一章的实验,打印的“乱七八糟”的内容比较多,原因在于我们调高了LOG打印的等级,我们将等级调成了DEBUG档位(最高级别),有关LOG等级的说明请大家查看本手册的LOG打印实验说明。 其中整个的流程,还是上电先扫描,然后发起连接,或者连接参数,更新MTU大小,最后再获取NUS服务。 当成功获取NUS服务之后,我们向从机Wirte“AAA”。[[文件:Nrf rtt 110.png|边框|居中|无框|878x878像素]]主机上电等待连接,连接成功后,获取连接参数,更新MTU大小。 当被主机使能Notify之后,我们向主机Notify“BBB”。[[文件:Nrf rtt 210.png|边框|居中|无框|656x656像素]] ==== 工程及源码讲解 ==== ===== 主机部分 =====源码讲解的部分,我们接着上一章的NUS服务获取之后,开始说明,我们是怎么进行数据的收发的。 ====== ble_nus_c_evt_handler()函数 ======主机的nus client回调函数,相对于上一章节,在BLE_NUS_C_EVT_DISCOVERY_COMPLETE服务发现完成的事件中,我们开启了一个周期定时器任务。 这边需要注意,我们接收到从机Notify的数据,是由BLE_NUS_C_EVT_NUS_TX_EVT事件返回,我们可以在这边获取接收的数据。<syntaxhighlight lang="c" line="1" start="244">//******************************************************************// fn : ble_nus_c_evt_handler//// brief : NUS事件//// param : none//// return : nonestatic void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt){ ret_code_t err_code; switch (p_ble_nus_evt->evt_type) { case BLE_NUS_C_EVT_DISCOVERY_COMPLETE: NRF_LOG_INFO("Discovery complete."); err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles); APP_ERROR_CHECK(err_code); err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c); APP_ERROR_CHECK(err_code); NRF_LOG_INFO("Connected to device with Nordic UART Service."); app_timer_start(m_timer_nus, APP_TIMER_TICKS(1000), NULL); break; case BLE_NUS_C_EVT_NUS_TX_EVT: NRF_LOG_DEBUG("Receiving data."); NRF_LOG_HEXDUMP_DEBUG(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len); break; case BLE_NUS_C_EVT_DISCONNECTED: NRF_LOG_INFO("Disconnected."); break; default: break; }} </syntaxhighlight>那么接下来我们看一下定时器任务中处理了什么,可以看到我们初始化了一个周期定时器,这个定时器是1s执行一次,没过1s之后,就会返回一次nus_timeout_handler。 在这个nus_timeout_handler函数中,我们调用ble_nus_c_string_send()函数,去向从机设备发送AAA。<syntaxhighlight lang="c" line="1" start="458">//******************************************************************// fn : nus_timeout_handler//// brief : NUS定时器超时任务// // param : p_event -> 指向数据库发现事件的指针//// return : nonestatic void nus_timeout_handler(void * p_context){ ble_nus_c_string_send(&m_ble_nus_c, "AAA", 3);} //******************************************************************// fn : timer_init//// brief : 初始化定时器//// param : none//// return : nonestatic void timer_init(void){ ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); err_code = app_timer_create(&m_timer_nus,APP_TIMER_MODE_REPEATED,nus_timeout_handler); APP_ERROR_CHECK(err_code);}</syntaxhighlight> ===== 从机部分 =====我们从NUS的回调函数中,可以看到,我们利用BLE_NUS_EVT_RX_DATA事件接收主机Write的数据。 而当我们的Notification被使能的时候,也就是BLE_NUS_EVT_COMM_STARTED事件返回,我们通用会开启一个定时器任务。<syntaxhighlight lang="c" line="1" start="195">//******************************************************************// fn : nus_data_handler//// brief : 用于处理来自Nordic UART服务的数据的功能// details : 该功能将处理从Nordic UART BLE服务接收的数据并将其发送到UART模块//// param : ble_nus_evt_t -> nus事件//// return : nonestatic void nus_data_handler(ble_nus_evt_t * p_evt){ if (p_evt->type == BLE_NUS_EVT_RX_DATA) { 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); } else if (p_evt->type == BLE_NUS_EVT_TX_RDY) { NRF_LOG_DEBUG(" Service is ready to accept new data to be transmitted.."); } else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) { NRF_LOG_DEBUG("NUS Notification Enable."); app_timer_start(m_timer_nus, APP_TIMER_TICKS(1000), NULL); } else if (p_evt->type == BLE_NUS_EVT_COMM_STOPPED) { NRF_LOG_DEBUG("NUS Notification Disable."); }}</syntaxhighlight>接下来我们同样看一下我们的定时器任务,我们初始化了一个周期的定时器任务,这个定时器任务在上方BLE_NUS_EVT_COMM_STARTED事件中被设置为1s周期。 也就是每过1s都会进入一次nus_timeout_handler()函数,在这个函数中,我们调用ble_nus_data_send()函数,向主机Notify数据。<syntaxhighlight lang="c" line="1" start="343">//******************************************************************// fn : nus_timeout_handler//// brief : NUS定时器超时任务// // param : p_event -> 指向数据库发现事件的指针//// return : nonestatic void nus_timeout_handler(void * p_context){ uint16_t len = 3; ble_nus_data_send(&m_nus, "BBB", &len, m_conn_handle);} //******************************************************************// fn : timers_init//// brief : 初始化定时器功能//// param : none//// return : nonestatic void timers_init(void){ ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); err_code = app_timer_create(&m_timer_nus,APP_TIMER_MODE_REPEATED,nus_timeout_handler); APP_ERROR_CHECK(err_code);}</syntaxhighlight> ==== 实验总结 ====这一章的学习,我们是建立在已经获取了NUS服务的基础上进行的,所以掌握的要点也比较少。 1、主机如何接收和Write数据 2、从机如何接收和Notify数据[[分类:NRF52832DK]][[分类:实验手册]]22