
1. 项目概述与核心思路最近在折腾一块富芮坤的FR801xH物联网开发板这板子集成了蓝牙5.0和温湿度传感器很适合用来做低功耗的无线传感节点。官方的SDK里有个简单的蓝牙外设例程但功能比较基础。我就琢磨着能不能把它改造成一个能实时把温湿度数据推送到手机上的小玩意儿这样无论是做环境监测还是智能家居的demo都会直观很多。这个项目的核心目标很明确让FR801xH开发板通过蓝牙将板载SHT30传感器采集到的温湿度数据实时发送到手机App上显示。听起来简单但整个过程涉及嵌入式代码修改、蓝牙协议交互、手机端App调试等多个环节对于刚接触蓝牙开发或者富芮坤平台的朋友来说还是有不少细节需要注意的。接下来我就把整个从环境搭建到最终实现的完整过程以及我踩过的坑和总结的经验详细拆解一遍。2. 环境准备与工具链解析工欲善其事必先利其器。在动手写代码之前把开发环境搭建妥当是第一步也能避免后续很多莫名其妙的问题。2.1 硬件连接与供电检查FR801xH开发板到手后第一件事不是急着上电而是检查跳线帽。板子上有几个关键的跳线决定了芯片的启动模式和调试接口。启动模式跳线FR801xH支持从Flash启动或通过串口下载启动。对于我们的开发烧录通常需要将BOOT相关的跳线短接到UART模式具体位置请参考你的板子丝印。烧写完程序后再改回Flash模式才能正常运行。串口跳线板载的CH340 USB转串口芯片需要与MCU的UART引脚正确连接。确保连接开发板打印日志和供电的USB口对应的TX、RX跳线是短接的。传感器供电板载的SHT30温湿度传感器通常是I2C接口并已连接好。需要确认一下原理图确保传感器所在的I2C总线没有被其他设备占用且上拉电阻已就位。注意很多初次接触的朋友容易忽略跳线设置导致程序烧不进去或者烧进去不运行。务必对照官方开发板手册确认跳线状态。我的习惯是在烧录前拍照记录跳线位置烧录后再核对一遍避免混乱。2.2 软件开发环境搭建软件开发主要依赖三样东西集成开发环境IDE、芯片支持包、以及烧录工具。Keil MDK-ARM (uVision5)这是ARM Cortex-M内核开发最常用的IDE之一。你需要从Keil官网下载并安装MDK-ARM注意选择对应的版本例如MDK-ARM v5。安装后它只是一个“空壳”还需要芯片支持包。ARM.CMSIS 和 FR801xH Device Family Pack在Keil的Pack Installer图标像一个小盒子里你需要安装两个包。首先是ARM::CMSIS这是ARM Cortex微控制器软件接口标准必装。其次最关键的是找到并安装FR801xH的Device Family PackDFP。这个包包含了芯片的启动文件、外设寄存器定义、链接脚本等。如果Keil的官方仓库里没有你需要从富芮坤的官网或SDK包中找到.pack文件双击安装。FR8010H_Download_Tool这是富芮坤官方的烧录工具。它通常位于SDK包的tools目录下是一个独立的.exe文件。这个工具负责将Keil编译生成的.bin或.hex文件通过串口借助CH340烧写到开发板的Flash中。确保你电脑上已安装CH340的USB转串口驱动否则烧录工具可能识别不到串口。2.3 调试利器手机端与数据打包工具要让手机和开发板“对话”我们需要一个桥梁。这里我选择了一款功能强大的开源App“蓝牙调试器”以及与之配套的“蓝牙数据打包工具ValuePack”。蓝牙调试器App在手机应用商店搜索“蓝牙调试器”就能找到。它的强大之处在于“专业调试”模式允许用户自定义通信协议定义发送什么数据包以及如何解析接收到的数据包。这对于调试自定义的蓝牙服务非常方便远比一些只能收发字符串的调试工具强大。ValuePack工具这是一个由“蓝牙调试器”作者提供的开源代码库GitHub地址https://github.com/XieLazyDog/ValuePack。它的作用是在嵌入式端即我们的FR801xH代码里将多个不同类型的数据如整数、浮点数、字符串打包成一个连续的字节流数组并生成一个包含长度和校验信息的完整数据包。手机端的App则按照相同的规则解包还原出各个数据。使用这个工具可以极大地简化蓝牙传输复杂数据结构的编程工作你不需要自己去设计繁琐的封包/解包协议。2.4 辅助工具串口调试助手虽然我们的主通道是蓝牙但串口打印依然是嵌入式开发不可或缺的“眼睛”。在PC上使用一个串口调试助手如XCOM、SSCOM、Putty等连接开发板的日志输出串口可以实时查看程序运行的printf信息这对于排查问题、确认程序执行流程至关重要。确保在代码中初始化了日志串口并且波特率设置正确通常为115200。3. 工程创建与代码修改详解环境准备好后就可以进入核心的代码修改环节了。我们基于富芮坤SDK中提供的ble_simple_peripheral例程进行修改。3.1 导入基础工程与添加ValuePack首先在Keil中打开SDK路径下的示例工程SDK\examples\dev1.0\ble_simple_peripheral\project\keil5\...uvprojx。添加ValuePack源码将从GitHub下载的ValuePack代码文件夹通常包含value_pack.c和value_pack.h复制到你的工程目录下例如放在与main.c同级的目录。然后在Keil的工程管理窗口中在对应的组如Application/User上右键选择Add Existing Files to Group...将value_pack.c添加进来。包含头文件路径在Keil的工程选项Options for Target中切换到C/C标签页在Include Paths里添加ValuePack头文件所在的目录。这样编译器才能找到value_pack.h。在代码中包含头文件在需要使用ValuePack功能的源文件通常是处理蓝牙数据的那个文件开头添加#include “value_pack.h”。3.2 剖析蓝牙数据接收与处理流程富芮坤的BLE协议栈已经处理了底层的无线电通信。我们的应用层代码主要关注GATT通用属性协议。在simple_gatt_service.c文件中有一个关键的回调函数sp_gatt_write_cb。当手机客户端向开发板服务器的某个特征值Characteristic写入数据时这个函数就会被协议栈调用。我们的改造思路就发生在这里定义通信指令我们约定当手机向开发板发送一个字节数据0x47即十进制71字母‘G’的ASCII码我用来代表“Get”时就触发一次温湿度采集与上传。在回调中拦截指令在sp_gatt_write_cb函数中检查接收到的数据write_buf数组。如果发现第一个字节或约定的某个字节是0x47就执行后续操作。执行采集与打包调用SHT30传感器的驱动函数如sht3x_measure_blocking_read读取温湿度原始值。注意驱动返回的可能是整数需要根据数据手册转换成实际的物理值例如温度可能是温度值 原始值 / 1000.0单位℃。使用ValuePack工具进行打包调用startValuePack初始化一个缓冲区然后依次调用putFloat将转换后的温度和湿度浮点数放入包中最后调用endValuePack结束打包并获得最终数据包的长度和完整的字节数组。通过蓝牙通知发送数据使用BLE的“通知”Notification机制将打包好的字节数组发送给手机。通知是一种服务器主动向客户端推送数据的方式效率比“读”操作更高。调用类似gatt_notification的函数将数据包和长度填充到通知属性结构体中并发送出去。以下是修改sp_gatt_write_cb函数的核心代码逻辑示例#ifdef TYCON_DEBUG // 建议使用一个宏控制调试代码 uint8_t ble_ntf_buff[30]; // 定义一个足够大的缓冲区存放打包后的数据 uint8_t ble_ntf_length; int32_t temperature_raw, humidity_raw; float temperature, humidity; int8_t ret 0; // 假设我们约定写入数据的第一个字节为指令 if (write_len 0 write_buf[0] 0x47) { // 1. 读取SHT30传感器原始数据 ret sht3x_measure_blocking_read(temperature_raw, humidity_raw); if (ret ! 0) { co_printf(“SHT30 read failed: %d\r\n”, ret); return; // 读取失败直接返回 } // 2. 将原始值转换为实际物理值 (根据SHT30数据手册) temperature temperature_raw / 1000.0f; // 假设原始值扩大1000倍 humidity humidity_raw / 1000.0f; // 假设原始值扩大1000倍 co_printf(“Temp: %.2f C, Humi: %.2f %%\r\n”, temperature, humidity); // 3. 使用ValuePack打包数据 startValuePack(ble_ntf_buff); // 传入缓冲区 putFloat(temperature); // 打包温度浮点数 putFloat(humidity); // 打包湿度浮点数 ble_ntf_length endValuePack(); // 完成打包获取包长度 // 4. 通过蓝牙通知发送打包好的数据 struct gatt_notification ntf_att; ntf_att.data_len ble_ntf_length; ntf_att.p_data ble_ntf_buff; // 注意需要找到正确的连接句柄和特征值句柄这里用...表示 gatt_notification(…, ntf_att); co_printf(“Data sent to mobile via notification.\r\n”); } #endif实操心得在修改协议栈提供的回调函数时务必注意不要进行长时间阻塞的操作比如在函数里加长延时。BLE协议栈有实时性要求阻塞太久可能导致连接断开。像SHT30的blocking_read阻塞读取函数其阻塞时间通常在几十毫秒量级对于BLE连接来说通常是可接受的但如果传感器响应慢就需要考虑使用非阻塞方式或放在其他任务中处理。3.3 工程配置与编译代码修改完成后在编译前需要检查几个关键配置芯片型号与Flash/RAM设置在Keil的Options for Target - Device中确认选中了正确的FR801xH型号。在Target标签页根据芯片数据手册正确设置IROMFlash和IRAM的起始地址与大小。优化等级对于调试阶段建议使用Optimization Level 0 (-O0)关闭优化这样调试时变量查看和单步执行最符合代码逻辑。发布时再考虑提高优化等级以减小代码体积。宏定义在C/C标签页的Preprocessor Symbols中确保添加了你在代码中使用的调试宏例如TYCON_DEBUG。编译与解决错误点击编译按钮。常见的错误包括头文件找不到检查Include Paths是否添加完整。未定义的符号检查对应的.c文件是否已添加到工程或者函数名是否拼写错误。链接错误内存溢出检查Target中的内存设置是否正确或者代码是否过大。可以尝试调整优化等级。编译成功后会在工程目录的Objects文件夹下生成.axf、.hex或.bin文件这就是我们要烧录的固件。4. 固件烧录与硬件调试得到编译生成的二进制文件后下一步就是将其烧录到开发板的Flash中。4.1 使用Download Tool进行烧录打开FR8010H_Download_Tool.exe。选择正确的串口在工具中选择开发板连接的COM口可以在Windows设备管理器中查看。加载固件文件点击“浏览”或类似按钮选择Keil生成的.bin或.hex文件。配置烧录参数通常需要设置波特率如921600、起始地址Flash起始地址一般为0x00000000。这些参数一般保持默认即可但最好与SDK例程或芯片手册核对。进入烧录模式这是关键一步。确保开发板的BOOT跳线已设置为UART下载模式。然后按住开发板上的RESET按钮不放再点击烧录工具上的“开始”或“下载”按钮随后立即松开RESET按钮。此时工具应能检测到设备并开始擦除、编程、校验。恢复启动模式烧录成功后务必记得将BOOT跳线改回Flash启动模式然后重新上电或复位程序才会从Flash开始运行。4.2 串口日志确认将开发板通过USB连接电脑打开串口调试助手配置正确的COM口和波特率如115200。复位开发板你应该能看到芯片启动的日志以及我们代码中添加的打印信息例如”BLE Simple Peripheral started”以及初始化SHT30成功或失败的信息。这能第一时间确认程序是否已成功运行起来。5. 手机端蓝牙调试器配置实战开发板端准备就绪后我们开始在手机上配置“蓝牙调试器”App建立与开发板的通信。5.1 连接设备与UUID配置打开手机蓝牙和“蓝牙调试器”App。在设备扫描列表中找到名为“Simple Per”这是SDK例程默认的设备名的设备点击连接。连接成功后进入该设备的详情或服务发现页面。在这里你需要找到开发板提供的那个用于读写数据的“特征值”Characteristic。这需要你知道它的UUID。在富芮坤的ble_simple_peripheral例程中这个可写的特征值UUID通常是预设好的例如0xFFF1。你需要在代码中simple_gatt_service.c确认这个值或者在串口日志中查看服务发现的信息。在App的“专业调试”模式或相关设置中将这个UUID配置为通信的目标特征值。5.2 创建专业调试工程“蓝牙调试器”的“专业调试”模式是其精髓所在它允许你定义一套完整的双向通信协议。新建工程在“专业调试”界面创建一个新工程命名为“FR801xH温湿度监测”。通信设置 - 发送数据包添加一个发送数据包。因为我们只发送一个指令所以数据包很简单。添加一个字段类型选择byte字节长度1。将这个字段的值设置为0x47十六进制或71十进制。这个包就代表“请求数据”指令。通信设置 - 接收数据包添加一个接收数据包。根据我们的代码开发板会通过通知发送两个浮点数。添加第一个字段类型选择float长度4字节我们可以将其命名为“温度”。添加第二个字段类型同样选择float长度4字节命名为“湿度”。这里有个关键点你需要设置接收数据包的“解析起始位置”和“长度”。因为ValuePack打包的数据前面有几个字节的包头长度、校验等。你需要根据value_pack.h中定义的包结构确定两个浮点数数据在包中的具体偏移量。例如假设包头占2字节那么第一个float可能从第3字节开始。这需要你仔细阅读ValuePack的源码或文档来确定格式。编辑控件回到主界面进入“编辑控件”模式。添加两个“文本标签”控件分别用来显示温度和湿度。在控件的属性中将其“数据绑定”到刚才创建的接收数据包中的“温度”和“湿度”字段。添加一个“按钮”控件将其“点击动作”绑定到“发送数据包”并选择我们创建的那个包含0x47的发送包。可以将按钮文本改为“请求数据”。5.3 联调测试与数据验证配置完成后保存工程。确保开发板已上电运行串口日志显示蓝牙已广播。在手机上进入“专业调试”模式打开刚才创建的“FR801xH温湿度监测”工程。点击“请求数据”按钮。此时App会通过蓝牙向开发板发送0x47这个字节。观察现象手机端如果一切正常两个文本标签应该会显示出接收并解析后的温度和湿度数值例如“25.6”和“45.2”。开发板串口日志你应该能看到类似”Ack>问题现象可能原因排查步骤Keil编译报错error: #5: cannot open source input file “xxx.h”头文件路径未包含或错误。1. 检查Options for Target - C/C - Include Paths。2. 检查头文件是否在工程目录中。编译通过但链接报错Section .text size overflow代码量或数据量超出芯片Flash或RAM容量。1. 检查Target中IROM/IRAM设置是否与芯片一致。2. 提高编译优化等级如-O2。3. 检查是否有大型数组或库被误包含。下载工具无法连接设备1. 串口驱动未安装。2. BOOT模式未切换。3. 串口被其他软件占用。1. 检查设备管理器是否有未识别设备。2.确认BOOT跳线在烧录时处于UART模式。3. 关闭所有可能占用串口的软件。4. 尝试降低烧录波特率。烧录成功但程序不运行1. BOOT模式未切回Flash。2. 程序跑飞或硬件初始化失败。1.烧录后务必把BOOT跳线改回Flash启动模式。2. 通过串口查看是否有启动日志如果没有检查系统时钟、电源初始化代码。6.2 蓝牙连接与通信类问题问题现象可能原因排查步骤手机搜索不到“Simple Per”设备1. 开发板程序未运行。2. 蓝牙未开始广播。3. 手机蓝牙问题或距离过远。1. 检查串口是否有启动日志。2. 确认代码中蓝牙广播已启动调用ble_stack_start等函数。3. 重启手机蓝牙靠近开发板。手机能搜索到但连接失败1. 设备已连接其他主机。2. 配对/绑定问题如果使能了安全功能。1. 尝试重启开发板复位蓝牙状态。2. 在手机蓝牙设置中忘记该设备后重试。3. 检查代码中是否配置了不必要的配对要求。连接成功但无法收发数据1. UUID配置错误。2. 特征值属性未配置正确通知未使能。1.仔细核对手机App中配置的UUID与代码中定义的UUID是否完全一致包括大小写、连字符。2. 在代码中确保用于通知的特征值其Properties包含了NOTIFY标志并且在连接后调用了gatt_server_send_notification或类似函数使能客户端的通知。点击“请求数据”手机无反应1. 发送的指令格式不对。2. 开发板未正确处理写请求。1. 用App的“数据收发”普通模式手动发送0x47十六进制看串口是否有反应。2. 在sp_gatt_write_cb函数开始处加打印确认函数是否被调用以及收到的数据是什么。手机收到数据但显示乱码或错误1. 数据解析格式不匹配。2. 字节序大小端问题。1.这是最高频问题。确认手机端解析的float格式与开发板发送的float格式通常是IEEE 754标准一致。2. 确认ValuePack打包和手机端解析的字节顺序大端/小端一致。ARM Cortex-M通常是小端模式。3. 在手机端以“十六进制”格式查看原始接收数据与开发板co_printf打印出的发送缓冲区的十六进制内容进行逐字节比对。6.3 传感器与功耗优化建议SHT30读取失败检查I2C总线初始化代码、SHT30的设备地址通常是0x44或0x45、以及时序。使用逻辑分析仪或示波器抓取I2C波形是最直接的调试方法。也可以先编写一个简单的I2C扫描程序确认是否能发现传感器。数据更新慢目前的实现是“一问一答”手机请求一次开发板发送一次。如果想实现自动定时上报可以在开发板端创建一个定时器每隔一段时间如5秒主动读取传感器并通过通知发送数据无需手机请求。但要注意蓝牙连接间隔和功耗的平衡。降低功耗FR801xH支持低功耗模式。在不需要频繁上报的场景可以让MCU在两次操作间进入睡眠模式如pmu_enter_sleep_mode。同时合理配置蓝牙的连接间隔、从机延迟等参数可以显著降低平均电流。使用示波器测量开发板供电电流是评估功耗优化的有效手段。整个项目从环境搭建到联调成功最耗费时间的往往不是写代码而是调试和排查。尤其是蓝牙通信和手机端数据解析部分需要耐心地对比数据、确认协议。当你第一次在手机屏幕上看到从几米外的开发板传回来的实时温湿度数据时那种成就感就是对所有折腾的最好回报。这个项目虽然小但它完整地走通了“传感器采集 - MCU处理 - 蓝牙无线传输 - 手机App显示”的物联网经典链路理解了各个环节的要点以后再去做更复杂的应用心里就有底了。