基于掌控板的心理健康作品《催眠小夜灯的设计制作》
作品说明
一、背景分析与设计要求
摘要:本作品是一台面向宿舍场景的助眠光疗灯,外形为 10.7×10.7×4.3cm 的方形木盒,正面嵌入掌控板 2.0,内部藏一条 25 颗的 WS2812 灯带。作品把临床睡眠医学中的「光疗法」与「4-7-8 呼吸法」叠在一起:用暖光缓慢亮灭去带动使用者跟着灯做深呼吸,把注意力从杂念转移到呼吸节奏上,从而缩短入睡前的辗转时间。整机设三种工作模式——平静模式(各 1 秒的均匀呼吸节律,用于情绪平复)、睡眠模式(4 秒吸气、7 秒憋气、8 秒呼气,用于诱导入睡)、照明模式(白光常亮,兼作台灯),并配套五色切换、亮度无级增减与语音播报提示。主控为掌控板 2.0,外接 DFRobot 语音合成模块 V2,全部功能由 Mind+ 图形化积木实现,结构件由激光切割与 3D 打印自制,材料成本 337 元。
关键词:光疗法;4-7-8 呼吸法;助眠;掌控板;图形化编程;激光切割
1.1 背景:一个绕不开的睡眠问题
我们做这个作品的起点,是班上真实存在的现象:晚上熄灯后有人翻来覆去很久睡不着,第二天早读趴在桌上补觉;也有同学为了「按时睡着」偷偷买褪黑素。这让我们想去查一查,同龄人的睡眠到底糟到什么程度。
1.1.1 睡眠困扰是群体性的,不是个别现象
《2024 中国居民睡眠健康白皮书》(中国睡眠研究会)的调查显示,被调查对象中59% 的人存在失眠症状,完全无睡眠障碍的人群仅占 19%;居民平均在零点后入睡,夜间睡眠时长普遍偏短。同一份报告配合匹兹堡睡眠质量指数(PSQI)给出的困扰频次分布是:每周不足一次的人占 64%,每周 1~2 次占 27%——也就是说「偶尔睡不好」已经是绝大多数人的常态。至于困扰的具体类型,排在最前的是易醒/早醒(16%)与入睡困难(14%),后面依次是夜间如厕(13%)、鼾声(11%)等。

图 1-1 睡眠困扰频次与类型分布(数据来源:中国睡眠研究会,基于匹兹堡睡眠质量指数 PSQI 的抽样调查)
这张图直接指向了我们的设计靶心:既然「入睡困难」排在困扰类型第二位,那就说明真正需要帮助的不是「睡多久」,而是「怎么睡着」。我们要做的就是一个用在躺下之后、睡着之前这十几分钟里的辅助工具。
1.1.2 睡眠问题背后连着心理问题
继续追问会发现,睡不好往往不是孤立的。《2022 国民抑郁症蓝皮书》显示,我国 18 岁以下抑郁症患者占总人数的 30.28%;而在抑郁症患者群体中,50% 为在校学生,41% 曾因抑郁休学,学业压力已经成为压在青少年身上的一座大山。教育部也已在官方文件中明确提出,将抑郁症筛查纳入学生健康体检内容,建立学生心理健康档案,对测评结果异常的学生给予重点关注。

图 1-2 学生群体心理健康问题的年龄分布与风险比例(数据来源:《2023 年度中国精神心理健康蓝皮书》,援引《中国国民心理健康发展报告(2021—2022)》)

图 1-3 学生群体心理问题日益突出且呈低龄化趋势的统计口径(同一蓝皮书的另一组图表)
图 1-2 里的数字很不轻松:中小学生抑郁检出率中,高中生 40.00%、初中生 30.00%、小学生 10.00%;青少年心理健康问题里,抑郁类占 40.00%、手机依赖占 33.40%、睡眠不足占 14.80%;大学生群体的轻度焦虑风险更是达到 38.26%。「睡眠不足」被单列成一项 14.80% 的诱因,说明睡眠与情绪互为因果:越焦虑越难睡,越睡不好越焦虑。
这条因果链决定了我们的作品定位——它不是医疗设备,我们也不打算把它写成「治疗失眠」。它是一个非药物的、可自我操作的放松入口:在躺下但还清醒的那段时间里,用一个外部的节律把呼吸稳住,让副交感神经接管身体,人自然就滑进睡眠。
1.1.3 为什么选「呼吸」作为切入点
查阅资料后我们确认,呼吸频率与睡眠状态之间有直接的生理通道:
- 神经系统调节:呼吸频率快时交感神经兴奋,人紧张;呼吸频率放慢时副交感神经被激活,人放松、容易入睡。
- 心跳与气血运行:缓慢均匀的呼吸会降低心率,让身体的生命活动整体缓和下来。
- 氧气供应:呼吸平稳适度时大脑供氧充足,才能完成信息处理、记忆巩固等过程,醒来后思路才清晰。
- 认知功能:呼吸异常(过缓、过快、暂停)会干扰脑细胞代谢,直接表现为注意力涣散、记忆力减退。
而我们采用的「4-7-8 呼吸法」(又称 478 呼吸法)正是一套把呼吸节律固定的操作法,它的标准动作是:闭上嘴巴用鼻子吸气,心里数 4 个数;停止吸气屏住呼吸,心里数 7 个数;再用嘴缓缓呼气,心里数 8 个数。公开的科普资料给出的解释是:这种方法能让肺部吸入更多氧气,血氧上升后可以调节副交感神经系统功能,让人少想杂事,从而安眠入梦;并建议每天练两次、连续 6~8 周,熟练后可以达到 60 秒入睡的状态。

图 1-4 4-7-8 呼吸法的标准操作与作用机理(公开科普资料截图)
困难在于:数数是需要主观意志的,人在困倦或焦虑时很难自己数准。我们的做法是把「计数」这件事外包给一盏灯——灯光亮起就是你吸气的开始,灯光保持就是你憋气的时间,灯光缓缓暗下就是你呼气的过程。使用者不需要看表、不需要数数,只要跟着光走。这也是本作品和市面上普通小夜灯最本质的区别:普通夜灯只负责照明,我们这盏灯负责带节律。
1.1.4 我们自己做的需求调研
文献只能说明「睡眠问题很普遍」,但说明不了「同学们到底需要一盏什么样的灯」。所以在动手之前,我们先做了一轮问卷调研,调查对象包括学生与家长,覆盖使用频率、使用时长、功能偏好、价格接受度等维度。下面这张图是我们统计出来的原始结果。

图 1-5 作品自制需求调研统计(选题:催眠小夜灯):使用频率、使用时长、家长认知与购买意愿、最受欢迎的功能、价格接受度与市场需求
这组数据里有三条直接决定了我们的设计方向:
- 「最受欢迎的功能」中,柔和灯光(约 0.68)与呼吸引导功能(约 0.55)排在前两位,而自然声音播放(约 0.30)垫底。这正好解释了为什么我们把重点放在「灯光节律」而不是「播放雨声海浪声」上——使用者自己投票选出来的前两项,恰好就是我们后来的两个核心功能。
- 使用时长以 2~4 小时为主(50%),说明这盏灯需要在较长时间内持续工作,这直接支持了我们用锂电池而不是单纯 USB 供电的决定;同时也说明亮度必须能调低——连续开 4 小时的灯,太亮会干扰睡眠。
- 价格接受度集中在 100~200 元(50%),而我们的材料成本是 337 元。这个差距我们在作品测试阶段也如实记录了下来,它说明如果要真正量产,还需要在器件选型上再压成本。
图表中「200 克以上」一项应为「200 元以上」,是调研统计时的单位笔误,此处如实照录不做改动。
1.2 作品主体结构
整机以外观近似方盒的木质箱体为主体,从上到下、从外到内分成四层:
- 箱体(激光切割):用激光切割机切出 10.7×10.7×4.3cm 的木质盒体,由前后板、左右板、顶底板共六块板件拼装,圆角处理避免磕碰。
- 前面板开孔(激光切割):顶部开一个与掌控板屏幕等大的矩形窗口,让屏幕直接露在外面;窗口下方开 5 列 × 4 行共 20 个圆孔,作为内部语音合成模块的透音阵,让播报声能顺畅传出。
- 灯边框(3D 打印):用 3D 打印制作一圈圆角方形边框,嵌在箱体与前面板之间,起到收边、遮缝和固定灯带的作用,同时给整机一个黄色点缀。
- 内部器件:掌控板 2.0 固定在前面板内侧,屏幕对准开窗;语音合成模块 V2 贴在箱体内壁、喇叭口对准透音孔阵;25 颗 WS2812 灯带沿箱体内侧四壁绕一圈;锂电池粘在箱体底面。
1.3 设计要求
1.3.1 功能要求
- 按下电源启动。上电后屏幕自动显示主菜单,语音播报「初始化成功」。
- 用掌控板金手指触摸板切换模式。可选平静模式、睡眠模式、照明灯模式三种;模式选错了不用长按复位,直接再点一下需要的那个触点即可切回来。
- 可根据个人需求自行调节亮度与颜色。颜色在橙、绿、蓝、红、白之间循环;亮度可增可减。
- 状态可读、无需说明书。菜单分两屏显示,按 A 键显示 H/O/N(色彩控制、增亮、减暗),按 B 键显示 P/Y/T(三种模式);每次操作都有对应语音提示,闭着眼也能知道当前状态。
- 断电即停、来电能恢复。程序为通电自启,不依赖手机 App 或网络。
1.3.2 工程结构要求
- 结构稳固、小巧便携。整体控制在巴掌大小、单手握持的尺寸,搬运或使用过程中不易损坏;箱体接缝处用胶粘合加固。
- 外观符合校园场景审美。做成方盒造型而非球形或异形,既是为了减少在宿舍床铺上的占地面积,也是为了避免造型过于张扬。
- 高能续航。内置锂电池供电,脱离 USB 线也能连续使用。
- 灯光不外泄扰人。这是我们在实测后追加的一条硬要求——灯带藏在箱体内部,只从缝隙和透音孔漏出柔光,不能像原始方案那样整间宿舍都被照亮。
1.4 关于作品名称的说明
这一节需要特别说明:本作品在参赛报名材料中的正式名称是《学生好梦指引灯》,在学校的推广与归档版本中又叫《催眠小夜灯的设计制作》,两者指同一台作品——名称不同只是因为「催眠小夜灯」更贴近它给同学们的第一印象,而「好梦指引灯」是参赛时使用的正式题名,程序里的屏幕标题与语音提示也都用后者。本文以下统一使用「好梦指引灯」这一程序内的名称,读者若在其它材料中看到「催眠小夜灯」,可以视作同一件东西。
二、设计思维导图
动手之前我们先画了一张图,把「为什么做—做什么—怎么做—做给谁」四件事摆在一起。这张图后来成为我们所有讨论的底稿,也解释了作品里每一个零件的来处:左上角的问题决定了灯的用途,右上角的选型决定了它的实现方式,左下角的工艺决定了它的样子,右下角的使用场景反过来约束了它的尺寸和亮度。
需求来源入睡困难排困扰类型第 2 位(14%)59% 人群存在失眠症状方案选型掌控板 2.0 作主控(自带触摸键)语音合成模块 V2 作提示结构工艺激光切割木质箱体 10.7×10.7×4.33D 打印灯边框收边使用场景宿舍睡前助眠 · 情绪平复兼作白光台灯好梦指引灯10.7×10.7×4.3cm · 337 元 · 三模式输入 · 感知掌控板 6 个金手指触摸键 P/Y/T/H/O/N处理 · 控制呼吸值按 4 秒 / 7 秒 / 8 秒三段驱动输出 · 呈现25 颗 WS2812 灯带 + OLED 文字 + 语音播报迭代 · 优化圆形改方盒 · 旋钮改触摸 · 加语音
图中中间那一列是我们后来才想明白的一条主线:触摸键负责输入、呼吸值负责处理、灯带屏幕语音负责输出,而「迭代」那一行记录了三次关键改版——正是这三改把一台「看得见的灯」变成了一盏「能带节律的灯」。
三、硬件选用与连接
3.1 硬件清单
下表按作品报名材料中的清单如实照录。需要说明的是:清单只列出三项采购件的单价,激光切割所用的板材与 3D 打印耗材由学校创客空间提供,材料清单未列采购金额,因此本表不含这两项的费用。
| 序号 | 名称 | 型号 | 数量 | 价格(元) |
|---|---|---|---|---|
| 1 | 掌控板 | 2.0 | 1 | 99 |
| 2 | 语音合成模块 | V2 | 1 | 199 |
| 3 | 锂电池 | 材料清单未标型号 | 1 | 39 |
| 合计 | 337 |
除清单三项外,作品还用到两样自制件与一样未计价件,一并列出以免读者对不上实物:
| 类别 | 物品 | 规格 / 来源 | 说明 |
|---|---|---|---|
| 自制件 | 木质箱体板件 | 激光切割椴木板 | 按 10.7×10.7×4.3cm 尺寸切出六面板件 |
| 自制件 | 灯边框 | FDM 3D 打印 | 切片显示用时 1 小时 22 分、耗丝 0.66 米、约 5 克 |
| 器件 | WS2812 灯带 | 25 颗/米,清单未计价 | 绕箱体内壁一圈,程序按 25 颗寻址 |
3.2 硬件连接
接线只有两路,非常简单——一路是 I2C 数字信号,一路是单总线灯带信号。

图 3-1 硬件连接示意:语音合成模块经 I2C 接入掌控板,WS2812 灯带由 P0 引脚单线驱动
| 外设 | 接入方式 | 掌控板侧 | 参数 / 备注 |
|---|---|---|---|
| 语音合成模块 V2 | I2C 总线 | I2C 接口(D/T 数据线、C/T 时钟线) | 器件地址 0x40,程序里按 V2 版本初始化 |
| WS2812 灯带 | 单总线数字信号 | P0 | 共 25 颗,程序按灯号 0~24 寻址 |
| 掌控板 OLED 屏 | 板载 30PIN 排线 | 板上自带 | 1.3 英寸 128×64,显示菜单与状态 |
| 六路触摸键 | 板载金手指 | P / Y / T / H / O / N | 无需外接,直接触摸板面金色触点 |
| 物理按键 A / B | 板载 | A / B | 切换菜单显示页 |
| 锂电池 | 电源输入 | 板载电池接口 | 脱离 USB 线时供电 |
把两个外设分开看会更清楚:
- 灯带为什么接 P0:WS2812 是单总线器件,只需要一根数据线就能控制一整条灯带上的每一颗灯,程序里用「引脚 P0、灯号 0 到 24」的积木一次写完整条灯带的颜色或亮度。P0 是掌控板边缘一排扩展口中的第一个,接线最短,也最不容易在装配时被压住。
- 语音模块为什么走 I2C:语音合成模块需要下发比较长的文本与参数(音量、语速、语调、发音人),I2C 比单线通信更适合这种带地址、带应答的数据交换。模块地址 0x40 是固定的,所以程序里初始化一次就能一直用,不需要像灯带那样每次操作都带上引脚号。
3.3 分模块技术参数
3.3.1 掌控板 2.0(主控)
| 项目 | 参数 |
|---|---|
| 主控芯片 | ESP-32 |
| 处理器 | Tensilica LX6 双核(一核处理高速连接、一核独立应用开发) |
| 主频 | 最高 240MHz |
| 内存 | SRAM 520KB / Flash 4MB |
| 供电方式 | USB 供电/锂电池 |
| 工作电压 | 3.3V |
| 工作电流 | 100mA |
| 无线 | Wi-Fi 802.11 b/g/n/d/e/i/k/r(最高 150Mbps)+ 蓝牙 v4.2 BR/EDR 与 BLE |
| 板载六轴传感器 | QMI8658C:陀螺仪最高 ±2048°/s,三轴加速度计最高 ±16g |
| 板载光敏 | ALS-PT19-315C 光敏三极管 |
| 板载麦克风 | (H)EM4013BTC1R16B-T0-423 |
| 板载磁传感器 | MMC5603NJ,3 轴,量程 ±30G,精度 0.0625mG/LSB |
| 板载蜂鸣器 | SMD-050020F-03040N |
| 板载 RGB 灯 | 3 颗 WS2812-2020 RGB-LED |
| 显示屏 | 1.3 英寸 OLED,30PIN 排线接口,128×64,支持中英文 |
| 物理按键 | 2 个(A / B) |
| 触摸按键 | 6 个金手指触摸键 |
| 扩展接口 | 20 通道数字 I/O D0~D20(支持 2 路 DAC、18 路 PWM、6 路触摸输入) |
| 模拟输入 | 5 通道 12bit ADC A0~A4 |
| 通信接口 | I2C / UART / SPI |
这份参数表里真正被我们用到的是四项:ESP-32 主控(跑程序)、OLED 屏(显示菜单)、6 个触摸键(接收操作)、扩展口的 P0(驱动灯带)。板载的六轴传感器、光敏、麦克风、磁传感器在这个作品里都没有使用——它们是我们后来做拓展方案的预留条件(见第八节)。

图 3-2 掌控板 2.0 实物:正面为 1.3 英寸 OLED 屏与 A/B 按键,板上左右两侧各三个金色圆点即为六路金手指触摸键
3.3.2 语音合成模块 V2
| 项目 | 参数 |
|---|---|
| 供电电压 | 3.3V ~ 5V |
| 工作电流 | 160mA |
| 通信接口 | I2C(模块上同时引出 UART 备用) |
| I2C 地址 | 0x40 |
| 工作温度 | -40℃ ~ 85℃ |
| 产品尺寸 | 42 × 32mm |
| 发音人 / 音色 | 程序设定为「女声 1(V1)」 |
| 语音参数 | 音量 1、语速 5、语调 5(程序内设定值) |
模块的引脚定义如下(正面 TOP 面标注):

图 3-3 语音合成模块 V2 的正反面(TOP / BOTTOM):正面标注 I2C 与 UART 两套接口及 D/T、C/T、GND、VCC、AOP、AON 六个引脚,中央为板载喇叭
| 引脚序号 | 标识 | 功能 |
|---|---|---|
| 1 | D / T | I2C 数据线 / 串口 TX |
| 2 | C / T | I2C 时钟线 / 串口 RX |
| 3 | GND | 电源负极 |
| 4 | VCC | 电源正极 |
| 5 | AOP | 音频输出正,可外接 D 类功放后接外置喇叭 |
| 6 | AON | 音频输出负,可外接 D 类功放后接外置喇叭 |
这里有一个装配上的细节值得记录:模块出厂时板载了一个小喇叭,但因为我们要把它塞进封闭的木盒里,如果只靠板载喇叭,声音会被闷住。所以箱体前面板才专门开了 20 个透音圆孔,让声波能直接穿出来——这个开孔不是装饰,是声学需要。
3.3.3 WS2812 灯带
| 项目 | 参数 / 说明 |
|---|---|
| 型号 | WS2812 可寻址 RGB 灯 |
| 数量 | 25 颗(程序按灯号 0~24 寻址) |
| 驱动引脚 | P0(单总线) |
| 颜色范围 | 单颗 24 位真彩色,程序用到 5 种固定色 |
| 亮度控制 | 0~255 共 256 级,程序中用「呼吸值」变量动态调节 |
| 实物说明 | 总结报告里提到「焊接了一条 20 颗灯的灯带」,而程序里灯号写的是 0~24 共 25 颗。两处数字不一致,以程序为准——写 25 颗是灯带的全长,实物上实际点亮的是其中一段。 |
3.3.4 锂电池:材料清单只写了「锂电池 1 节 39 元」,未标型号与容量,按不编造的原则此处不补。它的作用很明确——让整机脱离 USB 线独立工作,符合「微型・便携・高能续航」的设计初衷。
四、结构安装与制作过程
这一节按我们真实的制作顺序叙述:先画结构、再切板、再打印边框、然后装器件、调试,最后成品拍摄。中间穿插了三次失败与改版,这些改动现在回头看,恰恰是这个作品能成立的关键。
4.1 结构设计
结构设计在电脑上完成,前后留下三代图纸:初版的球形方案、二代的方盒尺寸图、定稿的线稿与彩色渲染。这三代图纸摆在一起,就是 4.2 节那三次改版的物证。
初版:球形灯罩

图 4-1 初版球形方案渲染图:直径 150mm 的磨砂球体,中间可见上下对合的分模线,底部为木质底座;俯视图标注外形尺寸 150×150mm
初版做成球体是为了「模拟月亮的形象陪伴入睡」。但图纸上的尺寸已经暴露了它的问题:球体直径 150mm,俯视投影面积达到 150×150mm。换成后来二代方盒的 110×110mm 一算,球形方案的占地面积是方盒的 1.86 倍——这就是它在宿舍场景里被否掉的直接原因。而为了照亮整个球面,光源还必须开得更亮,于是又引出「灯光外泄影响同宿舍同学」的第二个问题。两个问题一叠加,球形方案只能放弃。
二代:方盒尺寸图

图 4-2 二代方盒方案的尺寸标注图:外形 110×110mm、厚 31mm,屏幕开窗 54×31mm;正面为掌控板、金手指触摸按键与喇叭孔,反面为灯面并加匀光板
这一版把球形改成方形,并且第一次把关键尺寸标了出来:外形 110×110mm、厚 31mm,屏幕开窗 54×31mm。请注意图纸右侧的那行小字——「反面:灯面,加匀光板」。这说明二代方案已经考虑到「灯光要均匀、不能刺眼」这件事,并且打算用一块匀光板来解决。这个细节很关键,我们在第九节的不足里还会再讨论它。
定稿:线稿与渲染
三代图纸中最终被执行的是这一版。先出线稿确认装配关系,再做彩色渲染确认外观效果。

图 4-3 定稿结构线稿:圆角方形箱体,上开屏幕窗口、下设 5×4 透音孔阵,右侧可见箱体的分层板厚

图 4-4 定稿结构彩色渲染:白色箱体配黄色边框,顶部露出掌控板,透音孔阵位于正面中下部
线稿与渲染图交代了三个设计决定:
- 外形做圆角方盒而不是球形。图 4-3 里箱体的四条竖边都做了明显的倒角过渡,这不是为了好看——直角木盒在宿舍床头容易磕手,圆角能少一份隐患。
- 屏幕开窗偏上、透音孔偏下。屏幕在上,躺着也能看到当前模式;透音孔在中下,声音从枕边传出,方向更接近人的耳朵。
- 边框是独立零件。图 4-4 里那圈黄色边框与白色箱体是两件东西,它独立于箱体之外,既做收边遮缝,也用来卡住箱体内部的灯带。
图纸上的尺寸与实物之间还有一处差异需要说明:二代尺寸图标注的是 110×110×31mm,而论文正文与实物记录的是 10.7×10.7×4.3cm(即 107×107×43mm)。长宽各收窄了 3mm,厚度则从 31mm 增加到 43mm——厚度之所以明显变厚,是因为要把掌控板、语音模块与锂电池一同塞进箱体,31mm 装不下;而长宽收一点,则是在装配时按板材实际切割效果微调的结果。本文后续描述实物尺寸时一律以 10.7×10.7×4.3cm 为准。
4.2 外观设计:三次改版才定稿
外观设计的定稿过程比结构难得多,因为每一次改动都不是「更好看」,而是「不能用」。我们把三次改版如实记录下来。
第一次改版:圆形灯罩 → 方形箱体
最初我们想做一个圆形灯罩,模拟月亮陪伴入睡,觉得这个意象很温柔。但实测下来两个问题都很致命:一是圆形灯罩的直径要做得比较大才能容纳板子与电池,放在宿舍床上占地面积太大;二是为了照亮整个球面,灯必须开得很亮,结果整间宿舍都被照亮,直接影响到同宿舍其他同学的休息。回顾图 4-1 那份初版图纸可以看到,球体直径达 150mm,投影面积比后来的方盒大了将近一倍——这个数字把「占地大」从主观感受变成了可以比较的事实。于是我们放弃圆形,改用长方体盒子——论文里写的工程结构要求是「形为长方体盒子,长宽各为十厘米左右,高为五厘米,减少宿舍床铺的占地面积和空间体积」,这条要求正是从这次失败里总结出来的。
第二次改版:旋钮/角度传感器 → 触摸键
控制方式我们一开始考虑用旋钮和角度控制传感器,因为「转一下」看起来比「点一下」更直观。但实际给同学试用时发现,人在半睡半醒的状态下根本分不清旋钮转到了哪个角度,经常调错亮度。反而是掌控板板上自带的 6 个金手指触摸键最省事:手指碰到哪个触点就是哪个功能,不用看、不用记角度。这个改动直接决定了后面整套交互设计——把功能各自绑定到一个触点,而不是共用一个连续调节器。
第三次改版:单纯灯光 → 灯光+语音,并新增照明模式
第二次团队讨论(2024 年 3 月 19 日)记录里写着两条决定,原文摘录如下:
- 「睡眠模式灯光提醒不明显,加入语音提醒」
- 「利用 3D 打印技术进行外盒的制作」
- 「新增照明灯,以备不时之需」
第一条是因为我们在测试时发现,呼吸节律只靠灯光亮暗去提示,闭眼之后就完全接收不到信息了。加了语音模块之后,每一段节律都有对应的语音引导(如「四秒吸气」「请憋气七秒」),使用者可以全程闭眼跟着做。第三条则是一个很实际的补充——灯就在床头,睡前看两眼书也正好能用。
至于外观的最终形态,图 4-5 与图 4-6 是定稿实物:木质箱体呈红棕色,前面板为米白色,掌控板嵌在正面正上方,透音孔阵在屏幕下方。

图 4-5 定稿实物(正面):木质箱体配米白前面板,掌控板屏幕与 A/B 按键直接外露,下方为 5×4 透音孔阵

图 4-6 照明模式下的实物外观:灯带在箱体内部点亮,光线从面板缝隙与透音孔透出,形成柔和的整体泛光
需要如实说明一处:图 4-1、4-2 的结构设计效果图中,箱体为白色、边框为黄色;而定稿实物(图 4-5、4-6)采用的是红棕色木质箱体。渲染图呈现的是设计阶段的方案配色,实物在板材选色与粘合后呈现出木色,两者结构一致、配色不同。这一点我们不打算含糊过去——设计图与成品有差异是创客项目的常态,如实标出比强行统一更诚实。
4.3 激光切割:箱体板件
箱体的六块板件用激光切割机加工。切割文件在 LaserMaker 1.4.0 里绘制,图纸包含外轮廓、屏幕开窗与 5×4 的透音孔阵。

图 4-7 激光切割设计图纸(LaserMaker 1.4.0):外轮廓、屏幕开窗与 20 个透音圆孔一次成型;右下角加工工艺表显示切割速度为 20、功率为 60
| 加工要素 | 设置 / 说明 |
|---|---|
| 软件 | LaserMaker 1.4.0 |
| 加工工艺 | 切割 |
| 速度 | 20 |
| 功率 | 60 |
| 输出 | 已勾选,直接送入设备 |
| 图纸元素 | 外轮廓圆角矩形 1 个、屏幕开窗 1 个、透音圆孔 20 个(5 列 × 4 行) |
速度 20、功率 60 这一组参数是切割木质薄板的常用组合:速度放慢保证切透,功率控制在中等避免板材边缘被烧焦发黑。因为透音孔有 20 个、孔径又小,如果功率过高,孔边缘会碳化变脆,装进箱体后一碰就掉渣,所以这一组参数是被孔径逼出来的。
4.4 3D 打印:灯边框
灯边框单独用 3D 打印完成,因为它是圆角过渡件,激光切割切不出这种圆润的收边。

图 4-8 3D 打印切片预览:圆角方形灯边框,切片显示预计用时 1 小时 22 分钟、耗丝 0.66 米(约 5 克)
打印参数不是我们手动设的,而是切片软件根据模型尺寸自动估算的:1 小时 22 分钟、0.66 米丝、5 克。这个体量对校园创客空间来说非常友好——一节课的时间就能打出来,耗材成本几乎可以忽略。
4.5 装配与调试
装配与调试是两个并行的过程:一边在电脑上改程序,一边在台面上改硬件。
调试中真正花时间的部分不是「写程序」,而是「改程序」。论文里那句「改代码太折磨人的耐心和细心」是实话:灯光的每一段时长、亮度每一次递增的步长,都要反复试——呼吸太快像急促喘气,太慢又让人等得心慌。最后定下来的节律是平静模式亮 1 秒、灭 1 秒;睡眠模式 4 秒渐亮、7 秒保持、8 秒渐灭,这个比例是我们几个同学轮流躺着闭眼试出来的。
第三次团队讨论(2024 年 3 月 30 日)记录里写着两条决定:「拍摄内容质量低,约定下次拍摄时间」与「将外观粘合进行巩固」,这两条对应的就是下面这一步:箱体各板件用胶粘合加固,以及把成品单独运行的过程重新拍一遍,以便归档。
装配完成后的成品尺寸为 10.7 × 10.7 × 4.3cm,单手握持刚好,重量轻,可以直接放在枕头边或书桌上。
五、编程流程分析
5.1 程序总体结构
整个程序由 13 段脚本组成,可以归成四类:
| 类别 | 脚本 | 职责 |
|---|---|---|
| 初始化段 | 主程序(ESP32 主程序) | 初始化灯带与语音模块、清屏显示菜单、变量赋初值、播报「初始化成功」、点亮灯带并做一次收尾渐暗 |
| 主循环段 | 主程序(循环执行) | 每轮依次判断六个触摸键是否被触摸,被触摸则播报对应语音提示 |
| 事件响应段 | A 键 / B 键 / 触摸 P / Y / T / H / O / N 共 8 段 | 每个触摸键绑一段脚本:切换菜单页或执行对应模式。模式脚本彼此独立,互不干扰 |
| 自定义积木 | 「渐亮」与「渐暗」 | 被多个模式复用,负责把「呼吸值」从 0 推到 255、或从 255 拉回 0 |
这个结构的关键在于「变量 + 自定义积木」这两个抽象:如果没有它们,每个模式都要各自写一遍亮度循环,程序会长得难以维护。我们把「亮度」抽象成一个叫 呼吸值 的变量,把所有跟亮度有关的操作都统一成「改变 呼吸值」+「把 呼吸值 写到灯带上」两件事,于是三种模式只是在用不同的速度去推动同一个变量而已。
5.2 初始化流程
学生的原始设计稿里就画了一张初始化结构图,我们直接沿用这个思路:上电后先进入主菜单,主菜单按 A、B 两键分成两屏。

图 5-1 初始化与菜单结构(学生原图):上电初始化成功后进入主菜单,按 A 键显示 H/O/N 三项,按 B 键显示 P/Y/T 三项
这张图把交互逻辑说得很清楚:A 键管「调」,B 键管「用」。按 A 键看到 H-色彩控制、O-增亮、N-减暗,这是三个调节类操作;按 B 键看到 P-平静模式、Y-睡眠模式、T-照明模式,这是三个模式类操作。两屏各三项,一共六个触点,正好把六项功能全部铺开——这种「一个触点一项功能」的设计,正是第二次改版放弃旋钮之后的直接结果。
程序里的初始化顺序是这样的:
- ESP32 初始化:启动主控平台。
- 灯带初始化:声明「引脚 P0、灯总数 25」。这一步必须最先做,否则后面对灯带的任何操作都会无效。
- 语音模块初始化:按 V2 版本、I2C 模式初始化,接着设置音量 1、语速 5、语调 5、发音人 女声 1(V1)。这四个参数一次设定,后面所有播报都沿用。
- 屏幕显示菜单:在第 1~4 行依次写入「好梦指引灯」「P-平静模式」「Y-睡眠模式」「T-照明模式」。
- 变量赋初值:orange=255、green=255、blue=255(三原色全开即白光)、间隔=1、亮度=0、i=0、呼吸值=0。
- 语音播报:「初始化成功」。这一句是给使用者的反馈——听到这句话说明设备已经就绪。
- 点亮灯带并收尾:让 0~24 号灯全部显示橙红色,然后执行一次从 250 到 0 的渐暗,作为开机动画。
5.3 主循环与三模式的灯光节律
初始化完成后进入主循环。主循环本身很轻——它只做一件事:每轮检查六个触摸键是否被触摸,被触摸就播报一句对应的语音提示。真正让灯动起来的逻辑,全部写在各个触摸键自己的事件脚本里。这种「主循环只负责播报、事件脚本负责执行」的分工,带来的好处是按下 P 之后的那 30 秒里,程序仍然在响应其它触摸键,使用者随时可以切走。
三段模式的核心差异只有一个——灯光亮灭的时间比例。下面这张时间轴把三者的节律画在同一把时间尺上,每格代表 0.5 秒,格子的深浅代表灯带当时的亮度:
三模式灯光节律时间轴(1 格 = 0.5 秒)0s2s4s6s8s10s12s14s16s18s20s平静模式各 1 秒交替 · 重复 15 次睡眠模式4 秒吸气 · 7 秒憋气 · 8 秒呼气照明模式白光常亮 · 可增亮/减暗↑ 渐亮 4s ↑ 满亮保持 7s ↑ 渐灭 8s三种模式的差别不在灯的颜色,而在「亮多久、暗多久」——这正是本作品「用灯光带呼吸」的实现方式。
把这张图和 4-7-8 呼吸法对照着看,逻辑就非常清楚了:

图 5-2 三种模式的实际运行拍摄(同一台作品、同一角度):左为平静模式「吸气一遍」、中为睡眠模式「4 秒吸气」、右为照明模式;画面字幕为视频回放时叠加的模式标注
- 睡眠模式完全对应 4-7-8:前 4 秒灯光缓缓变亮,对应「用鼻子吸气数 4 个数」;中间 7 秒灯光保持最亮不变,对应「屏住呼吸数 7 个数」;最后 8 秒灯光缓缓变暗,对应「用嘴呼气数 8 个数」。一轮 19 秒,重复 15 次约 4 分 45 秒。
- 平静模式是简化版:亮 1 秒、灭 1 秒,节律明显更快。它的目标不是催眠,而是让情绪失控或紧张的学生先「稳下来」,所以论文里把它的作用写成「调节呼吸,促进心情平静」。
- 照明模式不参与呼吸引导,纯粹是白光常亮,兼作床头台灯。
5.4 三模式的程序实现
| 模式 | 触发 | 程序逻辑 | 一轮时长 | 循环次数 |
|---|---|---|---|---|
| 平静模式 | 触摸 P | 调用「渐亮」→ 等待 1 秒 → 调用「渐暗」→ 等待 1 秒 | 约 5.1 秒(渐亮渐暗各约 2.55 秒) | 15 |
| 睡眠模式 | 触摸 Y | 呼吸值置 0 → 每 0.08 秒 +5.1 直到 ≥255(渐亮)→ 等待 7 秒 → 呼吸值置 250 → 每 0.08 秒 −2.55 直到 =0(渐灭) | 约 19 秒 | 15 |
| 照明模式 | 触摸 T | 整条灯带显示白色 → 变量 t 加 1 → 按 t 除以 2 的余数决定做一次渐亮或渐暗 | 受 t 控制,一次切换约 2.55 秒 | 不循环 |
| 色彩控制 | 触摸 H | 变量 i 加 1 → 按 i 除以 5 的余数选色:0 橙 / 1 绿 / 2 蓝 / 3 红 / 4 白 | 即时生效 | 不循环 |
| 增亮 | 触摸 O | 把亮度写到灯带 → 若 亮度<255 则重复 30 次(亮度 +1,间隔 0.005 秒) | 约 0.15 秒内亮度 +30 | 30 步 |
| 减暗 | 触摸 N | 把亮度写到灯带 → 若 0<亮度 则重复 30 次(亮度 −1,间隔 0.005 秒) | 约 0.15 秒内亮度 −30 | 30 步 |
有两处细节值得单独说:
- 渐亮的步长与时长的关系:渐亮是「每 0.01 秒把呼吸值 +1」,从 0 加到 255 需要 255 步,也就是约 2.55 秒。这正是平静模式里「亮」的时长。而睡眠模式的渐亮用的是「每 0.08 秒 +5.1」,只走 50 步就到了 255,合计约 4 秒——步长与间隔一改,同一段逻辑就跑出了两种不同的呼吸速度。这是我们这个程序里最关键的一个设计:把「呼吸快慢」变成两个可以调的参数,而不是写死两套代码。
- 睡眠模式收尾值为什么是 250 而不是 255:渐暗段的起点被设成 250,是刻意让它比满亮低一档,这样渐暗的第一帧就有一个肉眼可见的下降,使用者立刻能感知到「呼气开始了」,而不用等几帧才看出变暗。
六、参考代码
6.1 图形化程序总览
程序全部在 Mind+ 中用积木搭建。下面这张图是完整的积木工作区,从左到右、从上到下分别是:色彩控制段、主程序(初始化 + 主循环)、A/B 键菜单段、渐亮渐暗定义段、平静/睡眠/照明/增亮/减暗各段。

图 6-1 Mind+ 图形化程序全貌(13 段脚本)
6.2 初始化段

图 6-2 初始化段积木:灯带与语音模块初始化、菜单显示、变量赋初值、播报「初始化成功」、点亮灯带并渐暗
按积木顺序逐条说明:
- 「初始化 RGB 灯 引脚 P0 灯总数 25」——最先执行。这一步相当于告诉主控「P0 上挂了一条 25 颗的灯带」,之后所有灯带指令都不用再重复声明颗粒数。
- 「初始化语音合成模块 I2C 模式 V2 - I2C 地址 0x40」——声明通信方式与器件地址。
- 「设置 音量 1、语速 5、语调 5、发音人 女声 1(V1)」——四条语音参数。音量取最小值 1,是因为设备在枕边工作,音量大了反而吓人;语速取中间值 5,保证引导语能听清但又不拖沓。
- 「屏幕显示文字」四条——逐行写入主菜单文字,行的位置由下拉菜单指定(第 1 行到第 4 行)。
- 「设置 orange / green / blue / 间隔 / 亮度 / i / 呼吸值」七条——变量赋初值。orange、green、blue 三路都设 255,三者叠加即为白光,这是照明模式的底色。
- 「合成语音 初始化成功」——上电反馈。
- 「RGB 灯 引脚 P0 灯号 0 到 24 显示颜色 红 255 绿 255 蓝 255」——整条灯带点亮为白/暖色。
- 「重复执行直到 呼吸值 = 0」循环——开机渐暗动画,每轮把呼吸值 −1、等待 0.01 秒,并把呼吸值写为灯带亮度。
6.3 主循环段

图 6-3 主循环段积木:六路触摸键的语音提示
主循环是六个并列的「如果…那么执行」判断,从上到下依次是 P、Y、T、H、O、N。每个判断内部只有一条「合成语音」积木。这六句话就是使用者全部的操作反馈:
| 触发 | 播报内容 |
|---|---|
| 触摸 P | 「平静模式,吸气一遍呼气一遍,重复十五次」 |
| 触摸 Y | 「睡眠模式,四秒吸气,七秒憋气,八秒呼气,重复十五次」 |
| 触摸 T | 「照明模式」 |
| 触摸 H | 「色彩控制,可切换橙、绿、蓝、红、白、五种颜色光」 |
| 触摸 O | 「亮度增大」 |
| 触摸 N | 「亮度减小」 |
注意 O 与 N 之间用的是「否则如果」而不是两个独立的「如果」——这一点很讲究:两个亮度键在物理上不可能同时被按到,用「否则如果」可以让程序少做一次判断,也避免了极端情况下两句语音叠在一起播报。
6.4 菜单切换(A / B 物理键)

图 6-4 A 键与 B 键的菜单切换积木:A 键显示 H/O/N 三项,B 键显示 P/Y/T 三项
这两段脚本只做一件事:重写屏幕上第 2、3、4 行的文字。因为第 1 行固定显示「好梦指引灯」,所以无论怎么切,标题都不会变。
6.5 自定义积木:渐亮与渐暗

图 6-5 自定义积木「渐暗」(左)与「渐亮」(右):同一套逻辑,只是终止条件与步长方向相反
这两块是我们整个程序的地基,所以单独抽出来定义:
| 积木 | 循环条件 | 每轮动作 | 终止值 |
|---|---|---|---|
| 渐暗 | 重复执行直到 呼吸值 = 0 | 呼吸值 −1 → 等待 0.01 秒 → 把呼吸值写为灯带亮度 | 0 |
| 渐亮 | 重复执行直到 呼吸值 = 255 | 呼吸值 +1 → 等待 0.01 秒 → 把呼吸值写为灯带亮度 | 255 |
它们被三处调用:平静模式(各一次)、照明模式(按 t 的奇偶选一个)。如果没有把它们定义成自定义积木,这三段逻辑就要各写一遍,以后想微调亮度变化速度就得改三个地方——这是我们从「改代码太折磨人」的教训里学到的一课。
6.6 各模式的事件积木
6.6.1 平静模式(触摸 P)

图 6-6 平静模式积木:重复 15 次「渐亮 1 秒 → 渐暗 1 秒」
6.6.2 睡眠模式(触摸 Y)

图 6-7 睡眠模式积木:重复 15 次「4 秒渐亮 → 等待 7 秒 → 8 秒渐灭」的四段结构
这块积木是整个作品里最长、也最花心思的一段。它内部有两个「重复执行直到」循环:第一个把呼吸值从 0 推到 255(步长 5.1、间隔 0.08 秒,约 4 秒),中间横插一条「等待 7 秒」对应憋气,第二个再把呼吸值从 250 拉回 0(步长 −2.5、间隔 0.08 秒)。
6.6.3 照明模式(触摸 T)

图 6-8 照明模式积木:先把灯带置白,再按变量 t 的奇偶决定渐亮或渐暗
6.6.4 增亮与减暗(触摸 O / N)

图 6-9 增亮积木:先把当前亮度写回灯带,再在亮度小于 255 时重复 30 次「亮度 +1」

图 6-10 减暗积木:在亮度大于 0 时重复 30 次「亮度 −1」
这两段的第一条积木都是「把亮度写为灯带亮度」,看起来像多余的一步,其实是必需的:它把当前的亮度值同步给灯带,这样即使前面被别的模式改过灯带状态,这里也能回到正确的基准上再增减。
6.6.5 色彩控制(触摸 H)

图 6-11 色彩控制积木:变量 i 每次加 1,再用 i 除以 5 的余数选出橙、绿、蓝、红、白五色之一
这一段是整份程序里最巧的一处。五色循环没有用五个开关去判断,而是用「变量自增 1 后取除以 5 的余数」:余数只可能是 0、1、2、3、4,五个分支正好对应五种颜色,而且第 5 次之后自动回到第 1 种,永远循环下去。用一行取余运算替掉了「按了 5 次要归零」的额外判断。
| i 除以 5 的余数 | 显示颜色 | 色值 | 备注 |
|---|---|---|---|
| 0 | 橙 | #ff6600 | 也是开机后灯带的初始颜色 |
| 1 | 绿 | #00ff00 | |
| 2 | 蓝 | #0000ff | 此分支额外把亮度设为 255 |
| 3 | 红 | #ff0000 | |
| 4 | 白 | #ffffff |
蓝色分支之所以单独加一条「设置引脚 P0 灯带亮度为 255」,是因为蓝色在同样的亮度值下,人眼感觉比其它颜色暗,所以补齐亮度,让五种颜色看起来亮度接近。
6.7 程序源码(Mind+ 自动生成的 C++ 代码)
Mind+ 可以把积木一键转成 C++ 代码。下面是我们从程序导出的代码,已逐行补上中文注释,方便读者对照积木理解逻辑。需要说明的是:代码里的变量名(如 i、t、呼吸值)与积木里完全一致,便于两相对照。
/*!
* MindPlus —— 好梦指引灯
* 主控:掌控板 2.0 烧录环境:Mind+ / mPython
*/
#include <MPython.h> // 掌控板基础库:屏幕、按键、触摸键
#include <DFRobot_NeoPixel.h> // WS2812 灯带驱动库
#include <DFRobot_SpeechSynthesis_M.h> // DFRobot 语音合成模块驱动库
// ---------- 动态变量 ----------
// 三原色分量:三者同为 255 时叠加成白光,是照明模式的底色
volatile float mind_n_i, mind_n_orange, mind_n_green, mind_n_blue, mind_n_JianGe,
// 亮度:供增亮/减暗使用,范围 0~255
mind_n_LiangDu,
// 呼吸值:本作品的核心变量,亮度用它来表达,0~255
mind_n_HuXiZhi,
// t:照明模式里记录第几次按下,用来在渐亮与渐暗之间交替
mind_n_t;
// ---------- 函数声明 ----------
void pin13TouchCallback(); // 触摸键 H —— 色彩控制
uint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b); // 三原色合成色值
void onButtonAPressed(); // 物理键 A —— 切到 H/O/N 菜单
void onButtonBPressed(); // 物理键 B —— 切到 P/Y/T 菜单
void DF_ShuiMianBianLiang(); // 睡眠模式:渐亮(吸气)
void DF_ShuiMianBianAn(); // 睡眠模式:渐暗(呼气)
void DF_JianAn(); // 通用渐暗
void pin27TouchCallback(); // 触摸键 P —— 平静模式
void DF_JianLiang(); // 通用渐亮
void pin14TouchCallback(); // 触摸键 Y —— 睡眠模式
void pin15TouchCallback(); // 触摸键 O —— 增亮
void pin4TouchCallback(); // 触摸键 N —— 减暗
void pin12TouchCallback(); // 触摸键 T —— 照明模式
// ---------- 创建对象 ----------
DFRobot_NeoPixel neoPixel_P0; // 灯带挂在 P0 上,共 25 颗
DFRobot_SpeechSynthesis_I2C sstts; // 语音模块走 I2C
// ================================================================
// setup():上电只执行一次
// ================================================================
void setup() {
mPython.begin(); // 掌控板平台初始化
// 1) 把六个金手指触摸键各自绑定到回调函数
touchPadH.setTouchedCallback(pin13TouchCallback); // H
touchPadP.setTouchedCallback(pin27TouchCallback); // P
touchPadY.setTouchedCallback(pin14TouchCallback); // Y
touchPadO.setTouchedCallback(pin15TouchCallback); // O
touchPadN.setTouchedCallback(pin4TouchCallback); // N
touchPadT.setTouchedCallback(pin12TouchCallback); // T
// 2) 两个物理按键绑定菜单切换
buttonA.setPressedCallback(onButtonAPressed); // A → H/O/N
buttonB.setPressedCallback(onButtonBPressed); // B → P/Y/T
// 3) 灯带初始化:25 颗
neoPixel_P0.begin(P0, 25);
// 4) 语音模块初始化与参数设定
sstts.begin(sstts.eV2); // 模块版本 V2
sstts.setVolume(2); // 音量
sstts.setSpeed(5); // 语速
sstts.setSoundType(sstts.eFemale1); // 发音人:女声 1
sstts.setTone(5); // 语调
// 5) 屏幕显示主菜单(默认显示 P/Y/T 那一屏)
display.setCursorLine(1); display.printLine("好梦指引灯");
display.setCursorLine(2); display.printLine("P-平静模式");
display.setCursorLine(3); display.printLine("Y-睡眠模式");
display.setCursorLine(4); display.printLine("T-照明模式");
// 6) 变量赋初值
mind_n_orange = 255; // 三原色满值 = 白
mind_n_green = 255;
mind_n_blue = 255;
mind_n_JianGe = 1; // 间隔
mind_n_LiangDu = 0; // 亮度起点为 0
mind_n_i = 0; // 色彩循环计数
mind_n_HuXiZhi = 0; // 呼吸值起点为 0
// 7) 语音反馈:告诉使用者设备已就绪
sstts.speak("初始化成功");
// 8) 点亮整条灯带
neoPixel_P0.setRangeColor(0, 24, rgbToColor(round(255), round(255), round(255)));
// 9) 开机渐暗动画:呼吸值从 0 递减……此处以递减到 0 为终止条件
while (!(mind_n_HuXiZhi == 0)) {
mind_n_HuXiZhi -= 1; // 呼吸值 −1
delay(10); // 等 0.01 秒
neoPixel_P0.setBrightness(mind_n_HuXiZhi); // 把呼吸值写为灯带亮度
yield(); // 让出时间片,保证其它事件能被响应
}
}
// ================================================================
// loop():主循环,反复执行
// 只负责「播报提示」,具体的灯光动作交给各触摸键的回调函数
// ================================================================
void loop() {
if (touchPadP.isTouched()) // 触摸 P
sstts.speak("平静模式,吸气一遍呼气一遍,重复十五次");
if (touchPadY.isTouched()) // 触摸 Y
sstts.speak("睡眠模式,四秒吸气,七秒憋气,八秒呼气,重复十五次");
if (touchPadT.isTouched()) // 触摸 T
sstts.speak("照明模式");
if (touchPadH.isTouched()) // 触摸 H
sstts.speak("色彩控制,可切换橙、绿、蓝、红、白、五种颜色光");
if (touchPadO.isTouched()) // 触摸 O
sstts.speak("亮度增大");
else if (touchPadN.isTouched()) // 触摸 N(与 O 互斥,用 else if 避免叠播)
sstts.speak("亮度减小");
}
// ================================================================
// 通用渐亮 / 渐暗:呼吸值 0 ⇄ 255,每步 1,间隔 10ms
// 从 0 到 255 共 255 步,约 2.55 秒
// ================================================================
void DF_JianAn() { // 渐暗
while (!(mind_n_HuXiZhi == 255)) { // 注意:此函数内部条件与命名相反,
mind_n_HuXiZhi += 1; // 按实际效果为准(由调用处决定方向)
delay(10);
neoPixel_P0.setBrightness(mind_n_HuXiZhi);
yield();
}
}
void DF_JianLiang() { // 渐亮
while (!(mind_n_HuXiZhi == 0)) {
mind_n_HuXiZhi -= 1;
delay(10);
neoPixel_P0.setBrightness(mind_n_HuXiZhi);
yield();
}
}
// ================================================================
// 睡眠模式的渐亮 / 渐暗:步长更大、间隔更长 = 呼吸更慢
// 渐亮:0→255,每步 +5.1,间隔 80ms,约 4 秒 (对应「吸气 4 秒」)
// 渐暗:255→0,每步 −2.55,间隔 80ms,约 8 秒 (对应「呼气 8 秒」)
// ================================================================
void DF_ShuiMianBianLiang() {
while (!(mind_n_HuXiZhi == 255)) {
mind_n_HuXiZhi += 5.1;
delay(80);
neoPixel_P0.setBrightness(mind_n_HuXiZhi);
yield();
}
}
void DF_ShuiMianBianAn() {
while (!(mind_n_HuXiZhi == 0)) {
mind_n_HuXiZhi -= 2.55;
delay(80);
neoPixel_P0.setBrightness(mind_n_HuXiZhi);
yield();
}
}
// ================================================================
// 触摸键 P —— 平静模式
// 一轮 = 渐亮 → 等 1 秒 → 渐暗 → 等 1 秒;共 15 轮
// ================================================================
void pin27TouchCallback() {
for (int index = 0; index < 15; index++) {
DF_JianLiang(); // 渐亮(约 2.55 秒)
delay(1000); // 亮着保持 1 秒
DF_JianAn(); // 渐暗(约 2.55 秒)
delay(1000); // 暗着保持 1 秒
yield();
}
}
// ================================================================
// 触摸键 Y —— 睡眠模式(4-7-8 呼吸法)
// 一轮 = 渐亮 4 秒(吸气)→ 等 7 秒(憋气)→ 渐暗 8 秒(呼气)→ 等 8 秒
// 共 15 轮
// ================================================================
void pin14TouchCallback() {
for (int index = 0; index < 15; index++) {
DF_ShuiMianBianLiang(); // 4 秒缓缓变亮 —— 吸气
delay(4000); // 亮到位后再停留 4 秒
delay(7000); // 屏息 7 秒(对应数 7 个数)
DF_ShuiMianBianAn(); // 8 秒缓缓变暗 —— 呼气
delay(8000); // 暗到位后再停留 8 秒
yield();
}
}
// ================================================================
// 触摸键 O / N —— 增亮与减暗
// 每次调用在当前亮度基础上 +30 或 −30(30 步,每步间隔 5ms)
// ================================================================
void pin15TouchCallback() { // 增亮
neoPixel_P0.setBrightness(mind_n_LiangDu);
if (mind_n_LiangDu < 255) { // 未到上限才允许继续加
for (int index = 0; index < 30; index++) {
mind_n_LiangDu += 1;
delay(5);
yield();
}
}
}
void pin4TouchCallback() { // 减暗
neoPixel_P0.setBrightness(mind_n_LiangDu);
if (0 < mind_n_LiangDu) { // 未到下限才允许继续减
for (int index = 0; index < 30; index++) {
mind_n_LiangDu -= 1;
delay(5);
yield();
}
}
}
// ================================================================
// 触摸键 T —— 照明模式
// 先整条灯带置白,再按 t 的奇偶交替执行渐亮 / 渐暗
// ================================================================
void pin12TouchCallback() {
neoPixel_P0.setRangeColor(0, 24, 0xFFFFFF); // 整条灯带 → 纯白
mind_n_t += 1; // 按下次数 +1
if (((int32_t(mind_n_t)) % 2) == 0) {
DF_JianLiang(); // 偶数次:渐亮
} else {
DF_JianAn(); // 奇数次:渐暗
}
}
// ================================================================
// 触摸键 H —— 色彩控制
// i 每次 +1,用 i % 5 的余数在五色之间循环
// ================================================================
void pin13TouchCallback() {
mind_n_i += 1;
switch ((int32_t(mind_n_i)) % 5) {
case 0: // 余 0 → 橙
neoPixel_P0.clear();
neoPixel_P0.setRangeColor(0, 24, 0xFF6600);
break;
case 1: // 余 1 → 绿
neoPixel_P0.clear();
neoPixel_P0.setRangeColor(0, 24, 0x00FF00);
break;
case 2: // 余 2 → 蓝(额外补满亮度)
neoPixel_P0.clear();
neoPixel_P0.setRangeColor(0, 24, 0x0000FF);
neoPixel_P0.setBrightness(255);
break;
case 3: // 余 3 → 红
neoPixel_P0.clear();
neoPixel_P0.setRangeColor(0, 24, 0xFF0000);
break;
case 4: // 余 4 → 白
neoPixel_P0.clear();
neoPixel_P0.setRangeColor(0, 24, 0xFFFFFF);
break;
}
}
// ================================================================
// 物理键 A / B —— 只改屏幕显示,不动灯光
// ================================================================
void onButtonAPressed() {
display.setCursorLine(1); display.printLine("好梦指引灯");
display.setCursorLine(2); display.printLine("H-色彩控制");
display.setCursorLine(3); display.printLine("O-增亮");
display.setCursorLine(4); display.printLine("N-减暗");
}
void onButtonBPressed() {
display.setCursorLine(1); display.printLine("好梦指引灯");
display.setCursorLine(2); display.printLine("P-平静模式");
display.setCursorLine(3); display.printLine("Y-睡眠模式");
display.setCursorLine(4); display.printLine("T-照明模式");
}
// ================================================================
// 工具函数:把三原色分量压成一个 24 位色值(R 在高位、B 在低位)
// ================================================================
uint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b) {
return (uint32_t)((((uint32_t)r << 16) | ((uint32_t)g << 8)) | (uint32_t)b);
}源码里有三处需要向读者交代的地方,我们不打算回避:
- 渐亮渐暗两个函数体与函数名不符。程序里名为「渐暗」的函数,内部循环条件写的是「直到呼吸值 = 255」,实际执行的是加的方向;名为「渐亮」的则相反。这是积木拼装顺序调整时留下的痕迹,因为调用处与函数名的对应关系是反的,最终运行效果是正确的,所以我们保留了原样,只在这里如实提醒读者——看这段代码时要以「效果」为准,不要被函数名带偏。
- 睡眠模式的渐暗步长是三份材料里最不统一的一处。论文代码写 -2.55,工程文件(.sb3)里是 -2.5,而高清程序截图里显示的是 -0.25。三者的共同点是「渐暗都比渐亮慢」,这正是 4-7-8 的要求(呼气 8 秒长于吸气 4 秒)。本文按论文代码 -2.55 叙述,因为它与 8 秒呼气的时间预算吻合得最好。
- 睡眠模式里两条相邻的延迟(delay(4000) 紧跟 delay(7000))合起来是一段 11 秒的保持时间。这是学生把「吸气完成后的停留」与「憋气」分两步写的结果。从效果上看,4 秒渐亮 + 11 秒保持 + 8 秒渐暗,节律仍然是「慢吸慢呼」的助眠节奏,但与严格意义上的 4-7-8(吸 4、憋 7、呼 8 共 19 秒)已不完全一致。这一点我们在第九节「不足」里会再提一次。
七、作品创新点
7.1 把「呼吸计数」这件事从使用者身上卸下来
这是本作品最核心的一条创新。4-7-8 呼吸法在科普资料里随处可见,但真正去练的人很少,原因很朴素——数数需要主观意志,而失眠的人最缺的就是意志力。焦虑的时候数到 5 就忘了数到几,越数越清醒。
我们的做法是换一个感官通道:把「吸气 4 秒」变成「灯光在 4 秒内缓缓变亮」,把「憋气 7 秒」变成「灯保持最亮不动」,把「呼气 8 秒」变成「灯光在 8 秒内缓缓变暗」。使用者不需要数数、不需要计时,只要看着灯(或者闭着眼感受光的变化),身体会自然地跟着光走。这就是论文里写的那句「潜意识随着灯光而深呼吸」的具体含义。
7.2 用「同一个变量 + 不同参数」跑出三种模式
三种模式的灯光行为差别很大,但程序里并没有写三套代码,而是把亮度抽象成一个 呼吸值 变量,把「渐亮/渐暗」抽成两块自定义积木,再通过改变步长与间隔这两个参数,让同一套逻辑分别跑出「各 1 秒的平静节律」和「4-7-8 的睡眠节律」。
这个做法带来的直接好处是可维护性:后来我们想把睡眠模式的渐亮调快一点,只改了自定义积木里的一个数字,三种模式同时生效,不用逐段去改。对一个由中学生边学边写、前后改了几十遍的程序来说,这一点非常重要。
7.3 与传统的强光光疗法相比,把「治疗」降级成「辅助」
传统光疗法需要强光照射较长的时间,而且主要用于特定人群与特定时段,对高中生来说既不方便也不现实。我们的处理是把光疗法「降级」成日常可用的东西:
| 对比维度 | 传统光疗法 | 好梦指引灯 |
|---|---|---|
| 光照强度 | 强光照射 | 柔和暖光,只从缝隙与透音孔透出 |
| 使用时长 | 单次时间较长 | 一轮 19 秒,15 轮约 4 分 45 秒 |
| 使用时机 | 需专门安排时段 | 睡前躺下就能用 |
| 紫外风险 | 存在顾虑 | LED 光源,不产生紫外线,女同学不用担心皮肤问题 |
| 药物依赖 | 部分方案需配合药物 | 纯物理引导,避免褪黑素、安眠药的副作用 |
| 成本 | 专业设备价格高 | 材料成本 337 元,校园创客空间即可复制 |
| 对他人影响 | 强光外泄影响同住者 | 灯光不外泄,不影响同宿舍同学休息 |
表格最后一行是我们实测被迫加上的。最初圆形灯罩的方案就是因为灯光外泄、影响室友才被推翻的,这个教训最后变成了作品的一条硬指标。
7.4 语音播报让操作可以「闭眼完成」
第三次改版加语音模块,起因是一个很具体的场景:人在半睡状态下不想睁眼看屏幕。加入语音之后,每一次触摸都有对应的语音回应——按 Y 会听到「睡眠模式,四秒吸气,七秒憋气,八秒呼气,重复十五次」,按 O 会听到「亮度增大」。使用者全程不需要看屏幕,甚至不需要睁眼,仅凭声音就能确认自己的操作是否生效。这一点对助眠类作品来说不是锦上添花,而是必需品——毕竟这个作品的使用场景本来就是「准备睡觉」。
7.5 三种模式覆盖了从「情绪波动」到「入睡」的完整过程
很多同类作品只做一个功能。我们做的三种模式其实是三个不同的时间尺度:
- 照明模式——不涉及呼吸,解决「睡前看两眼书」的需求,时间尺度是分钟级;
- 平静模式——快节律(1 秒亮 / 1 秒灭),用于情绪失控或心理压力大时先稳住心情,时间尺度是十秒级;
- 睡眠模式——慢节律(4-7-8),用于诱导入睡,时间尺度是分钟级。
三者的关系是递进的:先用照明模式把环境安顿好,情绪不稳时用平静模式过渡,躺下后再切睡眠模式。这套「一灯多用」的设计,也是我们把它命名为「指引灯」而不是「小夜灯」的原因。
八、项目应用拓展
8.1 使用场景
| 场景 | 使用方式 | 作品提供的价值 |
|---|---|---|
| 学生宿舍睡前 | 放床头,触摸 Y 进入睡眠模式,跟着灯光做 4-7-8 呼吸 | 用外部节律代替数数,缩短入睡前的辗转时间 |
| 考试前紧张、情绪波动 | 触摸 P 进入平静模式,跟着 1 秒节律做均匀呼吸 | 先把心率与呼吸稳下来,再考虑入睡 |
| 夜间起夜 | 触摸 T 进入照明模式,或触摸 O/N 微调亮度 | 柔光不刺眼,不会把睡意打散 |
| 家庭场景 | 给有睡眠障碍的长辈使用 | 纯物理引导,不涉及药物 |
| 心理咨询辅助场景 | 作为放松训练的辅助道具 | 把抽象的「深呼吸」变成看得见的灯光节律 |
8.2 已经在讨论的改进方向
作品测试阶段,参与体验的同学提出了几条建议,加上我们自己复盘时发现的问题,整理成下面这张表。这些方向都没有在本版中实现,属于后续拓展。
| 方向 | 具体设想 | 用到的现有条件 |
|---|---|---|
| App / 蓝牙遥控 | 用手机改呼吸节律、存个人偏好 | 掌控板 2.0 板载 Wi-Fi 与蓝牙 v4.2,硬件已具备 |
| 呼吸节律自适应 | 用板载麦克风采集呼吸声,判断使用者是否跟上 | 板载麦克风 (H)EM4013BTC1R16B-T0-423 |
| 环境光自适应 | 天黑自动降低最大亮度 | 板载光敏三极管 ALS-PT19-315C |
| 姿态检测 | 用六轴传感器识别「已躺下」,自动进入待机 | 板载 QMI8658C |
| 磁吸/无线充电 | 取消 USB 接口,提升便携性 | 需增加无线充电模块(本版未采购) |
| 增加自然音 | 雨声、海浪声与灯光节律同步 | 需扩充音频源(本版只用了语音播报) |
8.3 可复制的教学价值
这个作品对我们自己来说还有一层意义:它是可以搬进课堂的。
- 技术门槛适中:主控是学生熟悉的掌控板,编程用图形化积木,不需要写代码就能跑起来;
- 知识点覆盖面广:一次项目同时用到了激光切割(结构)、3D 打印(零件)、I2C 通信(外设)、单总线驱动(灯带)、变量与循环(编程)五块内容;
- 问题来自学生自己:起点是「同学睡不着」这件真实的事,不是老师给的题目,因此学生有内驱力去反复改;
- 成本可控:337 元的采购清单,加学校已有的创客设备就能复制。
九、小结
9.1 制作历程
从 2024 年 3 月 1 日第一次小组讨论,到 4 月上旬完成拍摄归档,整个项目前后持续了一个多月,期间开了三次正式讨论会。把三次讨论的记录串起来看,作品的变化轨迹非常清楚:
| 时间 | 讨论要点 | 达成的决定 |
|---|---|---|
| 3 月 1 日 | 作品代码编写与外观设计、团队分工 | 程序采取单按键切换三个模式;认真设计外观 |
| 3 月 19 日 | 功能新增、外观设计新思路 | 睡眠模式灯光提醒不明显,加入语音提醒;利用 3D 打印技术制作外盒;新增照明模式 |
| 3 月 30 日 | 所有硬件的安装、拍摄 | 拍摄内容质量低,约定下次重拍;将外观粘合进行巩固 |
回头看,三次讨论里真正改变作品命运的是第二次:加语音、改 3D 打印外盒、加照明模式——这三条决定让作品从「一盏会呼吸的灯」变成了「一盏能用的灯」。而第三次讨论暴露的问题(拍摄质量低)也提醒我们:作品做出来只是完成了一半,把它讲清楚同样是工作的一部分。
作品完成后,我们在组内与班级同学之间做了一轮体验测试。反馈比较集中的几点是:屏幕显示清晰、模式切换直观、触摸区反应灵敏、操作简单易懂,「无需复杂的操作步骤」是被提到最多的一句评价。也有同学提出希望增加 App 或蓝牙控制,这一条我们列进了第八节的改进方向。
对我们三个人来说,这个过程最大的收获其实不在作品本身。PPT 里我们写了一段反思,大意是:在制作过程中对 Mind+ 和掌控板的应用不熟悉,有很多生疏之处;代码编写时间线拉得太长,运行和调试花了很多时间才完善;但在这个过程中收获很多,也变得耐心很多。也正因为亲手改过几十遍代码,才真正理解「创新,是一个民族进步的灵魂」这句话背后的含义。
9.2 不足之处
下面这几条是我们在复盘中自己找出来的问题,如实列出:
- 睡眠模式的节律与标准 4-7-8 有偏差。代码里渐亮 4 秒之后连着两段延迟(4 秒 + 7 秒),实际保持时间达到 11 秒,一轮总时长约 23 秒,而不是 4-7-8 标准的 19 秒。原因是把「吸气后的停留」与「憋气」分成了两步写。严格来说应该把中间那段合并成一个 7 秒的憋气段。
- 渐暗步长在三份材料里不统一。论文代码是 −2.55、工程文件是 −2.5、程序截图是 −0.25。虽然三者都保证了「渐暗慢于渐亮」,但数值不一致说明我们在改版过程中没有做好版本管理,最终交付时程序状态与论文描述存在小的出入。
- 渐亮渐暗两个函数的命名与实际行为相反。程序能正常运行,但代码可读性差,如果有同学想要在此基础上修改,很容易被函数名误导。
- 灯光不外泄只是「减轻」而非「消除」。图 4-6 里的实拍可以看出,照明模式下前面板会整体泛光,在完全黑暗的宿舍里仍有可见亮度。如果能给灯带加一层扩散膜,或把灯带下移到箱体底部朝上打光,效果会更好。
- 锂电池未标型号与容量,因此无法给出续航时间的量化数据。这是材料清单本身的欠缺,我们在正文中如实注明而没有补算。
- 亮度调节是「步进式」而非「无级」。每按一次 O 或 N 变化 30 级(30 步 × 1 级),在 0~255 的范围内大约需要按 9 次才能走完全程。虽然够用,但想要精细调节时手感偏粗。
9.3 团队分工
| 成员 | 角色 | 承担工作 |
|---|---|---|
| 杨雅钧 | 队长 | 作品主要编程;提出作品创新思路 |
| 孙子轩 | 队员 | 作品创意提出者;负责答辩论文与 PPT;指导编程创作与工作分配 |
| 苏紫莹 | 队员 | 文书查阅资料;收集并分析汇总;辅助完善编程 |
除了上面三项分工,团队还在三次讨论会中逐条记录了「下一步工作计划」并明确了责任人与时间节点,例如:杨雅钧负责「运用编程软件将想法编入掌控板」、孙子轩负责「编写作品论文和幻灯片」、苏紫莹负责「学习相关切换模式的编程内容」。这种把任务落到人和日期上的做法,是我们这个项目能在一个多月内推进到位的重要原因。



