ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

低功耗BLE温度监测器设计:U-blox NINA-B1与Zephyr开发实战

低功耗BLE温度监测器设计:U-blox NINA-B1与Zephyr开发实战 前阵子做了一个便携式温度监测仪的项目核心器件用了U-blox的BLE模块整机用纽扣电池供电目标是在冷链运输场景下连续工作几个月。做完之后有不少朋友在问选型和实现上的细节这里把整个项目的设计思路、硬件选型、固件实现和实测踩坑一次性整理出来给正在做类似低功耗BLE产品的同学一个参考。先说结论U-blox BLE模块我用的NINA-B1系列在功耗、尺寸和开发效率上的综合表现比较均衡配合Zephyr SDK做嵌入式开发不需要额外MCU就能把温度采集、BLE通信、低功耗调度整套跑通。整机休眠电流做到了2.8uA左右用一颗CR2477纽扣电池10秒上报一次温度的工况下理论续航可以到9个月以上。1. 项目整体设计与方案选型1.1 需求拆解温度监测器到底要什么做任何硬件项目之前最好先把需求落到具体的量化指标上。这个温度监测器最开始的需求描述很模糊就是监测温度、蓝牙上报但真正进入设计阶段需要明确的点非常多测温范围冷链场景通常要求-20℃到60℃但如果你要兼顾体温计等医疗场景可能还要覆盖更宽范围测温精度普通环境监测±0.5℃就够但如果是疫苗、血液制品运输需要±0.2℃甚至更高上报频率是每秒都传还是10秒、1分钟、10分钟采一次这直接决定功耗量级数据存储蓝牙连接断开期间要不要本地缓存缓存多少条电池寿命客户要求一次性电池至少撑几个月还是允许充电体积约束纽扣电池还是有电池仓PCB面积有没有限制我们这个项目定位是冷链运输箱内的温度记录贴片要求是测温范围-30℃到70℃精度±0.3℃在-10℃到50℃范围内默认10秒采集一次温度BLE广播/连接上报CR2477纽扣电池供电目标续航不低于6个月。这个需求下来之后方案其实就已经比较清晰了集成BLE SoC的模块 高精度数字温度传感器 纽扣电池 低功耗固件调度。关键是选对BLE方案。1.2 为什么选U-blox BLE模块而不是裸片方案BLE方案的选择其实有几条路线第一种是直接用Nordic nRF52832/nRF52840裸芯片自己做射频设计。这种方式BOM成本最低但射频匹配、天线设计、认证FCC/CE都要自己搞定对于小团队或者快速验证的项目来说射频短板是最容易卡壳的。第二种是用国产或者日系的BLE SoC比如Telink、Apollo等成本很低但生态和文档相对弱一些低功耗调参的经验也不太好找。第三种就是集成模块方案比如U-blox、Laird现在是Ezurio、Murata、Silicon Labs的模块。模块把晶振、射频匹配、天线、DC-DC全部封装好了你做PCB的时候只需要保证电源干净、天线区域净空就能获得稳定的射频性能。蓝牙模块本身也通过了模块级的认证可以省掉一大笔认证费用和时间。我们的项目最终选了U-blox NINA-B1系列主要考量是基于nRF52832 SoCBLE 5.0支持长距离编码模式而且nRF52系列的生态成熟低功耗特性经过大量验证模块尺寸小NINA-B111内置天线版本只有10x15x2.0mm焊盘为LGA封装适合小型化设计U-blox有完整的AT命令固件同时支持Embedded模式用SDK开发开发方式灵活工作电压范围1.7V-3.6V可以直接吃纽扣电池电压不需要额外升压后来我对比过NINA-B3基于nRF52840和NORA-B1nRF52833B3主要是多出USB和更多Flash/内存适合复杂应用NORA-B1支持BLE 5.1天线版本也全但价格高一些。我们这个项目只需要连接和广播nRF52832的性能完全够用NINA-B1性价比最高。1.3 模块选型细节NINA-B1系列各版本怎么挑NINA-B1系列内部有多个版本主要区别在于天线和Flash容量。型号天线类型Flash/RAM适用场景NINA-B111PCB内置天线512KB/64KB空间紧凑外壳非金属NINA-B112外置天线引脚512KB/64KB需要外接天线金属外壳NINA-B121PCB内置天线升级版512KB/64KB与B111类似但有所优化如果你的产品外壳是全塑胶或者非金属强烈建议选内置天线版本省掉一个天线物料和装配工序。如果外壳有金属结构或者设备装在金属机箱里老老实实选外置天线版本预留IPEX座或天线焊盘留出调天线匹配的余量。我们这里选的是NINA-B111因为温度贴片是塑料外壳、空间极紧凑内置天线最合适。注意内置天线版本对净空区和外壳材质有要求具体我放在硬件设计部分详细说。2. 硬件设计要点与传感器选型2.1 温度传感器NTC还是数字I2C温度监测器最核心的就是传感器选型。很多人第一反应是用NTC热敏电阻便宜、简单、任何MCU都能读但项目精度要求±0.3℃时NTC方案的校准成本会高到让你怀疑人生。NTC的温度-电阻曲线是非线性的需要查表或者用Steinhart-Hart方程计算而且每个传感器个体差异大批量生产时校准点不能少否则一致性很难保证。数字温度传感器是更省心的选择。我对比过几款传感器接口精度功耗备注TMP117I2C±0.1℃-20~50℃待机0.2uA转换135uA/15msTI医疗级传感器SHT30I2C±0.2℃待机0.2uA转换~1.2mA/1ms温湿度一体BME280I2C/SPI±0.5℃待机0.1uA温湿度气压一体MCP9808I2C±0.25℃待机0.1uA转换200uAMicrochip最终选了TMP117。理由很简单它在-20℃到50℃范围内能做到±0.1℃的精度直接满足±0.3℃的需求还留了余量单次转换时间15ms转换结束后自动回到待机模式待机电流极低I2C地址可通过引脚配置如果未来要做多路温度监测也方便。另外一个隐藏优势是TMP117内部有出厂校准不需要你批量校准这对生产端来说省掉了一大笔设备和人工成本。使用TMP117时有几个细节注意I2C上拉电阻一般选2.2k-4.7k供电可以直接接VDD如果传感器离模块远上拉电阻要选小一些但注意上拉电流不要过大TMP117的地址引脚ADDR有三种状态低、高、浮动可以配置出4个地址方便I2C总线上挂多颗。2.2 供电方案一颗纽扣电池怎么喂饱整个系统温度监测器这种便携设备供电设计是低功耗的根基。我们用的是CR2477纽扣电池额定容量约1000mAh但纽扣电池有一个特性容易被忽略它的内阻比较大在脉冲大电流比如BLE广播时电流峰值十几毫安情况下输出电压会明显跌落。如果跌落太多可能导致模块复位或者射频性能下降。所以供电设计上要做几件事电源路径必须是电池 → 去耦电容 → 模块VBAT去耦电容至少要100uF钽电容或者220uF电解电容并联0.1uF陶瓷电容。这个电容的作用相当于一个能量缓冲池BLE在广播瞬间需要抽取十几毫安电流时由电容来放电补充避免电池电压被瞬间拉垮模块VDD供电引脚如果模块有内部DCDC则VBAT直接输入如果是外部供电架构需要参考具体手册要就近放去耦电容传感器供电TMP117的VDD可以直接连电池正极因为它的待机电流极低。如果传感器工作电流较大可以加一个MOS管开关只在采样期间供电实测下来CR2477在初期内阻大约15-30Ω在BLE广播脉冲约15mA、持续几毫秒下压降大约0.2-0.4V只要去耦电容足量系统最低电压仍能保持在2.8V以上NINA-B1的1.7V最低工作电压余量是足够的。2.3 射频部分与天线布局最容易翻车的地方选了内置天线模块射频设计会简单很多但简单不等于随意。NINA-B111的数据手册里对内置天线的PCB布局有明确要求天线下方和周围的PCB必须净空不能铺铜天线附近不能走地线、信号线和电源线天线周围包裹的外壳也不能是金属材质否则天线会被严重失谐辐射效率掉一半都不奇怪。我们第一版PCB就吃过这个亏为了压缩板面积在天线附近走了一根VCC走线结果广播距离从设计的30米缩水到10米左右。后来重新改版天线区域完全净空周围1cm内不铺铜、不走线、不放置器件距离立刻恢复正常。如果产品外壳是金属的那就必须换外置天线方案或者设计天线延伸到外壳外部。常见做法是用外置FPC天线贴在塑料外壳内壁上通过同轴线或弹簧针连接到模块。这种情况下一定要做天线匹配调试至少要用网络分析仪看S11频率范围至少要覆盖2.4-2.5GHz。还有一个容易忽略的点电池。纽扣电池本身是金属如果电池正好贴在天线下方或者非常近也会影响天线性能。设计时尽量让电池远离天线区域或者在结构上保证两者之间有足够距离。3. 固件开发与BLE通信实现3.1 开发模式选择AT命令还是Zephyr SDKU-blox NINA-B1支持两种开发模式一种是AT命令模式模块预烧了U-blox的AT固件你只需要一个外部MCU通过UART发AT命令控制它另一种是Embedded模式用nRF Connect SDK基于Zephyr RTOS开发自己的固件直接烧写到模块内部不需要外部MCU。对于这个温度监测器项目我选了Embedded模式理由很现实AT命令模式的最大好处是开发快、不需要了解BLE协议细节但它需要额外一颗MCU来控制模块整机功耗和BOM成本都会上升而且外部MCU和模块之间还需要额外的通信开销。对于温度监测这种功能简单、但对功耗和体积要求高的设备集成方案是更优解。Embedded模式下U-blox提供了基于Zephyr的board definition和示例工程你可以在SDK里直接选NINA-B111作为target板子写应用代码。Zephyr自带的BLE协议栈SoftDevice Controller非常成熟低功耗管理、广播、连接、GATT服务这些都有现成API不需要自己啃协议栈源码。3.2 广播包与GATT服务设计BLE通信设计要从产品功能反推。我们的温度监测器有两种工作模式广播模式设备以一定间隔发出广播包手机App可以扫描发现读取里面的温度数据连接模式手机或网关主动连接设备通过GATT服务读取历史温度数据、配置参数广播包设计相对简单。传统广播包只放设备名称和厂商自定义数据。如果你想在广播包里直接携带温度数据可以用厂商自定义字段比如Company ID用0xFFFF用于测试或者申请自己的ID后面的数据自定义格式[0x02, 0x01, 0x06] // Flags表示LE General Discoverable Mode [0x03, 0x03, 0xF0, 0xFF] // Complete List of 16-bit Service UUIDs或者用128-bit UUID [0x05, 0xFF, 0xAA, 0xAA, 0xYY, 0xYY] // Manufacturer Specific Data放置温度数值注意广播数据最长只有31字节你要权衡设备名长度、服务UUID数量和数据负载。如果把温度数据放在广播包里手机扫描时不连接也能秒读温度用户体验很好。GATT服务设计方面我们定义了一个自定义温度服务特征UUID属性长度说明Temperature Measurement自定义128-bit UUID读 / Notify4字节温度值IEEE 11073格式或int16单位0.01℃Battery Level0x180F标准服务读 / Notify1字节电池电量百分比Device Info0x180A标准服务读可变设备序列号、固件版本Sample Interval自定义128-bit UUID读 / 写1字节采样间隔配置比如10秒~10分钟温度值的数据格式我用了int16单位0.01℃这样-30.00℃到70.00℃都能表示。Notify属性让设备可以主动推送温度变化给手机手机不需要一直轮询。3.3 传感器采集与低功耗调度关键代码逻辑在Zephyr里开发NINA-B1的固件核心逻辑是这样一个无限循环进入System OFF或者深度睡眠模式比如nRF52的System ON idle 定时器唤醒定时器唤醒后读取TMP117温度更新GATT特征值如果当前有BLE连接直接Notify出去更新广播包中的温度数据重新进入睡眠代码核心片段大概是这样#include zephyr/kernel.h #include zephyr/device.h #include zephyr/drivers/sensor.h #include zephyr/bluetooth/bluetooth.h #include zephyr/bluetooth/gatt.h static const struct device *tmp117_dev; static int16_t temp_value; static bool connected; /* 温度特征值更新回调 */ static ssize_t read_temp(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attr, buf, len, offset, temp_value, sizeof(temp_value)); } /* Notify温度特征 */ static void notify_temp(void) { struct bt_gatt_attr *attr my_service_attrs[1]; bt_gatt_notify(NULL, attr, temp_value, sizeof(temp_value)); } void main(void) { int err; /* 初始化BLE协议栈 */ err bt_enable(NULL); if (err) { printk(Bluetooth init failed (err %d)\n, err); return; } tmp117_dev DEVICE_DT_GET(DT_NODELABEL(tmp117)); if (!device_is_ready(tmp117_dev)) { printk(TMP117 not ready\n); return; } /* 启动广播 */ bt_le_adv_start(...); while (1) { /* 读取温度 */ struct sensor_value temp; sensor_sample_fetch(tmp117_dev); sensor_channel_get(tmp117_dev, SENSOR_CHAN_AMBIENT_TEMP, temp); temp_value (int16_t)(temp.val1 * 100 temp.val2 / 10000); /* 更新广播包数据 */ update_adv_data(temp_value); /* 有连接则主动Notify */ if (connected) { notify_temp(); } /* 进入睡眠等待下一个采样周期 */ k_sleep(K_SECONDS(sample_interval)); } }这段代码简化掉了错误处理和广播参数配置但核心逻辑已经清楚了。重点在于采样周期内的绝大部分时间设备处于睡眠状态电耗几乎为零。k_sleep时如果系统配置了PM电源管理Zephyr会自动进入System ON idle模式电流只有微安级别。3.4 连接参数与功耗的取舍别让手机把功耗拖垮BLE设备的功耗大头不是在广播上而是在连接状态下。连接的功耗由连接间隔、从机延迟slave latency和超时时间共同决定。连接间隔是主设备手机和从设备模块之间通信的频率。间隔越短实时性越好但从设备需要频繁唤醒收包功耗越高。从机延迟允许从设备跳过若干个连接事件而不需要收包这可以让设备在数据不变化时一直睡到下一个必须回复的事件。我们项目的连接参数设置参数值说明Connection Interval Min30ms实际值由主设备决定Connection Interval Max50ms上限值Slave Latency4可以跳过4个连接事件Supervision Timeout4000ms超过该时间没通信则连接断开这样的配置下设备在连接状态中大部分时间是睡眠的只有每5个连接事件唤醒一次功耗接近广播状态。注意连接参数的最终决定权在主设备手机从设备只能通过更新连接参数请求来协商。Android和iOS的处理方式不太一样Android默认会接受从设备的请求iOS有时候会更保守需要从设备在特定时机请求更新连接参数。如果你做的是纯广播模式产品不需要连接那就简单很多只要把广播间隔调大功耗就直线下降。间隔100ms时平均电流约20uA间隔1s时平均电流约5uA左右具体取决于广播负载。4. 实测数据、功耗调优与问题排查4.1 功耗实测记录与电池寿命计算理论计算永远替代不了实测。我们用电流分析仪Keysight N6705B或者开源方案用INA226电流传感器树莓派测了整机在各种状态下的电流。实测平均电流数据状态电流持续时间深度睡眠无广播2.8uA常态广播间隔1s负载24字节28uA广播期间温度采集TMP117转换200uA15msBLE连接Notify间隔50mslatency435uA连接期间基于以上数据算一个典型场景10秒采集一次并广播一次温度不建立连接。平均电流大概是平均电流 广播平均电流10秒内有约3次广播每次约3-5ms电流约15mA 采集平均电流每次15ms x 200uA占比很小 睡眠电流占绝大部分时间 估算公式 广播每次消耗 15mA x 4ms / 1000 ≈ 60uC微库仑 10秒内3次广播 180uC 采集每次消耗 200uA x 15ms ≈ 3uC 10秒内1次采集 3uC 睡眠消耗10秒 2.8uA x 10s 28uC 总消耗10秒 180 3 28 ≈ 211uC 平均电流 211uC / 10s ≈ 21.1uACR2477容量约1000mAh按90%可用容量理论续航1000mAh x 0.9 900mAh 900000uAh 900000uAh / 21.1uA ≈ 42654小时 ≈ 1776天 ≈ 4.9年这个计算比客户要求的6个月目标高出很多说明设计余量充足。但要注意实际续航还会受温度、电池自放电CR2477年自放电约1%-2%、天线辐射效率等因素影响。如果你把上报频率提高到1秒一次平均电流会跑到100uA以上续航就降到一年以内了。所以在产品设计中上报频率和电池寿命的权衡很重要要根据实际业务需求来定不是越快越好。4.2 蓝牙扫描不到或者连接不稳先查这四个地方项目调试中遇到不少怪问题这里分享最有价值的几个排查方向第一先确认模块有没有跑起来。看广播有没有发出来最简单是用手机装一个nRF Connect扫描看看能不能看到设备。如果连nRF Connect都扫不到基本是固件启动失败或者射频硬件问题。这时候看串口日志NINA-B1板子会打印Zephyr的console是最好的方式代码里加打印确认bt_enable和广播启动成功。第二供电电压跌落。前面说过BLE广播瞬间电流很大如果电池老化或者去耦电容不够广播瞬间电压跌落会导致射频功放输出电压异常直接表现是广播距离极短或者时有时无。用示波器抓VBAT波形如果发现广播瞬间电压跌落超过0.3V就得加大电容容量。另外注意万用表量到的静态电压正常不代表动态电压正常必须用示波器看动态波形。第三天线净空区违规。如果你的PCB上元件布局很挤很容易无意中在天线附近走线、铺铜。哪怕只有一条细走线穿过净空区也会影响天线效率。我们踩过的坑就是VCC走线。重新布局后信号强度从-80dBm提升到-65dBm测试距离1米实测值效果非常明显。第四供电电源噪声。如果用USB供电或者开关电源供电电源纹波会耦合到射频电路造成信号质量下降。排查方法是换成电池供电对比测试。项目里遇到手机扫描偶尔超时的问题最后发现是实验室USB供电的纹波太大导致的换成电池后问题消失。4.3 常见问题速查表问题现象可能原因排查方法解决建议完全扫描不到设备模块未启动、供电异常看串口日志、查VBAT电压确认固件正常运行检查电源连接广播有但距离极短天线失谐、净空违规检查PCB天线区域、测S11确保净空区合规重新布局连接后频繁断开连接超时参数太短、供电不稳定查看断连原因码调大Supervision Timeout增强去耦温度读数异常跳变I2C干扰、传感器供电不稳示波器抓I2C波形加强滤波检查上拉电阻功耗远高于理论值未进入睡眠、外设漏电逐个外设断开测试检查GPIO配置禁用未用外设新固件烧录后无反应烧录配置错误、SDK版本不匹配检查烧录log核对U-blox官方SDK文档需要注意的是BLE相关的玄学问题多数都能归结为电源和天线两个物理层面的问题。先排除物理层再看协议层否则很容易在代码里白找半天。5. 写在最后的一点体会这个项目做下来我最大的一个感受是低功耗BLE产品真正的核心技术不是BLE协议本身而是系统级的能量预算管理。你能不能让设备在99%的时间里都睡得很深能不能把每次唤醒的动作压缩到最短这些决定了产品的续航上限。U-blox NINA-B1 Zephyr这套组合让我在项目开发中少踩了很多射频的坑。模块化方案虽然BOM成本比裸芯片方案高几十块钱但节约的时间和认证成本是实打实的。如果你也是小团队、项目周期紧、对射频经验不是特别自信用模块方案绝对比头铁去啃裸芯片要划算。最后分享一个小技巧做功耗测试时不要只看平均电流要把每个状态的电流-时间波形记录下来分析是哪一段占了主要能耗。有时候你会发现一个不起眼的GPIO上拉电阻可能比整个BLE协议栈还耗电。把波形拉出来问题一目了然。
返回列表