这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【e起DIY】【成果帖】低功耗蓝牙温湿度计:一颗MOS实现外设节能99.9%

共1条 1/1 1 跳转至

【e起DIY】【成果帖】低功耗蓝牙温湿度计:一颗MOS实现外设节能99.9%

菜鸟
2026-06-11 18:53:45     打赏

一、项目背景

        翻开任何一本物联网教材,温湿度传感器几乎都是入门章节的第一个例子。这并不是因为它简单,而是因为它足够基础——无论是粮仓、机房、温室大棚,还是病房、冷链货车、博物馆的文物储藏间,温湿度的精确感知都是一切智能决策的前提。

        然而,"能测"和"好用"之间存在一道鸿沟。传统有线部署方案在固定场所尚可接受,一旦面对大空间多点布置、移动设备监测或临时性部署需求,动辄上百米的布线工程便会让方案变得既昂贵又脆弱。蓝牙低功耗(BLE)技术的成熟给出了另一条路:设备直接用纽扣电池供电,通过手机或小程序随时读取数据,整个部署过程不需要任何网络基础设施。

        但"低功耗"三个字说起来轻巧,真正落地时却藏着很多细节。以本项目使用的SHT30模拟输出传感器为例,即便处于空闲状态,只要持续供电就会维持约0.6mA的静态电流。在一块200mAh的纽扣电池上,这一数字意味着不到两周的续航。如何把传感器的通电时间精确压缩到"刚好够采一次样"的16毫秒窗口,让其余时间彻底断电,正是本项目着重解决的工程问题。

        本项目选用NXP MCXW71作为核心芯片。这颗芯片内置独立的无线子系统,将BLE协议栈的运行与应用主核完全隔离,既保证了蓝牙通信的实时性,又让应用层可以毫无顾虑地进入深度睡眠。配合Zephyr RTOS成熟的电源管理框架,整个系统的低功耗潜力得以充分释放。


二、项目目标与要求

        本项目的最终交付物是一套可以实际使用的无线温湿度节点:上电即广播,手机小程序连接即可看到实时数据,放在那里不管它,电池也能撑得住。为达到这个目标,整个开发过程围绕以下几个核心问题展开:

传感器信号怎么读?
        SHT30采用模拟比率式输出,温度和湿度分别对应两路0~VDD范围内的电压信号,需要通过ADC双通道同步采集,再套用数据手册给出的比率式公式换算。本项目使用FRDM-MCXW71板载的LPADC(12位,VREFH = 3.3V),通道映射关系需结合原理图与芯片参考手册三方核对,不能仅凭引脚名称推断。

传感器电源怎么控?
        直接给传感器持续供电是最省事的方案,但也是最费电的。本项目引入一个高电平导通的MOS管开关模块,由GPIOC.4控制其通断,将传感器的供电窗口精确限制在"上电稳定(16ms)+ ADC采样(~1ms)"这17ms以内,其余时间传感器引脚与电源完全断开。

MCU睡眠怎么配?
        Zephyr的k_sleep()在启用CONFIG_PM=yCONFIG_TICKLESS_KERNEL=y之后,会由PM子系统自动选择当前可用的最深睡眠态,并依赖片上RTC定时唤醒,对应用层完全透明。开发者无需手动操作任何寄存器,只需确保配置正确、外设约束不阻止深度睡眠即可。

数据怎么传到手机?
本项目定义了两个独立的128-bit UUID自定义GATT服务(温度服务与湿度服务),各含一个支持Notify的float类型特征。微信小程序通过订阅Notify通知被动接收数据,开发板每完成一次采样即推送一次,无需小程序轮询,进一步减少BLE通信对系统功耗的影响。

围绕上述四个核心问题,本项目的具体任务分解如下:

  • 搭建Zephyr开发环境,验证工程可正常编译并烧录至FRDM-MCXW71

  • 完成SHT30传感器与开发板的硬件连接,编写ADC驱动并验证串口输出数据正确

  • 编写MOS管供电控制逻辑,实现"采样窗口内供电、采样完成立即断电"的精确时序

  • 配置BLE外设角色与自定义GATT服务,验证微信小程序可正常接收温湿度Notify通知

  • 启用Zephyr电源管理与Tickless内核,测量低功耗模式下的实际功耗并与连续供电方案对比


三、项目硬件

模块主要硬件选型如下:

  • NXP FRDM-MCXW71开发板

  • SHT30模拟输出温湿度传感器模块

  • MOS管开关模块(高电平导通型)

  • Nordic PPK2(低功耗分析)

        在主要硬件选择完毕后,查阅开发板原理图与官方设备树头文件,确定引脚连接方案如下:SHT30模块VCC通过MOS管开关模块受控接入3.3V,GND直连开发板GND;温度输出引脚T接至ADC0通道(CH1B),湿度输出引脚H接至ADC0通道(CH2A);MOS管开关模块控制引脚接至ARDUINO_HEADER_R3_D2(对应gpioc 4),高电平时MOS管导通、传感器上电,低电平时传感器完全断电。具体硬件连线图如下图所示。

727766007.jpg


四、项目软件

        完整项目软件包括两个工程,一是低功耗蓝牙温湿度计Zephyr工程(ble_thermo),二是上位机微信小程序。下面将对两个工程进行详细描述。

A:ble_thermo工程

NXP FRDM-MCXW71开发板支持VS Code、IAR、Keil等多工具开发。但是本次我们要围绕Zephyr操作系统展开,所以选择一个Zephyr开发的通用工具VS Code + Zephyr IDE插件。

在编写模块软件代码之前,需要了解利用Zephyr搭建工程所需的文件架构,如图所示:

vscode.jpg

完成项目工程所需编写的代码文件共有七个:

1. main.c —— 应用程序主逻辑

main.c是核心逻辑实现文件,负责:

(1)初始化硬件和协议栈:

  • 调用sht30_init()初始化ADC通道与电源控制GPIO(传感器初始断电)

  • 调用bt_enable()初始化蓝牙协议栈,注册连接/断开回调

  • 调用ble_th_init()静态注册GATT温度服务与湿度服务

(2)实现业务功能:

  • 每30秒调用一次sht30_read(),内部自动完成"上电→等待16ms→ADC采样→立即断电"的完整时序

  • int16_t类型的temp_x100/hum_x100转换为float后,通过printk输出至串口

  • 调用ble_th_notify_temp()ble_th_notify_hum()向已订阅的BLE客户端推送数据

(3)低功耗与电源管理:

  • 主循环中调用k_sleep(K_SECONDS(30)),配合CONFIG_PM=yCONFIG_TICKLESS_KERNEL=y,使系统在空闲时自动进入最深可用睡眠态,由片上RTC定时唤醒,全程对应用层透明

(4)连接状态管理:

  • 使用原子位STATE_CONNECTED/STATE_DISCONNECTED在回调与主循环间安全传递连接事件,断连后自动重新开始广播

由于main.c代码较长,本文不再详述,完整代码见文末附件。

2. prj.conf —— 项目Kconfig配置文件

prj.conf用于配置Zephyr内核及各子系统的编译选项。代码如下:

# 蓝牙核心
CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DIS=y
CONFIG_BT_DIS_PNP=n
CONFIG_BT_BAS=y
CONFIG_BT_DEVICE_NAME="Zephyr TH Sensor"
CONFIG_BT_DEVICE_APPEARANCE=512

# ADC / GPIO
CONFIG_ADC=y
CONFIG_GPIO=y

# 电源管理(低功耗核心配置)
CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_DEVICE_RUNTIME=y

# Tickless内核(消除周期性tick中断,最大化睡眠时间)
CONFIG_TICKLESS_KERNEL=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000

# 日志与串口
CONFIG_LOG=y
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_CBPRINTF_FP_SUPPORT=y

各内容具体作用如下:

  • 启用蓝牙功能:CONFIG_BT=yCONFIG_BT_PERIPHERAL=y使能蓝牙协议栈并使设备作为外设角色;CONFIG_BT_DEVICE_NAME设置广播名称;CONFIG_BT_DEVICE_APPEARANCE=512设置设备外观类别为Generic Sensor。

  • 启用必要外设驱动:CONFIG_ADC=yCONFIG_GPIO=y使能ADC驱动与GPIO框架,支持模拟电压采集和MOS管控制。

  • 配置电源管理:CONFIG_PM=y启用Zephyr PM子系统;CONFIG_TICKLESS_KERNEL=y关闭周期性tick中断,使k_sleep()能够触发真正的硬件深度睡眠;CONFIG_PM_DEVICE=y允许ADC等外设参与电源状态切换。

3. boards/frdm_mcxw71.overlay —— 设备树覆盖文件

        设备树(Device Tree)描述了硬件的外设、引脚连接和资源。.overlay文件在不修改官方板级设备树的前提下,添加或覆盖节点以适应自定义硬件连接。代码如下:

#include <zephyr/dt-bindings/adc/adc.h>
#include <zephyr/dt-bindings/adc/mcux-lpadc.h>

/ {
    aliases {
        adc0 = &adc0;
    };

    /*
     * 传感器供电控制 GPIO
     *
     * ARDUINO_HEADER_R3_D2 → gpioc 4(来自官方 arduino-connector gpio-map)
     * GPIO_ACTIVE_HIGH:写 1 → MOS管导通 → 传感器上电
     *                   写 0 → MOS管截止 → 传感器完全断电
     */
    zephyr,user {
        sensor-pwr-gpios = <&gpioc 4 GPIO_ACTIVE_HIGH>;
    };
};

&lpi2c1 {
    status = "disabled";
};

&adc0 {
    #address-cells = <1>;
    #size-cells = <0>;
    voltage-ref = <0x0>;            /* Alt1 = VREFH = 3.3V */
    nxp,references = <&vref 3300>;  /* 参考电压 3300mV */

    channel@0 {                     /* 温度通道 */
        reg = <0>;
        zephyr,gain = "ADC_GAIN_1";
        zephyr,reference = "ADC_REF_EXTERNAL0";
        zephyr,vref-mv = <3300>;
        zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
        zephyr,resolution = <12>;
        zephyr,input-positive = <MCUX_LPADC_CH1B>;
    };

    channel@1 {                     /* 湿度通道 */
        reg = <1>;
        zephyr,gain = "ADC_GAIN_1";
        zephyr,reference = "ADC_REF_EXTERNAL0";
        zephyr,vref-mv = <3300>;
        zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
        zephyr,resolution = <12>;
        zephyr,input-positive = <MCUX_LPADC_CH2A>;
    };
};

上述代码关键要点:voltage-ref = <0x0>选择VREFH(3.3V)作为ADC参考电压,若不覆盖则默认使用1.8V导致换算结果严重偏高;nxp,references = <&vref 3300>明确告知NXP驱动参考电压值,确保adc_raw_to_millivolts()函数计算正确。MOS管控制GPIO(gpioc 4)直接在C代码中通过DT_NODELABEL(gpioc)获取设备,规避了文件作用域静态初始化时DEVICE_DT_GET的符号解析问题。

4. src/sht30.h / src/sht30.c —— 传感器驱动

sht30.h声明两个API函数:

int sht30_init(void);
/* 初始化ADC通道与电源控制GPIO(传感器初始断电),返回0成功 */

int sht30_read(int16_t *temp_x100, int16_t *hum_x100);
/* 完整采集流程:上电→等待16ms→ADC采样→立即断电→换算 */
/* temp_x100:温度,单位0.01°C(如2530 = 25.30°C)       */
/* hum_x100 :湿度,单位0.01%RH(如5120 = 51.20%RH)     */

sht30.c的核心实现要点:

  • 通道配置从设备树自动生成:使用ADC_CHANNEL_CFG_DT宏展开channel子节点,参考电压从zephyr,vref-mv属性读取,驱动代码与硬件通道号完全解耦

  • 比率式换算公式(SHT30数据手册):T(°C) = -66.875 + 218.75 × (V_T / V_DD)RH(%) = -12.5 + 125.0 × (V_RH / V_DD),以V_DD为基准的比率式计算确保VDD轻微波动时结果仍准确

  • 断电保证:gpio_pin_set(pwr_port, SENSOR_PWR_PIN, 0)位于adc_read()返回后立即执行,使用goto结构确保即使ADC失败也必然断电,不存在传感器持续供电的风险

5. src/ble_th.h / src/ble_th.c —— BLE GATT服务

ble_th.c静态注册两个独立的128-bit UUID自定义服务:

服务

服务UUID

特征UUID

属性

温度服务

ADAF0100-C332-42A8-93BD-25E905756CB8

ADAF0101-...

Notify + Read

湿度服务

ADAF0700-C332-42A8-93BD-25E905756CB8

ADAF0701-...

Notify + Read

        每个特征均附带CCCD(Client Characteristic Configuration Descriptor)。小程序调用notifyBLECharacteristicValueChange()时写入CCCD,触发temp_ccc_changed/hum_ccc_changed回调置位通知使能标志。ble_th_notify_temp()ble_th_notify_hum()内部通过memcpyfloat的原始字节写入发送缓冲区,ARM Cortex-M小端架构保证字节序与小程序getFloat32(0, true)期望的完全一致,无需额外字节序转换。

6. CMakeLists.txt —— 构建系统配置
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(ble_thermo)

target_sources(app PRIVATE
    src/main.c
    src/sht30.c
    src/ble_th.c
)
  • 引入Zephyr构建系统:find_package(Zephyr ...)加载Zephyr的CMake模块,自动处理编译器、链接器、设备树生成等全部流程

  • 指定源文件:三个.c文件分别负责主逻辑、传感器驱动、BLE服务,职责清晰,便于独立维护


B:上位机:微信小程序

本项目使用微信开发者工具编写微信小程序。完整工程包括如下代码文件:

wx.jpg

1. index.js —— 页面逻辑与蓝牙核心控制

index.js是页面的JavaScript逻辑文件,主要承担以下职责:

(1)蓝牙生命周期管理:

  • 初始化蓝牙适配器(wx.openBluetoothAdapter

  • 直接通过设备ID连接指定设备(wx.createBLEConnection

  • 获取服务和特征值(wx.getBLEDeviceServiceswx.getBLEDeviceCharacteristics

(2)数据接收与解析:

  • 通过wx.notifyBLECharacteristicValueChange()订阅温度和湿度特征的Notify通知,数据到达时自动触发回调,无需轮询

  • wx.onBLECharacteristicValueChange回调中,通过new DataView(res.value).getFloat32(0, true)将4字节小端float解析为温湿度数值

(3)UI数据绑定:

  • 通过this.setData()更新页面的temperaturehumidity、连接状态等

(4)资源释放:

  • 页面卸载时调用wx.closeBLEConnection()关闭连接,释放蓝牙资源

2. index.wxml —— 页面结构描述

index.wxml定义以下界面元素:

  • 连接按钮:未连接时显示"连接设备"按钮,连接后隐藏

  • 数据面板:连接成功后展示,包含温度卡片(含温度计图标、数值{{temperature}} ℃)和湿度卡片(含水滴图标、数值{{humidity}} %

3. index.wxss —— 页面样式表

index.wxss负责控制页面外观,包括flex布局、数据卡片渐变背景色、温湿度数值大字号显示以及通过rpx单位实现的移动端适配。

4. app.json —— 全局应用配置

app.json主要配置了页面路径("pages/index/index"为启动页)、导航栏标题("环境监测")以及蓝牙权限声明(scope.bluetooth),后者是调用微信BLE API的必要前提。

微信小程序工程的完整代码见文末附件。


五、传感器外设低功耗优化分析

5.1 优化方案设计

        本项目低功耗策略的核心在于通过MOS管开关模块对传感器实施精确的间歇供电控制,结合Zephyr电源管理框架实现MCU深度睡眠,将传感器的通电时间压缩至最短必要窗口(约17ms),其余约29.98秒内传感器完全断电。

每30秒完整时序:

|<───16ms───>|<─1ms─>|<──────────── ~29983ms ──────────────>|
┌────────────┐┌──────┐                                       ┌─
│ 传感器上电  ││ ADC  │     MCU深度睡眠(PM自动选择最深态)  │
└────────────┘└──────┘                                       └─
     ↑                                                    RTC唤醒↑
  GPIO=HIGH                                               30s到期

        MCU侧,CONFIG_PM=yCONFIG_TICKLESS_KERNEL=y协同工作:主循环k_sleep(K_SECONDS(30))触发后,Zephyr PM子系统自动评估所有线程状态与外设约束,选择MCXW71支持的最深可用睡眠态,由片上LPTMR/RTC在30秒后触发唤醒中断,恢复执行上下文,全程对应用层完全透明。

5.2 功耗测量基准(30秒统一周期)

为公平对比,以30秒为一个完整统计周期,计算两种供电策略下传感器部分消耗的总电量(单位:mAs)。

727710170.jpg

5.3 方案A:连续供电模式(2Hz频率读取)

30秒内传感器执行60次读取,其余时间维持低功耗空闲态(但始终保持供电)。

normal.jpg

读取状态:

  • 每次读取时间:12ms = 0.012s;读取平均电流:1.05mA

  • 30秒内总读取消耗:

空闲供电状态:

  • 空闲总时间:;空闲电流:0.6mA

  • 总空闲消耗:

5.4 方案B:MOS管间歇供电低功耗模式(30秒读一次)

30秒内MOS管仅导通1次,其余时间传感器引脚完全与电源断开,漏电流降至nA级(理论取100nA = 0.0001mA)。

MOS.jpg

开关导通瞬态尖峰(PPK2实测):

  • 尖峰持续时间:76µs;尖峰平均电流:约20mA

  • 尖峰消耗:

上电读取工作状态:

  • 读取时间:16ms(含上电初始化等待,比连续供电模式多4ms);平均电流:0.9mA

  • 读取消耗:

彻底断电休眠状态:

  • 休眠时间:≈29.984s;漏电流:0.0001mA

  • 休眠消耗:

5.5 数据对比与结论

功耗产生项

方案B消耗电量

在方案B总功耗中的占比

开关瞬态尖峰(浪涌)

0.00152 mAs

8.03%

16ms传感器读取工作

0.01440 mAs

76.11%

断电休眠漏电

0.00300 mAs

15.86%

合计

0.01892 mAs

100%


核心结论:

  1. 尖峰电流影响微乎其微:76µs的导通浪涌电量仅占方案B总消耗的8%,完全不影响低功耗大局

  2. 省电效率高达99.9%:方案B将传感器30秒周期内的电量消耗从18.324mAs压缩至0.01892mAs,根本原因在于MOS管彻底斩断了连续供电模式下持续29.28秒、0.6mA的空闲电流,而低功耗模式下这部分功耗直接降至nA级

  3. 上电初始化开销可接受:虽然比率式模拟传感器需要16ms上电稳定时间(比数字传感器的即读即取多约4ms),但与节省的空闲供电电量相比完全可以忽略


六、成果演示

1. 打开串口监视器,设置波特率115200。

uart.jpg

可以看到串口每30秒打印一次温湿度数据,两次打印之间MCU进入深度睡眠,开发板功耗显著降低。

2. 打开手机微信,进入"温湿度监测"小程序,点击"连接设备"。

237370543.jpg

小程序成功连接后,温度与湿度数值实时刷新显示,每当开发板完成一次采样并发送Notify通知,界面数值即自动更新。

至此,整个低功耗蓝牙温湿度计模块演示完成。


七、小结

综合上述内容,本研究实现了以下功能:

1. 环境数据采集

  • 硬件连接:SHT30模拟输出温湿度传感器的T、H引脚分别连接至FRDM-MCXW71的ADC0双通道(CH1B、CH2A),参考电压通过设备树overlay覆盖为VREFH = 3.3V

  • 驱动实现:基于Zephyr ADC API,利用DT_FOREACH_CHILD_SEP宏从设备树自动生成通道配置,通过adc_raw_to_millivolts()完成原始值到电压的换算,再应用SHT30比率式公式(以V_DD为基准)输出温湿度数值

  • 串口输出:每隔30秒通过printk输出格式化数据,例如:Temperature: 23.5°C, Humidity: 45.2%RH

2. 低功耗优化

  • 传感器间歇供电:通过MOS管开关模块(控制引脚GPIOC.4)精确控制传感器供电窗口,仅在ADC采样前16ms上电,采样完成后立即断电,传感器静态功耗降至nA级,节电效率达99.9%

  • MCU深度睡眠:主循环使用k_sleep(K_SECONDS(30)),配合CONFIG_PM=yCONFIG_TICKLESS_KERNEL=y,系统自动进入最深可用睡眠态,由片上RTC定时唤醒,无需应用层额外干预

3. 蓝牙功能

  • 外设角色:配置为BLE外设,设备名称为"Zephyr TH Sensor",可被手机等中心设备扫描发现

  • 自定义GATT服务:定义温度服务(ADAF0100-...)与湿度服务(ADAF0700-...),各含一个支持Notify+Read的128-bit特征,蜂鸣器控制服务已移除,结构简洁

  • 数据格式:float类型温湿度值通过memcpy以小端序写入4字节发送缓冲区,与小程序getFloat32(0, true)完全匹配,无需额外字节序转换

4. 微信小程序功能

  • BLE连接管理:通过设备ID直连,获取服务与特征后自动订阅Notify通知,无需定时轮询

  • 实时数据展示:接收到4字节float数据后即时解析并刷新界面温湿度数值

  • 用户界面:包含连接状态指示、数据卡片展示,界面简洁且适配移动端






关键词: e起DIY     温湿度计     低功耗     BLE    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]