零知派ESP32——BLE Mesh蓝牙组网智能灯控系统(PIR感应+W2812三档调色)

✔零知派(零知开源)是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台,在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录,让开发重心从 "配置环境" 转移到 "创意实现",极大降低了技术门槛。零知开源编程软件,内置上千个覆盖多场景的示例代码,支持项目源码一键下载,项目文章在线浏览。零知派(零知开源)平台通过软硬件协同创新,让你的创意快速转化为实物,来动手试试吧!

✔访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

目录

一、系统接线部分

[1.1 硬件清单](#1.1 硬件清单)

[1.2 接线方案表](#1.2 接线方案表)

[1.3 具体接线图](#1.3 具体接线图)

[1.4 接线实物图](#1.4 接线实物图)

二、核心代码讲解

[2.1 WS2812 驱动实现](#2.1 WS2812 驱动实现)

[2.2 BLE Mesh 控制逻辑](#2.2 BLE Mesh 控制逻辑)

[2.3 PIR 人体感应](#2.3 PIR 人体感应)

[2.4 硬件总开关](#2.4 硬件总开关)

三、项目结果演示

[3.1 操作流程](#3.1 操作流程)

[3.2 视频演示](#3.2 视频演示)

四、常见问题解答(FAQ)

[Q1:WS2812 初始化后显示乱码白光?](#Q1:WS2812 初始化后显示乱码白光?)

[Q2:PIR 触发后颜色恢复不对?](#Q2:PIR 触发后颜色恢复不对?)

Q3:按键抖动导致误触发?


项目概述

本项目基于零知ESP32BLE Mesh 技术,实现了一款智能灯节点。手机通过nRF Mesh App可远程控制灯的开关亮度 ,同时本地PIR人体感应器 能自动开灯并延时关灯。与上个版本不同的是,PIR人体感应器的优先级较高,当识别到有人时,会强制显示白光,并屏蔽手机所有指令。

项目难点及解决方案

问题描述:PIR、BLE、硬件按键三个控制源并发触发时,灯光颜色与开关状态互相覆盖,导致恢复结果错误

解决方案: 为每一层控制源建立独立的状态保存变量(s_saved_xxx / s_sw_saved_xxx),严格按优先级在回调入口处拦截低优先级指令,各层状态互不共用

一、系统接线部分

1.1 硬件清单

元器件 型号 数量 说明
主控板 零知ESP32(ESP32-WROOM-32) 3 240MHz双核,内置BLE 5.0
OLED显示屏 SSD1306 0.96寸 128×64 3 I2C接口,3.3V供电
RGB彩灯模块 WS2812灯珠+去耦电容模块 3 内置去耦电容
数据线 USB Type-A to Micro-USB 1 烧录用
杜邦线 公对母/母对母 若干 连接用
手机 iOS/Android 1 安装nRF Mesh App
人体感应模块 HC-SR505 人体感应模块 3 检测人体或动物的移动热源
扩展板 零知派 ESP32 通用扩展板 1 提供OLED接口和按键,节省接线时间

1.2 接线方案表

以下引脚定义严格依据 project_config.h 中的宏定义,三台设备接线完全相同。

模块 模块引脚 ESP32引脚 说明
OLED SSD1306 VCC 3.3V 注意:只能接3.3V
OLED SSD1306 GND GND 接地
OLED SSD1306 SDA GPIO 21 I2C数据,对应OLED_SDA_GPIO
OLED SSD1306 SCL GPIO 22 I2C时钟,对应OLED_SCL_GPIO
WS2812彩灯模块 DIN GPIO 5 PWM控制,对应LED_GPIO
WS2812彩灯模块 VCC 3.3V LED模块用3.3V供电
WS2812彩灯模块 GND GND 接地
人体感应模块 VCC 5V 默认工作电压4.5~20V
人体感应模块 OUT GPIO 18 输出引脚,对应PIR_GPIO
人体感应模块 GND GND 接地
总开关按键 SW GPIO 12 输入引脚,常开

1.3 具体接线图

OLED VCC务必接3.3V引脚,ESP32的5V引脚会损坏OLED、GPIO 21和GPIO 22之间无需外接上拉电阻;人体感应模块的正极+不能接3.3V,低于工作电压,模块输出引脚数据不正常;图中按键型号,弯钩相对的两个引脚默认是相连的,如果不确定,可以用万用表测试后再接线

1.4 接线实物图

​​

二、核心代码讲解

本项目代码基于上篇文章新增了WS2812 彩灯的功能,核心代码仅针对新添加部分做讲解,更多可以回顾上篇文章

2.1 WS2812 驱动实现

原项目使用 LEDC PWM 驱动单色 LED,改为 WS2812 后需换用 RMT 外设,利用精确时序发送 24bit 颜色数据(顺序为 G → R → B)

RMT 时序参数

信号 时间 Tick 数 (80MHz)
T0H(bit0 高电平) 400 ns 32
T0L(bit0 低电平) 850 ns 68
T1H(bit1 高电平) 800 ns 64
T1L(bit1 低电平) 450 ns 36
RES(复位低电平) ≥50 μs 4800

时钟务必设置为 80MHz(resolution_hz = 80 * 1000 * 1000),否则时序错误,WS2812 显示乱码白光。

核心驱动代码

cpp 复制代码
/* WS2812 时序 Tick 数(80MHz,1 tick = 12.5ns) */
#define WS2812_T0H_TICKS  32
#define WS2812_T0L_TICKS  68
#define WS2812_T1H_TICKS  64
#define WS2812_T1L_TICKS  36
#define WS2812_RES_TICKS  4800

/* 写入颜色到灯珠(WS2812 顺序:G R B) */
static void ws2812_write(uint8_t brightness)
{
    uint8_t g = (uint16_t)s_g * brightness / 255;
    uint8_t r = (uint16_t)s_r * brightness / 255;
    uint8_t b = (uint16_t)s_b * brightness / 255;
    uint8_t payload[3] = {g, r, b};

    rmt_transmit_config_t tx_cfg = { .loop_count = 0 };
    rmt_transmit(s_rmt_chan, s_encoder, payload, sizeof(payload), &tx_cfg);
    rmt_tx_wait_all_done(s_rmt_chan, pdMS_TO_TICKS(10));
}

/* 渐变 Tick(在 FreeRTOS 任务中每 15ms 调用一次) */
void led_pwm_fade_tick(void)
{
    if (s_current == s_target) return;
    if (s_current < s_target) {
        uint8_t d = s_target - s_current;
        s_current += (d > FADE_STEP) ? FADE_STEP : d;
    } else {
        uint8_t d = s_current - s_target;
        s_current -= (d > FADE_STEP) ? FADE_STEP : d;
    }
    ws2812_write(s_current);
}

2.2 BLE Mesh 控制逻辑

三档调色实现

将 Generic Level 模型的范围(-32768 ~ 32767)平均分为三段,每段对应一种色调:

Level 范围 色调 RGB 值 效果
-32768 ~ -10923 冷色调 (100, 150, 255) 蓝白冷光
-10922 ~ 10922 自然暖白 (255, 180, 80) 暖白光
10923 ~ 32767 暖黄色 (255, 220, 30) 温暖黄光
cpp 复制代码
static void apply_level_color(int16_t lv)
{
    if (lv < -10923) {
        led_pwm_set_color(100, 150, 255);   // 冷色调
    } else if (lv <= 10922) {
        led_pwm_set_color(255, 180, 80);    // 自然暖白
    } else {
        led_pwm_set_color(255, 220, 30);    // 暖黄色
    }
}

优先级控制逻辑

系统存在三层控制,优先级从高到低:

优先级 控制源 行为
🔴 最高 硬件总开关 关闭时屏蔽 BLE 和 PIR,强制关灯
🟡 中 PIR 人体感应 有人强制白光,屏蔽手机所有指令
🟢 最低 手机 BLE 控制 正常开关 + 调色

2.3 PIR 人体感应

PIR 触发时保存当前灯光状态(开关 + 亮度 + 颜色),强制切换白光;人离开后完整恢复之前的状态。

cpp 复制代码
static void pir_on_motion(void)
{
    s_pir_active = true;
    /* 保存当前状态 */
    s_saved_led_on     = g_local_led_on;
    s_saved_brightness = g_local_brightness;
    led_pwm_get_color(&s_saved_r, &s_saved_g, &s_saved_b);
    /* 强制白色开灯 */
    led_pwm_set_color(255, 255, 255);
    uint8_t bri = g_local_brightness ? g_local_brightness : 200;
    led_pwm_set(true, bri);
}

static void pir_on_idle(void)
{
    s_pir_active = false;
    /* 恢复之前的颜色和状态 */
    led_pwm_set_color(s_saved_r, s_saved_g, s_saved_b);
    led_pwm_set(s_saved_led_on, s_saved_led_on ? s_saved_brightness : 0);
    g_local_led_on     = s_saved_led_on;
    g_local_brightness = s_saved_brightness;
}
      

2.4 硬件总开关

使用 FreeRTOS 任务轮询 GPIO,检测下降沿(按下瞬间)触发 Toggle,50ms 防抖。

cpp 复制代码
// 检测下降沿(按下)
if (last_level == 1 && cur_level == 0) {
    vTaskDelay(pdMS_TO_TICKS(50));  // 防抖
    if (gpio_get_level(MASTER_SW_GPIO) == 0) {
        s_master_on = !s_master_on;
        if (!s_master_on) {
            /* 关闭:强制关灯 */
            led_pwm_set(false, 0);
        } else {
            /* 开启:恢复正常控制模式 */
            led_pwm_set_color(255, 255, 255);
        }
    }
}

三、项目结果演示

3.1 操作流程

编译与烧录

①打开 main/project_config.h,将 #define NODE_ID 0修改为对应设备编号(0~2)

​​

②设置目标芯片,点击底部任务栏"Set Espressif Device Target"设置IDF_TARGET芯片为ESP32

​​

③烧录并打开串口监视器,通过日志和操作数据进行调试

​​

手机配网

①打开nRF Mesh App → Network → 右上角"+"扫描

通过UUID第三字节(00,01,02,03,04)识别节点,依次配网(选择No OOB)

②配网成功后,节点LED闪烁三次,OLED显示变为已配网状态,为每个节点的OnOff Server和Level Server绑定App Key 1​​

创建分组与订阅

在Groups界面创建 Node 0,1Node 1,2Node 0~2 三个分组,为每个节点的OnOff Server和Level Server订阅相应分组

功能控制

单灯控制:在Network中选择节点,使用ON/OFF和Level滑块

分组控制:在Groups中选择分组,使用ON/OFF和+/-按钮

感应控制:模拟人体走动触发灯光的开关

3.2 视频演示

零知派ESP32---BLE Mesh蓝牙组网智能灯控系统

本视频展示了基于ESP32多节点的BLE Mesh智能灯控系统的完整操作流程。包括:三台ESP32在nRF Mesh App的配网全过程、分组控制下的WS2812三档色调切换(冷色调 / 暖白 / 暖黄)、OLED状态显示、PIR人体感应自动触发白光及离开后恢复原始灯光状态,以及硬件总开关一键切换系统启停。

四、常见问题解答(FAQ)

Q1: WS2812 初始化后显示乱码白光**?**

A:检查 RMT 时钟是否设为 80MHz,时序 Tick 数是否与上文一致。10MHz 时钟会导致时序放大 8 倍,WS2812 无法识别。

Q2: PIR 触发后颜色恢复不对**?**

A:确认 led_pwm_set() 内部没有强制重置颜色为白色,颜色应只在

led_pwm_set_color() 中修改。

**Q3:**按键抖动导致误触发?

A:轮询任务检测到下降沿后延迟 50ms 再次确认电平,确保稳定后才切换状态。

项目资源整合

ESP-BLE-MESH 架构: ble-mesh-architecture

BLE Mesh API: bluetooth/esp-ble-mesh

相关推荐
计算机安禾6 小时前
【c++面向对象编程】第29篇:定位new(placement new):在指定内存上构造对象
开发语言·c++·算法
计算机安禾6 小时前
【c++面向对象编程】第27篇:空类的大小为什么是1?——C++对象标识的秘密
开发语言·c++·算法
rGzywSmDg6 小时前
如何在Dev-C++中选择TDM-GCC编译器
linux·jvm·c++
云泽8087 小时前
笔试算法 - 滑动窗口篇(二):从异位词到最小覆盖子串的通用框架
c++·算法
_wxd6667 小时前
类与对象 (上) (C++)
c++
basketball6167 小时前
并查集基础算法总结 C++ 实现
开发语言·c++·算法
凤凰院凶涛QAQ7 小时前
《C++转Java快速入手系列》String篇:在C++里拼字符串像搬砖,在Java里拼字符串像玩乐高 —— 还是带垃圾回收的那种。
java·开发语言·c++
雪度娃娃7 小时前
Asio——socket的创建和连接
linux·运维·服务器·c++·网络协议