公司动态

基于WisBlock与Arduino的蓝牙数据透传实战:从传感器到手机交互

📅 2026/8/19 14:30:58
基于WisBlock与Arduino的蓝牙数据透传实战:从传感器到手机交互
1. 项目概述从零开始玩转蓝牙数据透传最近在捣鼓物联网原型开发发现很多朋友对如何快速实现设备间的无线数据通信很感兴趣尤其是蓝牙这种几乎每台智能设备都标配的技术。正好手边有一套 RAK 的 WisBlock Starter Kit这玩意儿简直就是为快速验证物联网点子而生的。今天我就以这套开发套件为核心手把手带你走通“通过蓝牙发送数据”的完整流程。无论你是想做个无线传感器数据采集器还是想实现手机对嵌入式设备的简单控制这个项目都能给你一个清晰的起点。简单来说我们要做的事情就是利用 WisBlock Starter Kit 中的核心板通常基于 Nordic nRF52840 这类支持蓝牙的芯片和必要的传感器或IO模块编写固件让其变成一个蓝牙外设Peripheral然后通过手机上的蓝牙调试APP比如热门的 Serial Bluetooth Terminal与之连接并实现双向的数据收发。这听起来像是蓝牙最基础的应用但其中涉及的配置细节、数据协议设计以及调试技巧往往是新手最容易卡壳的地方。通过这个项目你不仅能学会操作更能理解在资源受限的嵌入式设备上实现可靠蓝牙通信的底层逻辑和实用技巧。2. 硬件与工具准备认识你的“武器库”工欲善其事必先利其器。在开始写代码之前我们得先搞清楚手头有什么以及还需要准备什么。2.1 WisBlock Starter Kit 核心组件解析WisBlock 模块化设计是其最大亮点它像乐高一样通过标准的接口将不同功能的模块拼接在一起。对于蓝牙数据通信项目我们通常需要以下核心模块核心板WisBlock Core这是大脑。Starter Kit 里通常是 RAK4631基于 Nordic nRF52840或 RAK3172基于 STM32WLE5等。它们共同的特点是集成了低功耗蓝牙BLE射频部分和一颗微控制器。nRF52840因其强大的生态和丰富的片上资源在BLE开发中尤为流行它支持蓝牙5.0拥有充足的Flash和RAM能轻松运行复杂的协议栈和应用逻辑。底座板WisBlock Base这是骨架型号如 RAK5005-O。它提供了电源管理、模块接口用于插接核心板、传感器板、IO扩展板以及USB转串口芯片。通过底座板的USB-C口我们既能给整个系统供电也能在电脑上看到一个虚拟串口COM口用于下载程序和输出调试信息这是后续开发的关键通道。功能模块可选但推荐为了演示数据“有米可炊”建议插上一块传感器模块比如RAK1901温湿度传感器或RAK1904气压传感器。这样我们就能采集真实的环境数据并通过蓝牙发送出去让项目更生动。注意在组装时务必确保所有模块的接口对齐并用力按压直至听到清脆的“咔嗒”声确保连接器完全锁紧。接触不良是导致后续各种灵异问题如无法下载、传感器读取失败的首要元凶。2.2 软件与辅助工具清单硬件搭好了软件环境也得跟上集成开发环境IDEArduino IDE是入门首选。RAK 为 WisBlock 提供了完善的 Arduino 板支持包BSP封装了底层细节让我们能专注于应用逻辑。你需要先在 Arduino IDE 的“开发板管理器”中添加 RAKwireless 的板支持网址然后搜索并安装“RAKwireless WisBlock Boards”。手机端调试APP这是与你的蓝牙设备交互的窗口。Serial Bluetooth Terminal是应用商店里非常流行的一款它界面简洁支持连接BLE设备并以串口形式收发数据完美契合我们的需求。当然你也可以使用 nRF Connect 这类更专业的工具进行底层服务和特征值的探索。驱动程序将 WisBlock 通过 USB 连接到电脑后可能需要安装 CP210x 或 CH340 等 USB 转串口芯片的驱动以便 Arduino IDE 能识别到正确的端口。3. 项目设计与蓝牙协议浅析在动手写代码前花几分钟理解一下设计思路和蓝牙的基本工作模式能让你在调试时事半功倍。3.1 系统架构与数据流设计我们这个项目的架构非常清晰感知层WisBlock 传感器模块负责采集物理世界的数据如温度、湿度。核心控制与通信层WisBlock Core 运行我们的固件。它一方面通过 I2C 或 SPI 总线读取传感器数据另一方面运行 BLE 协议栈扮演“蓝牙外设”的角色。应用层手机上的 Serial Bluetooth Terminal APP作为“蓝牙中心设备”主动扫描并连接我们的 WisBlock然后接收数据或发送控制命令。数据流是双向的上行数据上报传感器 - 核心板MCU - BLE协议栈封装 - 无线射频发射 - 手机APP接收并显示。下行命令控制手机APP输入命令 - 无线射频发射 - 核心板BLE协议栈解析 - MCU处理命令如控制LED、修改采样率- 执行动作。3.2 蓝牙低功耗BLE通信模型关键概念对于数据透传我们通常利用 BLE 的“服务”和“特征值”模型来实现一个虚拟的串口即 SPP 或 UART 服务。在这个模型里服务可以理解为一个功能容器。例如一个“电池服务”包含了电量相关的信息一个“设备信息服务”包含了厂商名称、型号等。对于我们最关键的是一个叫做“Nordic UART Service”的服务它的 UUID 是6E400001-B5A3-F393-E0A9-E50E24DCCA9E。这个服务被广泛用于模拟串行通信。特征值每个服务包含若干个特征值它们是实际存储和传输数据的单元。每个特征值有属性读、写、通知、指示等。在 Nordic UART Service 中通常有两个关键特征TX 特征(UUID:6E400002-B5A3-F393-E0A9-E50E24DCCA9E): 属性为Write或Write without response。手机向这个特征写入数据相当于向设备发送指令。RX 特征(UUID:6E400003-B5A3-F393-E0A9-E50E24DCCA9E): 属性为Notify。设备通过这个特征“通知”手机新数据到达。手机需要先启用该特征的“通知”功能才能自动接收数据。为什么选择 Nordic UART Service (NUS)因为它本质上定义了一个简单的、基于数据流的协议极其适合传输不定长的、简单的指令或数据包无需自己从头定义复杂的服务结构兼容性好大多数蓝牙串口APP都支持。4. 固件开发详解从环境搭建到代码实现接下来就是核心的编码环节。我们将使用 Arduino 框架和 RAK 的 BSP 库来快速实现功能。4.1 开发环境配置与库安装首先确保你的 Arduino IDE 已安装好 WisBlock 支持。打开 IDE依次点击“文件”-“首选项”在“附加开发板管理器网址”中添加https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json然后在“工具”-“开发板”-“开发板管理器”中搜索“RAK”安装“RAKwireless WisBlock Boards”。安装必要的库。在“项目”-“加载库”-“管理库”中搜索并安装Adafruit BME280(如果你使用 RAK1906 环境传感器模块)。BLEPeripheral或 RAK BSP 自带的 BLE 库通常已集成无需单独安装。4.2 核心代码实现与逐行解析下面是一个集成温湿度传感器和 BLE 串口功能的示例代码框架。我将关键部分拆解开来讲解。#include Arduino.h #include bluefruit.h // RAK BSP 使用的BLE库基于Adafruit BluefruitLE #include Wire.h #include Adafruit_BME280.h // 以BME280为例 // 定义BLE UART服务 BLEUart bleuart; // 定义传感器对象 Adafruit_BME280 bme; // 传感器数据变量 float temperature, humidity; void setup() { // 初始化串口用于调试 Serial.begin(115200); while (!Serial) delay(10); // 等待串口就绪仅用于调试 // 初始化I2C总线以连接传感器 Wire.begin(); // 初始化BME280传感器 if (!bme.begin(0x76)) { // 0x76是常见I2C地址 Serial.println(Could not find a valid BME280 sensor, check wiring!); while (1); // 停止执行 } // 配置并启动BLE Bluefruit.begin(); // 设置设备名称这个名称会在手机蓝牙扫描列表中显示 Bluefruit.setName(WisBlock-Env-Sensor); // 设置连接回调函数 Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setDisconnectCallback(disconnect_callback); // 配置并启动BLE UART服务 bleuart.begin(); // 开始广播允许手机发现并连接 Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); Bluefruit.Advertising.addTxPower(); Bluefruit.Advertising.addService(bleuart); // 将UART服务加入广播数据包 Bluefruit.Advertising.restartOnDisconnect(true); Bluefruit.Advertising.setInterval(32, 244); // 广播间隔单位0.625ms Bluefruit.Advertising.setFastTimeout(30); // 快速广播超时时间秒 Bluefruit.Advertising.start(0); // 0表示持续广播直到连接 Serial.println(BLE UART and Sensor are ready!); } void loop() { // 1. 读取传感器数据 temperature bme.readTemperature(); humidity bme.readHumidity(); // 2. 通过串口打印到电脑用于调试 Serial.print(Temp: ); Serial.print(temperature); Serial.print( °C, Humi: ); Serial.print(humidity); Serial.println( %); // 3. 通过BLE UART发送到手机如果已连接 if (Bluefruit.connected()) { char buffer[64]; // 将数据格式化为字符串 int len snprintf(buffer, sizeof(buffer), T:%.2f,H:%.2f\n, temperature, humidity); // 通过bleuart对象发送 bleuart.write(buffer, len); } // 4. 检查是否收到来自手机的命令 if (bleuart.available()) { String command bleuart.readStringUntil(\n); // 假设命令以换行符结束 command.trim(); processCommand(command); // 处理命令 } // 延时控制数据上报频率例如每5秒一次 delay(5000); } // BLE连接事件回调函数 void connect_callback(uint16_t conn_handle) { Serial.println(Client connected!); } void disconnect_callback(uint16_t conn_handle, uint8_t reason) { Serial.println(Client disconnected!); } // 处理来自手机的命令 void processCommand(String cmd) { Serial.print(Received command: ); Serial.println(cmd); if (cmd LED_ON) { digitalWrite(LED_BUILTIN, HIGH); bleuart.println(LED is ON); } else if (cmd LED_OFF) { digitalWrite(LED_BUILTIN, LOW); bleuart.println(LED is OFF); } else if (cmd GET_DATA) { // 立即发送一次数据 char buffer[64]; int len snprintf(buffer, sizeof(buffer), T:%.2f,H:%.2f\n, temperature, humidity); bleuart.write(buffer, len); } else { bleuart.println(Unknown command); } }代码关键点解析Bluefruit.begin()初始化 BLE 协议栈这是所有 BLE 操作的基础。Bluefruit.setName()设置广播的设备名务必起一个容易识别的名字。bleuart.begin()初始化 Nordic UART Service。这个库函数帮我们创建了符合 NUS 规范的服务和特征值无需手动定义 UUID。广播配置Bluefruit.Advertising下的系列函数设置了广播参数。addService(bleuart)至关重要它将 UART 服务的 UUID 包含在广播包中让手机APP能识别出这是一个支持串口功能的设备。数据发送bleuart.write()函数将数据通过 BLE 发送出去。这里有一个重要细节BLE 协议对单个数据包有长度限制通常 ATT_MTU 为 20-23 字节。虽然bleuart.write()内部会处理分包但一次性发送过长的数据比如超过100字节仍可能导致效率低下或问题。最佳实践是控制单次发送的数据块大小。数据接收bleuart.available()和bleuart.readStringUntil()用于接收手机发来的数据其用法与硬件串口Serial对象非常相似降低了学习成本。连接管理回调函数connect_callback和disconnect_callback让你能在设备连接状态改变时执行特定操作比如连接后加速传感器采样断开后进入深度睡眠省电。4.3 编译与上传在 Arduino IDE 中选择开发板“工具” - “开发板” - “RAKwireless WisBlock Boards” - 选择你对应的核心板型号如 RAK4631。选择端口将 WisBlock 通过 USB 连接到电脑在“工具”-“端口”中选择出现的串口如 COMx 或 /dev/cu.usbmodemXXX。点击上传。编译无误后代码将被烧录到核心板。上传完成后打开 IDE 的串口监视器波特率设置为 115200你应该能看到“BLE UART and Sensor are ready!”的提示并且每隔5秒打印一次传感器数据。5. 手机端连接与数据交互实战固件在设备上跑起来后就该用手机和它“对话”了。5.1 使用 Serial Bluetooth Terminal 进行连接打开手机蓝牙功能。打开Serial Bluetooth TerminalAPP。点击界面上的“连接”按钮或类似选项。APP 会开始扫描周围的 BLE 设备。在设备列表中你应该能找到名为“WisBlock-Env-Sensor”的设备。点击它进行连接。连接成功后APP 界面通常会显示“Connected”并且可能自动打开一个接收文本的窗口。5.2 数据收发测试与协议约定接收数据连接成功后你无需任何操作应该就能在 APP 的接收框里看到每隔5秒出现一行的数据格式如T:25.60,H:45.20。这就是从 WisBlock 主动上报的传感器数据。发送命令在 APP 的发送输入框里输入我们在代码中定义的命令例如LED_ON然后点击发送。观察 WisBlock 核心板上的 LED如果有的话是否点亮同时接收框里应该会收到设备回复的LED is ON。同理可以测试LED_OFF和GET_DATA命令。关于通信协议的思考我们上面使用了简单的字符串命令和\n换行符作为分隔。这对于简单交互足够了。但在更复杂的项目中你需要设计更健壮的协议例如帧结构可以定义类似[起始符][命令字][长度][数据][校验和][结束符]的二进制帧结构提高抗干扰和数据完整性校验能力。JSON格式对于复杂数据可以使用轻量级的 JSON 字符串方便手机端解析。例如{cmd:set_interval, value:10000}。实操心得在 Serial Bluetooth Terminal 中注意发送时是否自动添加了换行符。有些APP的输入框有“发送新行”的选项。我们的代码使用readStringUntil(\n)所以确保发送的命令以换行符结尾。如果命令没反应第一个要排查的就是这里。6. 功耗优化与进阶调试技巧一个简单的数据透传做完了但要让项目更实用、更专业我们还得考虑功耗和稳定性。6.1 低功耗优化策略我们的代码目前是delay(5000)进行简单延时在延时期间 CPU 仍在全速运行并不节能。对于电池供电的物联网设备优化功耗至关重要。使用低功耗延时许多 BLE 库包括 Adafruit/RAK 使用的提供了低功耗延时函数它会在延时期间让 CPU 进入睡眠模式。例如可以将delay(5000)替换为Bluefruit.Advertising.start(0);后的sd_ble_gap_conn_param_update等机制或者利用库提供的waitForEvent()类函数。更直接的方法是使用定时器中断或RTC 唤醒。调整广播参数Bluefruit.Advertising.setInterval(32, 244)设置了广播间隔。第一个参数是最小间隔320.625ms20ms第二个是最大间隔2440.625ms152.5ms。更长的间隔可以显著降低广播阶段的功耗但也会让手机发现设备的速度变慢。在需要快速连接和低功耗之间权衡。连接后的功耗连接间隔由手机和设备协商决定。在connect_callback中可以请求更长的连接间隔来省电但这会影响数据实时性。断开连接后进入深度睡眠在disconnect_callback中可以停止所有不必要的功能如传感器持续采样甚至让 MCU 进入深度睡眠模式仅靠 RTC 或外部中断唤醒重新开始广播。一个简单的低功耗 loop 修改思路伪代码void loop() { if (Bluefruit.connected()) { // 连接状态下正常执行数据采集和发送 readAndSendSensorData(); checkAndProcessCommand(); // 使用低功耗等待等待下一个连接事件或超时 idle(); } else { // 未连接状态下除了必要的广播维护进入低功耗模式 // 例如使用库提供的低功耗延时或直接进入睡眠 lowPowerDelay(MAIN_LOOP_INTERVAL); } }6.2 常见问题排查与调试技巧实录开发过程中难免遇到问题这里记录几个我踩过的坑和解决方法问题1手机扫描不到蓝牙设备。可能原因与排查广播未启动检查代码中Bluefruit.Advertising.start(0)是否执行。设备名不符合规范某些APP对设备名有过滤尝试使用简单的英文名。广播数据过长确保没有在广播包里添加过多不必要的服务UUID或数据。物理距离与干扰靠近设备避开强 Wi-Fi 路由器或微波炉等 2.4GHz 干扰源。硬件问题重新插拔核心板确认天线如果外置连接良好。问题2手机能连接但收不到数据或发送命令没反应。可能原因与排查未启用通知对于接收数据RX特征手机APP必须主动启用“通知”Enable Notifications。Serial Bluetooth Terminal 通常会在连接时自动完成但有些专业工具需要手动点击。数据发送频率过快BLE 吞吐量有限如果 loop 中不加延时疯狂发送可能导致缓冲区溢出或协议栈异常。确保有合理的间隔。数据包长度单次bleuart.write()的数据不要超过 BLE 协议栈能处理的长度。虽然库会分包但小包如20字节以内更可靠。字符串格式不匹配代码中使用readStringUntil(\n)但手机发送的命令没有以换行符结尾。或者手机发送了换行符但代码中是读取直到其他字符。问题3连接不稳定经常断开。可能原因与排查信号强度弱确保设备与手机之间没有严重遮挡距离不要太远。电源不稳定如果使用电池检查电压是否充足。USB 供电接触不良也会导致复位。软件看门狗复位如果代码中有复杂操作或阻塞时间过长可能触发看门狗复位。确保loop()函数执行时间不会太长或者及时喂狗。连接参数不合理连接间隔太短可能增加功耗和系统负担太长可能导致响应慢。一般保持默认即可。问题4传感器数据读取失败。可能原因与排查I2C 地址错误使用Wire库的扫描示例代码确认传感器的实际 I2C 地址。供电问题某些传感器需要 3.3V 稳定供电检查底座板跳线帽是否设置正确。库不兼容确保安装的传感器库与你的硬件版本匹配。调试利器串口日志在整个开发过程中务必充分利用硬件串口Serial输出调试信息。将关键步骤的状态、变量的值、错误代码打印出来是定位问题最快的方法。例如在connect_callback和disconnect_callback中打印信息在发送数据前后打印长度等。7. 项目扩展与更多可能性这个基础的蓝牙数据透传项目就像一个乐高底座你可以在此基础上添加更多模块实现更丰富的功能多传感器融合除了温湿度可以增加光照RAK1903、加速度RAK1905等模块打包多种环境数据一起上报。数据上报云平台让 WisBlock Core 同时连接 Wi-Fi使用 RAK11200 等 Wi-Fi 核心板或模块将蓝牙收集的数据或者通过蓝牙接收的手机指令转发到阿里云、腾讯云等物联网平台实现远程监控。实现蓝牙 Mesh 组网如果使用支持 Mesh 的芯片如 nRF52840可以组建一个蓝牙 Mesh 网络让多个 WisBlock 节点相互通信其中一个节点作为网关与手机通信覆盖更大范围。开发定制化手机APP抛弃通用的串口调试APP使用 MIT App Inventor、React Native 或 Flutter 等工具开发专属APP设计更友好的界面实现数据图表化展示、历史记录、智能告警等功能。增加本地存储插入一块 microSD 卡模块RAK1907在蓝牙断开时将数据临时存储在本地待连接后再同步到手机防止数据丢失。这个项目最大的价值在于它为你打通了从物理世界感知到移动端交互的完整链路。当你掌握了这些基础再去探索更复杂的协议、更低的功耗或更远的距离就有了坚实的立足点。硬件开发就是这样从一个点亮的 LED到一个能通信的节点再到一个完整的系统每一步的成就感都实实在在。希望这篇长文能帮你少走些弯路更快地把想法变成现实。如果在实际操作中遇到新的问题不妨回头看看串口打印的日志那里面往往藏着答案。