- 开发环境搭建
- 开发环境涉及到协议栈SDK版本、keil PACK版本的匹配问题,目前测试通过的环境如下:
- windows系统:win10
- 硬件:NRF52832测试板、JLINK-V8仿真器
- Keil uVision5 For ARM 5.14
- nrfgostudio_win-64_1.21.2_installer
- nRF5_SDK_11.0.0
- NordicSemiconductor.nRF_DeviceFamilyPack.8.5.0.pack
软件都安装完毕后,就可以开始进行调试了。
- 协议栈烧录
开发板通过SWD接口连接调试仿真,通过nrfgo官方工具烧写蓝牙协议栈(s132);
协议栈hex文件在sdk的路径:nRF5_SDK_11.0.0_89a8197\components\softdevice\s132\hex.
先擦除,写入s132协议栈,应用部分在keil上编程烧写及调试。
2.NRF52832添加串口私有服务透传实现
- 打开nRF5_SDK_11.0.0_89a8197\examples\ble_peripheral\ble_app_uart\pca10040\s132\arm5_no_packs例程,我们的开发基于例程修改就可以了;
- NRF52832初始化分一般流程,主要需要设置的是连接参数(时间间隔)、广播间隔、扫描响应数据等
int main(void){ uint32_t err_code; bool erase_bonds; // Initialize. //APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); uart_init(); //串口硬件初始化 APP_LOG("\r\nNRF52832例程测试!\r\n"); timers_init(); //定时器创建 APP_LOG("\r\n应用定时器初始化!\r\n"); buttons_leds_init(&erase_bonds); //使用BSP驱动功能较完善,到时修改 APP_LOG("\r\nBSP按键、LED初始化!\r\n");// leds_init();// buttons_init(); ble_stack_init(); APP_LOG("\r\nBLE协议栈初始化!\r\n"); gap_params_init(); APP_LOG("\r\nGAP参数设置初始化:\r\n"); APP_LOG(" 最小连接间隔:20ms\r\n"); APP_LOG(" 最大连接间隔:75ms\r\n"); APP_LOG(" 从机延迟:0\r\n"); APP_LOG(" 连接超时:4s\r\n"); services_init(); //添加私有服务,需要初始化在广播初始化之前 APP_LOG("\r\n添加私有服务\r\n"); advertising_init(); APP_LOG("\r\n广播初始化\r\n"); conn_params_init(); err_code = ble_advertising_start(BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); application_timers_start();//开始定时,时间间隔 // Enter main loop. for (;;) { power_manage(); }}
- 串口私有服务主要在services_init()中添加
#include "ble_nus.h" //蓝牙串口服务
同时工程中添加对应文件及引用路径如下图:
static void services_init(void){ uint32_t err_code; ble_nus_init_t nus_init;// ble_lbs_init_t lbs_init; memset(&nus_init, 0, sizeof(nus_init)); nus_init.data_handler = nus_data_handler; //蓝牙接收数据串口处理 err_code = ble_nus_init(&m_nus, &nus_init); //添加nus的GATTS服务UUID APP_ERROR_CHECK(err_code); // memset(&lbs_init, 0, sizeof(lbs_init));// lbs_init.led_write_handler = led_write_handler;// err_code = ble_lbs_init(&m_lbs, &lbs_init); //特性:按键字节、LED字节// APP_ERROR_CHECK(err_code);}
- 蓝牙串口服务的接收数据处理函数,实现蓝牙接收串口发送
services_init
nus_data_handler
static void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length){ for (uint32_t i = 0; i < length; i++) { while(app_uart_put(p_data[i]) != NRF_SUCCESS); //数据串口发送 } while(app_uart_put('\n') != NRF_SUCCESS);}
- 串口接收蓝牙发送(数据以回车为结束位)
uart_init //串口初始化,注册串口接收事件处理函数
uart_event_handle //串口数据接收处理函数
void uart_event_handle(app_uart_evt_t * p_event){ static uint8_t data_array[BLE_NUS_MAX_DATA_LEN]; //蓝牙规范限长20字节 static uint8_t index = 0; uint32_t err_code; switch (p_event->evt_type) { case APP_UART_DATA_READY: UNUSED_VARIABLE(app_uart_get(&data_array[index])); index++; if ((data_array[index - 1] == '\n') || (index >= (BLE_NUS_MAX_DATA_LEN))) { err_code = ble_nus_string_send(&m_nus, data_array, index); //蓝牙无线发送 if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } index = 0; } break; case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; }}static void uart_init(void){ uint32_t err_code; const app_uart_comm_params_t comm_params = { RX_PIN_NUMBER, TX_PIN_NUMBER, RTS_PIN_NUMBER, CTS_PIN_NUMBER, APP_UART_FLOW_CONTROL_DISABLED, //禁止硬件流控制 false, UART_BAUDRATE_BAUDRATE_Baud115200 }; APP_UART_FIFO_INIT( &comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_event_handle, //串口接收事件处理(串口接收-蓝牙发送) APP_IRQ_PRIORITY_LOW, err_code); APP_ERROR_CHECK(err_code);}
- 串口私有服务UUID
私有服务UUID服务的添加在ble_nus_init中实现:
rx_char_add(p_nus, p_nus_init); //添加串口接收特征字节
tx_char_add(p_nus, p_nus_init); //添加串口发送特征
串口私有服务通过扫描响应的方式告诉主设备对应的服务UUID信息,在advertising_init()中添加扫描响应数据;
static ble_uuid_t m_adv_uuids[] = {
{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
3.调试
通过keil编译下载程序到测试板中,通过手机BLE调试助手和PC的串口调试助手即可实现蓝牙串口简单的数据透传。