保姆级教程:在NRF52840上实现USB虚拟串口(基于nRF5 SDK 17.0.2)

张开发
2026/4/20 12:09:20 15 分钟阅读

分享文章

保姆级教程:在NRF52840上实现USB虚拟串口(基于nRF5 SDK 17.0.2)
NRF52840 USB虚拟串口开发实战从零构建双向通信系统在嵌入式开发领域USB通信一直是连接设备与主机的重要桥梁。NRF52840作为Nordic Semiconductor推出的高性能蓝牙5.0/低功耗蓝牙SoC其内置的USB 2.0全速控制器为开发者提供了便捷的通信解决方案。本文将带你从零开始在nRF5 SDK 17.0.2环境下基于PCA10056开发板实现一个完整的USB虚拟串口(CDC ACM)通信系统。1. 开发环境准备与工程配置1.1 硬件与软件基础开始之前确保你已准备好以下硬件和软件硬件设备NRF52840开发板(PCA10056)USB Type-A转Micro-USB数据线支持USB OTG的安卓设备(可选)软件工具nRF5 SDK 17.0.2Segger Embedded Studio或Keil MDKJ-Link驱动PC端串口调试工具(Tera Term、Putty等)Android Studio(用于安卓端测试)提示确保开发板的USB接口连接稳定避免因供电不足导致通信异常。1.2 SDK安装与例程定位nRF5 SDK提供了丰富的USB通信例程我们将基于usbd_ble_uart例程进行修改解压nRF5_SDK_17.0.2到本地目录导航至examples/peripheral/usbd_ble_uart/pca10056/s140/arm5_no_packs打开工程文件(ses/ble_usbd_uart.emProject或keil5/ble_usbd_uart.uvprojx)# SDK目录结构示例 nRF5_SDK_17.0.2/ ├── components/ ├── documentation/ ├── examples/ │ └── peripheral/ │ └── usbd_ble_uart/ │ └── pca10056/ │ └── s140/ │ └── arm5_no_packs/ └── external/2. USB CDC ACM功能实现2.1 定时器功能集成为了实现每秒发送一次数据的功能我们需要添加1Hz定时器#define TICK_1HZ_INTERVAL 32768 /* 1Hz定时器间隔(使用32.768kHz时钟) */ APP_TIMER_DEF(m_1hz_id); static nrf_atomic_u32_t m_1hz_evt; static void tick_1hz_timeout_handler(void * p_context) { UNUSED_PARAMETER(p_context); UNUSED_RETURN_VALUE(nrf_atomic_u32_or(m_1hz_evt, 1)); } static void timers_init(void) { ret_code_t err_code app_timer_init(); APP_ERROR_CHECK(err_code); err_code app_timer_create(m_1hz_id, APP_TIMER_MODE_REPEATED, tick_1hz_timeout_handler); APP_ERROR_CHECK(err_code); err_code app_timer_start(m_1hz_id, TICK_1HZ_INTERVAL, NULL); APP_ERROR_CHECK(err_code); }2.2 主循环数据处理在主循环中处理定时器事件并发送数据static uint32_t tick_cnt; int main(void) { // 初始化代码... for (;;) { while (app_usbd_event_queue_process()) { /* 处理USB事件 */ } uint32_t events nrf_atomic_u32_fetch_store(m_1hz_evt, 0); if (events m_uart_connected) { tick_cnt; char buf[32]; uint32_t length sprintf(buf, Tick %d\n, tick_cnt); memcpy(m_nus_data_array, buf, length); ret_code_t ret app_usbd_cdc_acm_write(m_app_cdc_acm, m_nus_data_array, length); if(ret ! NRF_SUCCESS) { NRF_LOG_INFO(CDC ACM unavailable); } } idle_state_handle(); } }3. 数据接收处理与调试3.1 USB数据接收实现在CDC ACM事件处理函数中添加接收逻辑case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: { ret_code_t ret; uint8_t index 0; do { /* 获取接收数据大小 */ size_t size app_usbd_cdc_acm_rx_size(p_cdc_acm); /* 读取数据直到缓冲区为空 */ ret app_usbd_cdc_acm_read(m_app_cdc_acm, m_cdc_data_array[index], 1); if (ret NRF_SUCCESS) { index; } } while (ret NRF_SUCCESS); m_cdc_data_array[index] \0; // 添加字符串结束符 NRF_LOG_INFO(Received: %s, m_cdc_data_array); break; }3.2 调试与日志输出NRF52840提供了多种调试方式调试方式优点缺点RTT Viewer实时性强无需额外硬件需要占用少量RAMUART日志简单易用需要额外UART引脚Segger SystemView可视化任务调度配置复杂推荐使用RTT Viewer进行调试连接J-Link调试器打开J-Link RTT Viewer选择目标设备为NRF52840_XXAA设置RTT控制块地址为0x20000000(默认值)4. PC端与安卓端通信测试4.1 PC端串口工具配置在Windows平台上测试USB虚拟串口连接开发板USB接口等待驱动自动安装(或手动安装SDK中的usb_drivers)打开串口工具选择正确的COM端口设置参数波特率115200数据位8停止位1无校验确保勾选DTR选项打开串口应每秒收到Tick X消息注意某些串口工具可能需要手动发送DTR信号才能激活NRF52840的USB通信。4.2 安卓端USB通信配置对于安卓设备测试需要修改USB Vendor ID和Product ID在sdk_config.h中确认默认ID#define APP_USBD_VID 0x1915 // Nordic Semiconductor的Vendor ID #define APP_USBD_PID 0x521A // 示例Product ID在安卓工程中修改CustomProber.javaprivate static final int VENDOR_ID 0x1915; private static final int PRODUCT_ID 0x521A;安卓端操作流程安装修改后的APP连接开发板到安卓设备在APP中选择正确的USB设备设置波特率为115200勾选Control Lines选项连接后应能收到Tick数据5. 常见问题与性能优化5.1 典型问题排查以下是开发过程中可能遇到的常见问题及解决方案问题1PC无法识别USB设备检查USB线是否支持数据传输确认开发板供电充足尝试手动安装驱动问题2能识别但无法通信确认DTR信号已激活检查波特率设置是否匹配验证USB描述符配置问题3数据接收不完整增加接收缓冲区大小优化数据处理流程检查USB中断优先级5.2 性能优化技巧缓冲区管理#define CDC_ACM_DATA_IN_EP_SIZE 64 // 根据实际需求调整 #define CDC_ACM_DATA_OUT_EP_SIZE 64电源管理优化// 在usbd_config中启用低功耗特性 static const app_usbd_config_t usbd_config { .ev_state_proc usbd_user_ev_handler, .enable_low_power true };数据传输优化使用批量传输代替中断传输实现双缓冲机制合理设置USB中断优先级6. 进阶功能扩展6.1 多接口复合设备NRF52840支持同时实现多个USB接口可以创建复合设备修改USB描述符配置添加额外的接口类协调各接口的资源分配6.2 自定义Vendor ID申请如需产品化建议申请自己的Vendor ID访问USB-IF官网申请VID修改sdk_config.h中的定义更新所有相关工具配置6.3 无线固件更新(OTA)集成结合USB实现无线更新功能设计双区(bank)存储方案实现DFU协议集成nRF DFU库// DFU初始化示例 void dfu_init(void) { nrf_dfu_settings_init(); nrf_dfu_req_handler_init(); nrf_dfu_flash_init(true); }在实际项目中我发现NRF52840的USB性能足够满足大多数嵌入式应用需求但在高负载情况下需要注意及时处理USB事件以避免数据丢失。通过合理配置缓冲区和优化数据处理流程可以实现稳定的10KB/s以上的数据传输速率。

更多文章