基于WisBlock与Arduino的蓝牙数据透传实战:从传感器到手机交互
2026/8/19 14:30:34 网站建设 项目流程

1. 项目概述:从零开始玩转蓝牙数据透传

最近在捣鼓物联网原型开发,发现很多朋友对如何快速实现设备间的无线数据通信很感兴趣,尤其是蓝牙这种几乎每台智能设备都标配的技术。正好手边有一套 RAK 的 WisBlock Starter Kit,这玩意儿简直就是为快速验证物联网点子而生的。今天我就以这套开发套件为核心,手把手带你走通“通过蓝牙发送数据”的完整流程。无论你是想做个无线传感器数据采集器,还是想实现手机对嵌入式设备的简单控制,这个项目都能给你一个清晰的起点。

简单来说,我们要做的事情就是:利用 WisBlock Starter Kit 中的核心板(通常基于 Nordic nRF52840 这类支持蓝牙的芯片)和必要的传感器或IO模块,编写固件让其变成一个蓝牙外设(Peripheral),然后通过手机上的蓝牙调试APP(比如热门的 Serial Bluetooth Terminal)与之连接,并实现双向的数据收发。这听起来像是蓝牙最基础的应用,但其中涉及的配置细节、数据协议设计以及调试技巧,往往是新手最容易卡壳的地方。通过这个项目,你不仅能学会操作,更能理解在资源受限的嵌入式设备上实现可靠蓝牙通信的底层逻辑和实用技巧。

2. 硬件与工具准备:认识你的“武器库”

工欲善其事,必先利其器。在开始写代码之前,我们得先搞清楚手头有什么,以及还需要准备什么。

2.1 WisBlock Starter Kit 核心组件解析

WisBlock 模块化设计是其最大亮点,它像乐高一样,通过标准的接口将不同功能的模块拼接在一起。对于蓝牙数据通信项目,我们通常需要以下核心模块:

  1. 核心板(WisBlock Core):这是大脑。Starter Kit 里通常是 RAK4631(基于 Nordic nRF52840)或 RAK3172(基于 STM32WLE5)等。它们共同的特点是集成了低功耗蓝牙(BLE)射频部分和一颗微控制器。nRF52840因其强大的生态和丰富的片上资源,在BLE开发中尤为流行,它支持蓝牙5.0,拥有充足的Flash和RAM,能轻松运行复杂的协议栈和应用逻辑。

  2. 底座板(WisBlock Base):这是骨架,型号如 RAK5005-O。它提供了电源管理、模块接口(用于插接核心板、传感器板、IO扩展板)以及USB转串口芯片。通过底座板的USB-C口,我们既能给整个系统供电,也能在电脑上看到一个虚拟串口(COM口),用于下载程序和输出调试信息,这是后续开发的关键通道。

  3. 功能模块(可选但推荐):为了演示数据“有米可炊”,建议插上一块传感器模块,比如RAK1901(温湿度传感器)RAK1904(气压传感器)。这样我们就能采集真实的环境数据并通过蓝牙发送出去,让项目更生动。

注意:在组装时,务必确保所有模块的接口对齐,并用力按压直至听到清脆的“咔嗒”声,确保连接器完全锁紧。接触不良是导致后续各种灵异问题(如无法下载、传感器读取失败)的首要元凶。

2.2 软件与辅助工具清单

硬件搭好了,软件环境也得跟上:

  1. 集成开发环境(IDE)Arduino IDE是入门首选。RAK 为 WisBlock 提供了完善的 Arduino 板支持包(BSP),封装了底层细节,让我们能专注于应用逻辑。你需要先在 Arduino IDE 的“开发板管理器”中添加 RAKwireless 的板支持网址,然后搜索并安装“RAKwireless WisBlock Boards”。

  2. 手机端调试APP:这是与你的蓝牙设备交互的窗口。Serial Bluetooth Terminal是应用商店里非常流行的一款,它界面简洁,支持连接BLE设备,并以串口形式收发数据,完美契合我们的需求。当然,你也可以使用 nRF Connect 这类更专业的工具进行底层服务和特征值的探索。

  3. 驱动程序:将 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): 属性为WriteWrite 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"); } }

代码关键点解析:

  1. Bluefruit.begin():初始化 BLE 协议栈,这是所有 BLE 操作的基础。
  2. Bluefruit.setName():设置广播的设备名,务必起一个容易识别的名字。
  3. bleuart.begin():初始化 Nordic UART Service。这个库函数帮我们创建了符合 NUS 规范的服务和特征值,无需手动定义 UUID。
  4. 广播配置Bluefruit.Advertising下的系列函数设置了广播参数。addService(bleuart)至关重要,它将 UART 服务的 UUID 包含在广播包中,让手机APP能识别出这是一个支持串口功能的设备。
  5. 数据发送bleuart.write()函数将数据通过 BLE 发送出去。这里有一个重要细节:BLE 协议对单个数据包有长度限制(通常 ATT_MTU 为 20-23 字节)。虽然bleuart.write()内部会处理分包,但一次性发送过长的数据(比如超过100字节)仍可能导致效率低下或问题。最佳实践是控制单次发送的数据块大小。
  6. 数据接收bleuart.available()bleuart.readStringUntil()用于接收手机发来的数据,其用法与硬件串口Serial对象非常相似,降低了学习成本。
  7. 连接管理:回调函数connect_callbackdisconnect_callback让你能在设备连接状态改变时执行特定操作,比如连接后加速传感器采样,断开后进入深度睡眠省电。

4.3 编译与上传

在 Arduino IDE 中:

  1. 选择开发板:“工具” -> “开发板” -> “RAKwireless WisBlock Boards” -> 选择你对应的核心板型号(如 RAK4631)。
  2. 选择端口:将 WisBlock 通过 USB 连接到电脑,在“工具”->“端口”中选择出现的串口(如 COMx 或 /dev/cu.usbmodemXXX)。
  3. 点击上传。编译无误后,代码将被烧录到核心板。上传完成后,打开 IDE 的串口监视器,波特率设置为 115200,你应该能看到“BLE UART and Sensor are ready!”的提示,并且每隔5秒打印一次传感器数据。

5. 手机端连接与数据交互实战

固件在设备上跑起来后,就该用手机和它“对话”了。

5.1 使用 Serial Bluetooth Terminal 进行连接

  1. 打开手机蓝牙功能。
  2. 打开Serial Bluetooth TerminalAPP。
  3. 点击界面上的“连接”按钮或类似选项。APP 会开始扫描周围的 BLE 设备。
  4. 在设备列表中,你应该能找到名为“WisBlock-Env-Sensor”的设备。点击它进行连接。
  5. 连接成功后,APP 界面通常会显示“Connected”,并且可能自动打开一个接收文本的窗口。

5.2 数据收发测试与协议约定

  • 接收数据:连接成功后,你无需任何操作,应该就能在 APP 的接收框里看到每隔5秒出现一行的数据,格式如T:25.60,H:45.20。这就是从 WisBlock 主动上报的传感器数据。
  • 发送命令:在 APP 的发送输入框里,输入我们在代码中定义的命令,例如LED_ON,然后点击发送。观察 WisBlock 核心板上的 LED(如果有的话)是否点亮,同时接收框里应该会收到设备回复的LED is ON。同理,可以测试LED_OFFGET_DATA命令。

关于通信协议的思考:我们上面使用了简单的字符串命令和\n换行符作为分隔。这对于简单交互足够了。但在更复杂的项目中,你需要设计更健壮的协议,例如:

  • 帧结构:可以定义类似[起始符][命令字][长度][数据][校验和][结束符]的二进制帧结构,提高抗干扰和数据完整性校验能力。
  • JSON格式:对于复杂数据,可以使用轻量级的 JSON 字符串,方便手机端解析。例如:{"cmd":"set_interval", "value":10000}

实操心得:在 Serial Bluetooth Terminal 中,注意发送时是否自动添加了换行符。有些APP的输入框有“发送新行”的选项。我们的代码使用readStringUntil('\n'),所以确保发送的命令以换行符结尾。如果命令没反应,第一个要排查的就是这里。

6. 功耗优化与进阶调试技巧

一个简单的数据透传做完了,但要让项目更实用、更专业,我们还得考虑功耗和稳定性。

6.1 低功耗优化策略

我们的代码目前是delay(5000)进行简单延时,在延时期间 CPU 仍在全速运行,并不节能。对于电池供电的物联网设备,优化功耗至关重要。

  1. 使用低功耗延时:许多 BLE 库(包括 Adafruit/RAK 使用的)提供了低功耗延时函数,它会在延时期间让 CPU 进入睡眠模式。例如,可以将delay(5000)替换为Bluefruit.Advertising.start(0);后的sd_ble_gap_conn_param_update等机制,或者利用库提供的waitForEvent()类函数。更直接的方法是使用定时器中断RTC 唤醒
  2. 调整广播参数Bluefruit.Advertising.setInterval(32, 244)设置了广播间隔。第一个参数是最小间隔(320.625ms=20ms),第二个是最大间隔(2440.625ms=152.5ms)。更长的间隔可以显著降低广播阶段的功耗,但也会让手机发现设备的速度变慢。在需要快速连接和低功耗之间权衡。
  3. 连接后的功耗:连接间隔由手机和设备协商决定。在connect_callback中,可以请求更长的连接间隔来省电,但这会影响数据实时性。
  4. 断开连接后进入深度睡眠:在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_callbackdisconnect_callback中打印信息,在发送数据前后打印长度等。

7. 项目扩展与更多可能性

这个基础的蓝牙数据透传项目就像一个乐高底座,你可以在此基础上添加更多模块,实现更丰富的功能:

  1. 多传感器融合:除了温湿度,可以增加光照(RAK1903)、加速度(RAK1905)等模块,打包多种环境数据一起上报。
  2. 数据上报云平台:让 WisBlock Core 同时连接 Wi-Fi(使用 RAK11200 等 Wi-Fi 核心板或模块),将蓝牙收集的数据,或者通过蓝牙接收的手机指令,转发到阿里云、腾讯云等物联网平台,实现远程监控。
  3. 实现蓝牙 Mesh 组网:如果使用支持 Mesh 的芯片(如 nRF52840),可以组建一个蓝牙 Mesh 网络,让多个 WisBlock 节点相互通信,其中一个节点作为网关与手机通信,覆盖更大范围。
  4. 开发定制化手机APP:抛弃通用的串口调试APP,使用 MIT App Inventor、React Native 或 Flutter 等工具开发专属APP,设计更友好的界面,实现数据图表化展示、历史记录、智能告警等功能。
  5. 增加本地存储:插入一块 microSD 卡模块(RAK1907),在蓝牙断开时将数据临时存储在本地,待连接后再同步到手机,防止数据丢失。

这个项目最大的价值在于,它为你打通了从物理世界感知到移动端交互的完整链路。当你掌握了这些基础,再去探索更复杂的协议、更低的功耗或更远的距离,就有了坚实的立足点。硬件开发就是这样,从一个点亮的 LED,到一个能通信的节点,再到一个完整的系统,每一步的成就感都实实在在。希望这篇长文能帮你少走些弯路,更快地把想法变成现实。如果在实际操作中遇到新的问题,不妨回头看看串口打印的日志,那里面往往藏着答案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询