你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32WB5MM-DK | Zephyr】6 基于 STM32WB5MM-DK 的接近唤醒低功耗测距显示

[复制链接]
lugl 发布时间:2026-11-4 22:16

基于 STM32WB5MM-DK 的接近唤醒低功耗测距显示(Zephyr)

板载 VL53L0CX 激光测距传感器 + SSD1306 OLED:

有人靠近自动亮屏显示距离,无人 5 秒后熄屏进入低功耗。

全程只用 Zephyr 标准 API,代码不足 150 行。


1. 功能效果

  • 活跃态:OLED 实时显示温度和距离,串口同步打印;
  • 无人 5 秒:OLED 熄屏,停止温度采样,MCU 进入 STOP2 低功耗;
  • 低功耗态:每 500ms 唤醒一次快速测距(耗时约 33ms),其余时间 MCU 与传感器都处于低功耗;
  • 有人靠近(<500mm):立即亮屏恢复显示,响应延迟 <0.7 秒。

2. 硬件

STM32WB5MM-DK 板载 VL53L0CXV0DH/1(原理图 U6),与 VL53L0X 软件兼容:

信号 连接
I2C I2C3(PB13 SCL / PB11 SDA),地址 0x29
XSHUT 硬件上拉到 3.3V,上电即工作,无需控制
GPIO1 PD9(本方案不使用,纯定时轮询)

Zephyr 官方板级 dts 已声明传感器节点,但 xshut-gpios 指向 PC6 与硬件不符 (PC6 实际用于触摸),需在 overlay 删除。

3. 工作原理

        ┌─────────────────────────────────────┐
        │              活 跃 态                │
        │  200ms 轮询,OLED 显示温度+距离       │
        └──────────────┬──────────────────────┘
                       │ 连续 5 秒无 500mm 内目标
                       ▼
        ┌─────────────────────────────────────┐
        │            低 功 耗 态               │
        │  OLED 熄灭,MCU 停 STOP2            │
        │  每 500ms 被 LPTIM 唤醒测一次距      │
        └──────────────┬──────────────────────┘
                       │ 测量有效且 <500mm
                       ▼
                 回到活跃态

关键点:STOP2 下 SysTick 停摆,需要 LPTIM1 作低功耗 tick 源(WB5MM 模块 内置 32.768kHz LSE 晶振),否则第一次 k_sleep 就会睡死。

这是 Zephyr 在STM32WB 上开 CONFIG_PM 的必要配置。

4. 配置

4.1 prj.conf(增量)

# VL53L0X ToF 测距传感器(板载 U6,I2C3 @ 0x29)
CONFIG_VL53L0X=y
​
# 系统级电源管理:idle 时自动进 STOP0/1/2
CONFIG_PM=y

4.2 boards/stm32wb5mm_dk.overlay

#include <zephyr/dt-bindings/clock/stm32wb_clock.h>
​
/* 修正官方 dts 与硬件不符的属性(PC6 未接传感器 XSHUT) */
&i2c3 {
    vl53l0x@29 {
        /delete-property/ xshut-gpios;
    };
};
​
/* PM 必需:LPTIM1 作低功耗 tick 源,STOP2 下继续运行 */
&clk_lse {
    status = "okay";
};
​
stm32_lp_tick_source: &lptim1 {
    clocks = <&rcc STM32_CLOCK(APB1, 31)>,
         <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>;
    status = "okay";
};

5. 完整代码(src/main.c)

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/display.h>
#include <zephyr/display/cfb.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/sensor/vl53l0x.h>
​
#define NEAR_THRESHOLD_MM  500   /* 接近判定阈值 */
#define FAR_TIMEOUT_MS     5000  /* 无人多少毫秒后熄屏 */
#define SLEEP_POLL_MS      500   /* 低功耗态测距间隔 */
​
const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
const struct device *temp_dev = DEVICE_DT_GET(DT_NODELABEL(stts22h));
const struct device *tof_dev = DEVICE_DT_GET(DT_INST(0, st_vl53l0x));
​
int main(void)
{
    if (!device_is_ready(dev) || !device_is_ready(temp_dev) ||
        !device_is_ready(tof_dev)) {
        printk("device not ready\n");
        return -ENODEV;
    }
​
    display_set_pixel_format(dev, PIXEL_FORMAT_MONO01);
    display_blanking_off(dev);
    if (cfb_framebuffer_init(dev)) {
        return -EIO;
    }
    cfb_framebuffer_clear(dev, true);
​
    int64_t far_since = 0;
​
    while (1) {
        bool near = false;
        struct sensor_value temp_value, dist, status;
        char buf[32];
​
        /* --- 温度 --- */
        if (sensor_sample_fetch(temp_dev) == 0) {
            sensor_channel_get(temp_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp_value);
            snprintf(buf, sizeof(buf), "Temp: %d.%02d C",
                     temp_value.val1, temp_value.val2 / 10000);
        } else {
            snprintf(buf, sizeof(buf), "Temp: error");
        }
​
        /* clear 第二参数必须 false,只清内存帧缓冲不刷屏,
         * 否则每帧推两次全屏数据,OLED 会闪 */
        cfb_framebuffer_clear(dev, false);
        cfb_print(dev, "VL53L0CX demo", 0, 0);
        cfb_print(dev, buf, 0, 16);
​
        /* --- 单次测距 --- */
        if (sensor_sample_fetch(tof_dev) == 0) {
            sensor_channel_get(tof_dev, SENSOR_CHAN_DISTANCE, &dist);
            sensor_channel_get(tof_dev,
                               (enum sensor_channel)SENSOR_CHAN_VL53L0X_RANGE_STATUS,
                               &status);
​
            int32_t mm = dist.val1 * 1000 + dist.val2 / 1000;
​
            if (status.val1 == 0) {
                snprintf(buf, sizeof(buf), "Dist: %d mm", (int)mm);
                near = (mm < NEAR_THRESHOLD_MM);
            } else {
                snprintf(buf, sizeof(buf), "Dist: ---- mm");
            }
            printk("range status=%d, distance=%d mm\n",
                   (int)status.val1, (int)mm);
        } else {
            snprintf(buf, sizeof(buf), "Dist: error");
        }
​
        cfb_print(dev, buf, 0, 32);
        cfb_framebuffer_finalize(dev);
​
        if (near) {
            far_since = 0;
            k_sleep(K_MSEC(200));
            continue;
        }
​
        if (far_since == 0) {
            far_since = k_uptime_get();
        }
​
        if (k_uptime_get() - far_since >= FAR_TIMEOUT_MS) {
            /* ===== 无人超时:熄屏进低功耗轮询 ===== */
            display_blanking_on(dev);
​
            for (;;) {
                k_msleep(SLEEP_POLL_MS);   /* 期间 MCU 自动停 STOP2 */
​
                if (sensor_sample_fetch(tof_dev) != 0) {
                    continue;
                }
                sensor_channel_get(tof_dev, SENSOR_CHAN_DISTANCE, &dist);
                sensor_channel_get(tof_dev,
                    (enum sensor_channel)SENSOR_CHAN_VL53L0X_RANGE_STATUS,
                    &status);
​
                int32_t mm = dist.val1 * 1000 + dist.val2 / 1000;
​
                printk("sleep poll: status=%d mm=%d\n",
                       (int)status.val1, (int)mm);
                if (status.val1 == 0 && mm < NEAR_THRESHOLD_MM) {
                    break;   /* 有人靠近,退出休眠 */
                }
            }
​
            display_blanking_off(dev);
            far_since = 0;
        }
​
        k_sleep(K_MSEC(200));
    }
}

6. 验证

range status=0, distance=2031 mm     ← 活跃态,2m 墙稳定读出
...
(移开目标 5 秒,OLED 熄灭)
sleep poll: status=4 mm=8190         ← 低功耗轮询,无目标
sleep poll: status=0 mm=342          ← 手掌 30cm 靠近
(OLED 点亮,恢复实时显示)
  • 2m 白墙实测误差 ±20mm;
  • 唤醒响应 <0.7 秒(轮询间隔 500ms + 单次测量 ~33ms)。

7. 参数调优

参数 位置 说明
NEAR_THRESHOLD_MM 500 接近判定距离,按产品需求改
FAR_TIMEOUT_MS 5000 无人多久后熄屏
SLEEP_POLL_MS 500 休眠测距间隔:调大更省电、唤醒更慢;调小相反
温度采样 低功耗态自动停止 STTS22H 自身功耗 µA 级,无需断电

功耗说明:低功耗态下 MCU 每 500ms 只工作约 33ms(测距),其余时间停 STOP2; 传感器每次测完自动回 standby(µA 级)。相比"传感器连续测距 + GPIO1 中断唤醒" 方案(传感器常~19mA),整机功耗低一个数量级,且规避了 VL53L0X 在量程边缘 阈值中断误触发的问题。

8. 编译烧录

west build -b stm32wb5mm_dk -p always app/stm32wb5mm_dk_vl53l0cxv -d build
west flash -d build

调试提示:板子熄屏处于 STOP2 时,串口 RX 和 SWD 调试器都不可用,属正常现象, 靠近唤醒后即恢复。

赞 收藏 评论0 发布时间:2026-11-4 22:16

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版