基于 Hi3861 的 PWM 与彩灯综合实践指南

------蜂鸣器发声、音量、音乐 · 交通灯板 · 炫彩灯板 RGB 混色

配套教材:《OpenHarmony 轻量设备开发》第5章 控制I/O设备 5.3 PWM输出方波(1~4)

适用平台:润和满天星系列 Pegasus 智能家居开发套件(底板 + Hi3861核心板 + 交通灯板/炫彩灯板)

使用说明

本指南面向零基础学生,覆盖"原理讲解 → 动手实践 → 小作业"完整闭环,教师可直接对照本指南组织课堂,学生可照此文档独立完成实验。全文分为四大板块:

  • 知识精讲:PWM 原理、HAL/SDK 双层 API、颜色模型、视觉暂留原理
  • 五个递进式实验:蜂鸣器发声 → 音量控制 → 音乐播放 → 交通灯综合演示 → RGB 混色调光
  • 每个实验后配套小作业,用于课后巩固或考核
  • 结尾附养老场景应用分析,帮助理解"为什么学这些底层技术"

💡 本指南中的示例代码是按教材给出的目录结构、API与引脚参数整理的参考实现思路,用于讲解编程逻辑;实际以课程配套工程源码为准。

一、学习目标与知识地图

1.1 学完本单元你将能够

  • 说清楚 PWM 是什么、为什么用数字信号能控制模拟效果(面积等效原理)
  • 分清占空比和频率各自控制什么效果(亮度/音量 vs 平滑度/音调)
  • 理解 OpenHarmony 的 HAL 标准接口和海思 SDK 底层接口的分层关系,知道该用哪一层写代码
  • 独立完成:蜂鸣器发声、音量控制、简谱转代码播放音乐、交通灯按键联动、RGB三色灯平滑混色 五个实验
  • 理解 RGB 颜色模型和视觉暂留原理,能设计"平滑调光"效果
  • 能举例说明这些技术如何迁移到真实的智能养老产品场景

1.2 知识地图(建议课堂讲授顺序)

顺序 模块 对应实验 建议时长
1 PWM 基本原理(面积等效、占空比、频率) --- 20 分钟
2 HAL API / 海思SDK API 介绍与对比 --- 15 分钟
3 交通灯板蜂鸣器介绍 + 实验一:控制蜂鸣器发声 pwm_buz.c 25 分钟
4 实验二:控制蜂鸣器音量(占空比应用) pwm_volume.c 20 分钟
5 简谱转程序原理 + 实验三:控制蜂鸣器播放音乐 pwm_music.c 35 分钟
6 交通灯板三色灯 / 按键介绍 + 实验四:交通灯综合演示 traffic_light.c 35 分钟
7 颜色模型(RGB/HSB/CMYK)+ 炫彩灯板三色灯介绍 --- 20 分钟
8 视觉暂留原理 + 平滑调光三原则 --- 15 分钟
9 实验五:控制三色灯亮度(RGB混色) pwm_led.c 30 分钟
10 总结 + 养老场景应用讨论 --- 15 分钟

二、硬件与开发环境准备

2.1 硬件清单

  • 润和满天星(HiHope)Pegasus 智能家居开发套件:底板 + Hi3861 核心板
  • 交通灯板(红/黄/绿三色 LED + 按键 + 无源蜂鸣器)------ 用于实验一~四
  • 炫彩灯板(RGB 三色 LED)------ 用于实验五
  • USB 数据线(供电+烧录)、PC(Windows,已装好 HDC/烧录工具与 OpenHarmony 编译环境)

2.2 交通灯板硬件引脚对照表

器件 标记 连接引脚 复用功能 说明
红灯 D1 GPIO-10 --- 高电平点亮
黄灯 D2 GPIO-12 --- 高电平点亮
绿灯 D3 GPIO-11 --- 高电平点亮
按键 S1 GPIO-08 --- 按下低电平,抬起悬空(需上拉为高电平以区分状态)
蜂鸣器(无源) B1 27号引脚 GPIO-09 / PWM0 内部无震荡源,需方波驱动,频率可控(决定音调)

💡 交通灯板的三色 LED 是直接 GPIO 高低电平控制(只有"亮/灭"两态),并不经过 PWM;只有蜂鸣器走 PWM。这与炫彩灯板的三色 LED(走 PWM 调光)是不同的驱动方式,务必在课堂上讲清楚,避免学生混淆。

2.3 炫彩灯板硬件引脚对照表

颜色 引脚 复用功能
28号引脚 GPIO-10 / PWM1
绿 29号引脚 GPIO-11 / PWM2
30号引脚 GPIO-12 / PWM3

三色 LED 标记为 D4,内部封装红绿蓝三颗独立 LED,通过分别控制三路 PWM 占空比(即三色各自的亮度)实现混色,理论上可呈现任意可见色彩。

三、知识精讲:PWM 基本原理

3.1 为什么用数字信号控制模拟效果

PWM(Pulse Width Modulation,脉冲宽度调制)是利用微处理器的数字输出去控制模拟电路的一种技术。原因很直接:模拟电路看似简单,但不经济------存在漂移、发热、对噪声敏感等问题;而数字电路成本低、功耗低、易实现,所以工程上更愿意"用数字的方式,做出模拟的效果"。

3.2 面积等效原理(重点)

这是 PWM 技术的核心理论:冲量相等而形状不同的窄脉冲,加在具有惯性的环节上时,效果基本相同。这里"冲量"就是窄脉冲的面积,"效果相同"指的是这个环节的输出波形基本相同。

"惯性环节"是什么意思?当输入量发生突变时,输出量不会跟着突变,只能按指数规律逐渐变化------比如灯泡从灭到亮总有个渐变过程。惯性环节通常包含一个储能元件和一个耗能元件。正因为电路"来不及"对每一个脉冲做出瞬时反应,所以哪怕输入的是一串方波(通/断),只要脉冲的"面积"(能量)相同,最终表现出来的平均效果就是相同的------这就是为什么可以用开关量(数字)模拟出连续变化的模拟量。

3.3 占空比:决定"强度"

以电池+开关+LED电路为例:开关控制 LED 亮一秒、灭一秒,一个周期(完成一次"亮+灭"循环的总时间)内,LED 有 50% 的时间亮、50% 的时间灭。"亮"的时间占周期的比值,就叫占空比(Duty Ratio)。

  • 占空比越大 → 输出的平均电压越大 → LED 越亮 / 蜂鸣器音量越大
  • 占空比越小 → 输出的平均电压越小 → LED 越暗 / 蜂鸣器音量越小

💡 重点记忆:LED 的亮度(光量)与频率无关,只与占空比成正比!蜂鸣器的音量同理。

3.4 频率:决定"平滑度 / 音调"

控制电路的频率范围受电路响应时长限制:频率太低,LED 会明显闪烁(人眼能察觉"亮灭"的间隙);频率太高,电感类负载可能饱和。频率合理且较高时(如 1kHz~200kHz 量级),得到的模拟输出会近似平滑连续。

  • 对 LED:频率决定"闪不闪",占空比决定"亮不亮"
  • 对蜂鸣器:频率决定"音调(音符)",占空比决定"音量"

3.5 小结

PWM 有两个关键参数:频率越高,模拟效果越好(越平滑);占空比越大,模拟出的"电压/强度"越大。这两点是贯穿本单元所有实验的核心逻辑,请务必让学生复述一遍再进入实验环节。

3.6 PWM 的典型应用场景

蜂鸣器驱动、电机驱动、逆变电路、加湿器雾化量控制、变速风扇控制器、混合动力/电动汽车电机驱动电路、LED 调光器等------凡是需要"用数字信号模拟出连续变化的物理量"的场景,几乎都能看到 PWM 的身影。

3.7 Hi3861 芯片 PWM 引脚分布

引脚编号 默认功能 复用信号
2 GPIO-00 PWM3_OUT
3 GPIO-01 PWM4_OUT
4 GPIO-02 PWM2_OUT
5 GPIO-03 PWM5_OUT
6 GPIO-04 PWM1_OUT
17 GPIO-05 PWM2_OUT
18 GPIO-06 PWM3_OUT
19 GPIO-07 PWM0_OUT
20 GPIO-08 PWM1_OUT
27 GPIO-09 PWM0_OUT
28 GPIO-10 PWM1_OUT
29 GPIO-11 PWM2_OUT
30 GPIO-12 PWM3_OUT
31 GPIO-13 PWM4_OUT
32 GPIO-14 PWM5_OUT

四、知识精讲:HAL API 与海思 SDK API

4.1 两层接口的关系(不是平行关系)

OpenHarmony 的分层设计是:应用层代码 → HAL 标准接口(iot_pwm.h)→ 芯片厂商 SDK 实现(hi_io.h)→ 硬件寄存器。HAL 是"厂商中立"的标准抽象,换芯片时业务代码基本不用改;SDK 是海思针对 Hi3861 的具体实现。

4.2 HAL API 列表

接口位置:base\iot_hardware\peripheral\interfaces\kits\iot_pwm.h

API 名称 说明
unsigned int IoTPwmInit(unsigned int port) PWM 模块初始化,port 指定 PWM 端口号
unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq) 开始输出 PWM 信号。duty 为占空比(1~99),freq 为实际频率(≥2442Hz)
unsigned int IoTPwmStop(unsigned int port) 停止输出 PWM 信号
unsigned int IoTPwmDeinit(unsigned int port) 解除 PWM 模块初始化

4.3 海思 SDK API 列表

接口位置:device\hisilicon\hispark_pegasus\sdk_liteos\include\hi_io.h

API 名称 说明
hi_u32 hi_pwm_set_clock(hi_pwm_clk_source clk_type) 设置 PWM 时钟类型(对所有PWM模块生效):内部160MHz时钟(默认)或外部40M时钟
hi_u32 hi_pwm_start(hi_pwm_port port, hi_u16 duty, hi_u16 freq) 开始输出 PWM 信号。duty 为占空比原始值(1~65535),freq 为分频倍数(1~65535)
hi_u32 hi_pwm_stop(hi_pwm_port port) 停止输出 PWM 信号

4.4 关键区别:参数含义完全不同

HAL :IoTPwmStart(port, duty, freq) SDK :hi_pwm_start(port, duty, freq)
duty 取值 1~99(直接就是百分比占空比) 1~65535(寄存器原始值,需要换算)
freq 含义 ≥2442(直接就是目标频率 Hz) 1~65535(时钟的分频倍数,不是Hz)

这说明 HAL 层在内部帮你做了"百分比 → 占空比寄存器值""目标频率 → 分频系数"的换算,再去调用 hi_pwm_start。二者不是"调用任意一个都行"的平行接口,而是 HAL 对 SDK 的封装转换。

💡 教学与实践建议:写业务代码统一使用 IoTPwmXxx(HAL层),这是官方推荐做法,也符合"厂商中立、可移植"的产品架构思路。只有做底层驱动移植/调试寄存器细节时才直接用 hi_pwm_xxx。定位封装实现可用 ripgrep:rg "hi_pwm_start" --type c -l

五、实验一:控制蜂鸣器发声

5.1 硬件介绍:交通灯板蜂鸣器

蜂鸣器标记为 B1,用于发声,连接到 Hi3861 芯片的 27 号引脚(复用为 GPIO-09 / PWM0)。特性参考:输出频率 2700Hz 时,10cm 处声音输出可大于 80dB(占空比50%);工作温度 -20℃~70℃。

5.2 实验目标

  • 使用 PWM 模块的相关 API,控制交通灯板的蜂鸣器发声
  • 理解 PWM 的基本原理
  • 准备开发套件:底板 + 核心板 + 交通灯板

5.3 操作步骤

  1. 建立目录:applications\sample\wifi-iot\app\pwm_demo
  2. 编写源码 pwm_buz.c 与编译脚本 BUILD.gn(并在上级 app\BUILD.gn 中登记新目录)
  3. 编译产品
  4. 烧录固件
  5. 运行观察现象

5.4 常见报错与排查(重点:让学生记录到笔记)

编译过程中如果出现 undefined reference to hi_pwm_* ,原因是默认情况下海思 SDK 没有开启 PWM 支持。

解决方案:修改 device\hisilicon\hispark_pegasus\sdk_liteos\build\config\usr_config.mk 文件,把

CONFIG_PWM_SUPPORT is not set

修改为:

CONFIG_PWM_SUPPORT=y

5.5 参考实现思路(基于 HAL API)

#include "iot_pwm.h"

#include "iot_gpio.h"

#define BUZZER_PWM_PORT 0 // 27号引脚复用 PWM0

void BuzzerDemoTask(void)

{

IoTPwmInit(BUZZER_PWM_PORT);

// duty: 占空比(1-99),freq: 实际频率(>=2442Hz)

IoTPwmStart(BUZZER_PWM_PORT, 50, 2700); // 参考手册特性:2700Hz、50%占空比

// ... 延时一段时间后关闭 ...

IoTPwmStop(BUZZER_PWM_PORT);

IoTPwmDeinit(BUZZER_PWM_PORT);

}

5.6 小作业

  1. 📝 画出本实验的调用流程图:IoTPwmInit → IoTPwmStart → 延时 → IoTPwmStop → IoTPwmDeinit,并标注每一步在做什么。
  2. 📝 尝试把频率改成 500Hz 和 5000Hz 分别听声音有什么变化,写下你的听感描述,并解释这与 PWM 原理的关系。
  3. 📝 如果不调用 IoTPwmStop 直接调用 IoTPwmDeinit,会发生什么?请查阅资料或实测后说明原因。

六、实验二:控制蜂鸣器音量

6.1 原理回顾

占空比可以改变输出电压大小,占空比越大,模拟出的电压越大。蜂鸣器的音量与频率无关,与占空比成正比------这是本实验唯一需要牢记的知识点。

6.2 实验目标

  • 使用 PWM 模块的相关 API,控制交通灯板蜂鸣器的音量
  • 理解占空比的原理
  • 准备开发套件:底板 + 核心板 + 交通灯板

6.3 操作步骤

  1. 建立目录:applications\sample\wifi-iot\app\pwm_demo
  2. 编写源码 pwm_volume.c 与编译脚本 BUILD.gn
  3. 编译产品
  4. 烧录固件
  5. 运行观察现象

6.4 参考实现思路

// 保持频率不变,只改变占空比,观察音量变化

unsigned short dutyList\[\] = {10, 30, 50, 70, 90};

for (int i = 0; i < 5; i++) {

IoTPwmStart(BUZZER_PWM_PORT, dutyListi, 2700);

// 延时一段时间,让耳朵能分辨出音量差异

}

6.5 小作业

  1. 📝 设计一个"音量从小到大再到小"的呼吸式提示音效果(占空比渐变),写出你的占空比数组和切换间隔。
  2. 📝 思考题:为什么占空比只影响音量而不影响音调?结合"面积等效原理"用自己的话解释。

七、实验三:控制蜂鸣器播放音乐

7.1 准备工作一:认识无源蜂鸣器

交通灯板上使用的是无源蜂鸣器:内部不带震荡源,需要外部方波驱动,且频率(音调)可控------这正是它能"演奏音乐"而不只是"嘀嘀响"的原因(有源蜂鸣器通电就响固定音调,不能变调)。

7.2 准备工作二:音符与频率、分频倍数的对应关系

PWM 的时钟源频率为 40MHz。分频倍数 = 时钟源频率 ÷ 目标音符频率(这是 SDK 层 hi_pwm_start 的 freq 参数,若用 HAL 层 IoTPwmStart 则直接填目标频率 Hz 即可,无需自己换算分频倍数)。

音符 频率(Hz) 分频倍数
C6(do) high C 1046.5 38223
D6(re) 1174.7 34052
E6(mi) 1318.5 30338
F6(fa) 1396.9 28635
G6(so) 1568 25511
A6(la) 1760 22728
B6(si) 1975.5 20249
G5(so) 低八度 784 51020

7.3 准备工作三:读懂简谱《两只老虎》

  • 左上角"1=C"是正调:常规对应关系为 1-C、2-D、3-E、4-F、5-G、6-A、7-B
  • 左上角"4/4"是四四拍:四分音符为一拍,每小节四拍
  • 谱子上的竖线是小节分隔符,与 4/4 拍对应
  • 数字后面的一条横线表示延时一拍
  • 数字后面的一个点表示顺延半拍
  • 数字下方一条下划线表示二分之一时值,两条下划线表示四分之一时值

💡 这一段是本实验的"难点",建议课堂上现场哼唱《两只老虎》并对照简谱指出每个符号,学生更容易建立"乐谱符号 ↔ 时间长度"的直觉。

7.4 把曲谱"翻译"成程序:两个数组

思路:先建一张"音符编号 → 分频倍数(或频率)"的查表数组,再把简谱上的音符按发音顺序记录成"编号数组",最后单独记录每个音符对应的"时值(拍数)数组"。三者下标一一对应,程序按顺序查表播放即可。

// 分频倍数表(数组下标与简谱数字对应,低八度单独处理)

static const uint16_t g_tuneFreqs\[\] = {

0, // 不使用

38223, // 1046.5Hz C6(do)

34052, // 1174.7Hz D6(re)

30338, // 1318.5Hz E6(mi)

28635, // 1396.9Hz F6(fa)

25511, // 1568Hz G6(so)

22728, // 1760Hz A6(la)

20249, // 1975.5Hz B6(si)

51020 // 784Hz G5(so) 低八度

};

// 曲谱音符序列(与简谱数字基本一致,8表示低八度G5)

static const uint8_t g_scoreNotes\[\] = {

1, 2, 3, 1, 1, 2, 3, 1, 3, 4, 5, 3, 4, 5,

5, 6, 5, 4, 3, 1, 5, 6, 5, 4, 3, 1, 1, 8, 1, 1, 8, 1,

};

// 曲谱时值序列:4=一拍,8=半拍,3+1=附点(顺延半拍)拆分表示等,按简谱记谱转写

static const uint8_t g_scoreDurations\[\] = {

4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 8,

3, 1, 3, 1, 4, 4, 3, 1, 3, 1, 4, 4, 4, 4, 8, 4, 4, 8,

};

7.5 实验目标

  • 使用 PWM 模块的相关 API,灵活控制交通灯板蜂鸣器的音调
  • 理解将乐曲"电子化"的过程
  • 准备开发套件:底板 + 核心板 + 交通灯板

7.6 操作步骤

  1. 建立目录:applications\sample\wifi-iot\app\pwm_demo
  2. 编写源码 pwm_music.c 与编译脚本 BUILD.gn
  3. 编译产品
  4. 烧录固件
  5. 运行,听《两只老虎》是否正确播放

7.7 参考实现思路(播放主循环)

#define NOTE_COUNT (sizeof(g_scoreNotes) / sizeof(g_scoreNotes0))

#define BEAT_MS 300 // 一拍的基准时长,可自行调整曲速

for (int i = 0; i < NOTE_COUNT; i++) {

uint8_t note = g_scoreNotesi;

uint32_t freqHz = /* 用HAL层:把 g_tuneFreqs 换算成实际 Hz 后传入 */;

IoTPwmStart(BUZZER_PWM_PORT, 50, freqHz);

// 时值换算成延时:g_scoreDurationsi 对应的拍数 * BEAT_MS

IoTPwmStop(BUZZER_PWM_PORT); // 音符间短暂停顿,听感更清晰

}

7.8 小作业

  1. 📝 自选一首简单儿歌(如《小星星》),按本节方法画出简谱→数组的转换过程(不要求编程,先手工列出音符数组和时值数组)。
  2. 📝 编程实现你选的曲子,并在课堂上播放展示。
  3. 📝 思考题:如果想让整首曲子播放得更快或更慢,应该改哪个变量?为什么不需要改 g_tuneFreqs?

八、交通灯板的三色灯与按键介绍

8.1 三色 LED(直接 GPIO 控制,非PWM)

颜色 标记 引脚 点亮方式
红灯 D1 GPIO-10 高电平点亮
黄灯 D2 GPIO-12 高电平点亮
绿灯 D3 GPIO-11 高电平点亮

8.2 按键 S1

  • 标记为 S1,用于用户输入,连接到 Hi3861 芯片的 GPIO-08 引脚
  • 按下:GPIO-08 引脚处于低电平状态
  • 抬起:GPIO-08 引脚悬空

💡 注意:引脚电平应上拉为高电平,才能可靠区分"按下(低)"与"抬起(悬空但视为高)"两种状态,否则悬空引脚电平不确定,容易误触发。

九、实验四:交通灯综合演示(GPIO + 按键 + PWM)

9.1 实验目标

  • 综合运用 GPIO 输出电平、GPIO 按键输入、PWM 输出方波等知识
  • 实现按键切灯、蜂鸣器发声等效果
  • 准备开发套件:底板 + 核心板 + 交通灯板

9.2 操作步骤

  1. 建立目录:applications\sample\wifi-iot\app\pwm_demo
  2. 编写源码 traffic_light.c 与编译脚本 BUILD.gn
  3. 编译产品
  4. 烧录固件
  5. 运行,用按键测试交互效果

9.3 扩展练习(课堂拔高 / 也可作为大作业)

目标:实现更接近真实场景的交通灯功能。

  • 红灯、绿灯的保持(各持续固定时长)
  • 红→绿切换
  • 绿→红切换(中间插入黄灯闪烁过渡,更符合真实路口逻辑)
  • 红灯、绿灯状态结束时,蜂鸣器给出提醒音
  • 点击按键可以立即结束当前的红灯或绿灯状态(模拟"行人请求"或人工干预)

9.4 小作业

  1. 📝 画出交通灯的状态机图(红→黄闪→绿→红...),标出每个状态的触发条件(时间到 / 按键按下)和输出动作(哪个灯亮、是否鸣响)。
  2. 📝 在你的状态机基础上,实现"黄灯闪烁过渡"效果,并说明闪烁频率你是怎么用延时或PWM实现的。
  3. 📝 (选做/思考题)如果要给这套系统加上"行人过街按钮优先放行"的逻辑,你会怎么设计状态转移?

十、颜色模型与炫彩灯板 RGB 原理

10.1 三种常见颜色模型

模型 全称/维度 主要用途
HSB 色相 Hue、饱和度 Saturation、亮度 Brightness 图像和视频调色、UI设计
RGB 红 Red、绿 Green、蓝 Blue(加色) 发光领域:显示器、灯光
CMYK 青 Cyan、洋红 Magenta、黄 Yellow、黑 Key 减光领域:印刷

10.2 RGB 模型详解

绝大多数可见光可用红、绿、蓝三色光的不同强度混合来表示。R/G/B 每个通道取值范围 0~255:黑色(0,0,0),白色(255,255,255),红(255,0,0)、绿(0,255,0)、蓝(0,0,255)。可表示颜色数为 256×256×256 = 16,777,216 色。

10.3 炫彩灯板三色灯介绍

三色 LED 标记为 D4,内部封装红绿蓝三颗独立 LED,与 Hi3861 引脚对应关系见第二章表格(红28/GPIO-10/PWM1,绿29/GPIO-11/PWM2,蓝30/GPIO-12/PWM3)。可编程控制每个灯的状态和亮度,实现 RGB 混色。

10.4 三色灯发色原理与发色数量对比(重点)

炫彩灯板的三色 LED 使用 RGB 模型:通过改变 PWM 输出的占空比,分别控制 RGB 三个 LED 的亮度,实现混色。

调用方式 占空比取值范围 可分级数 理论发色数量
HAL API(IoTPwmStart) 1~99 99 级 99×99×99 = 970,299 色
海思 SDK API(hi_pwm_start) 1~65535 可分为256级 256×256×256 = 16,777,216 色

💡 这是一个很好的"HAL便利性 vs SDK精细度"权衡案例:日常教学和大多数场景用 HAL 的99级足够;如果要做专业级调色(比如仿真真实照明产品),可以考虑直接用 SDK 层获得256级精度。

10.5 发光单元排列注意事项

  • 三色灯可以当作一个"大像素点"看待
  • 排列方式:蓝上、红左、绿下
  • 不要近距离观察:距离越近,发色效果越差;峰值亮度太高,伤眼

十一、平滑调光的理论基础:视觉暂留

11.1 什么是视觉暂留

视觉暂留(Persistence of vision)由伦敦大学教授皮特于1824年最先提出:人眼观察景物时,光信号传入大脑神经需要一段短暂时间;光的作用结束后,视觉形象不会立即消失------物体映像会在视网膜上保留约0.1~0.4秒,这种残留视觉称为"后像"。利用这一现象,将一系列变化很小的图像以足够快的速度连续播放,就会产生连续活动的场景(190年前的手翻动画即是此原理的早期应用)。

11.2 解剖学原理(选讲,供有兴趣的学生拓展)

可参考犹他大学教材《网络视觉------视网膜和视觉系统的组织》(webvision.med.utah.edu)了解光的传导路线,以及视网膜感光感色(对应RGB模型)与反应速度(对应视觉暂留)的生理基础。

11.3 平滑调光三原则(重点,实验五的设计依据)

  1. PWM 输出的频率足够高
  2. 两次发色(发光)间隔时间足够短
  3. 色彩值变化的梯度足够平滑,避免颜色大幅跳跃

这三条原则本质上都是在利用"视觉暂留"这个生理特性:只要变化足够快、足够细腻,人眼就会把一连串离散的颜色状态感知成连续渐变的效果。

十二、实验五:控制三色灯亮度(RGB 混色平滑调光)

12.1 实验目标

  • 理解 RGB 颜色模型、三色灯发色原理
  • 掌握平滑调光的方法,实现炫彩灯光效果
  • 准备开发套件:底板 + 核心板 + 炫彩灯板

12.2 操作步骤

  1. 建立目录:applications\sample\wifi-iot\app\pwm_demo
  2. 编写源码 pwm_led.c 与编译脚本 BUILD.gn
  3. 编译产品
  4. 烧录固件
  5. 运行,观察渐变混色效果

12.3 参考实现思路

#define RED_PORT 1 // PWM1

#define GREEN_PORT 2 // PWM2

#define BLUE_PORT 3 // PWM3

#define PWM_FREQ 20000 // 频率足够高,满足调光三原则第1条

void SetColor(uint16_t r, uint16_t g, uint16_t b)

{

// r/g/b 建议先按 0-255 设计接口,再线性映射到 duty(1-99)

IoTPwmStart(RED_PORT, MapTo99(r), PWM_FREQ);

IoTPwmStart(GREEN_PORT, MapTo99(g), PWM_FREQ);

IoTPwmStart(BLUE_PORT, MapTo99(b), PWM_FREQ);

}

// 渐变示例:从红色过渡到蓝色

for (int step = 0; step <= 100; step++) {

uint16_t r = 255 - (255 * step / 100);

uint16_t b = 255 * step / 100;

SetColor(r, 0, b);

// 短延时(满足调光三原则第2条:间隔时间足够短)

}

💡 渐变步长设置得越细(比如从100步改成500步),每一步的颜色跳跃就越小,越符合"梯度平滑"的第3条原则,视觉效果也越顺滑。

12.4 小作业

  1. 📝 实现一个"红→绿→蓝→红"循环渐变的呼吸灯效果,并说明你的渐变步数和延时是如何选取的。
  2. 📝 对比:把渐变步长从100改成10,观察并描述画面观感上的差别,用"视觉暂留三原则"解释原因。
  3. 📝 (选做)分别用 HAL API(99级)和查阅资料尝试用 SDK API(256级)实现同一个渐变效果,比较两者的色彩细腻程度。

十三、课堂讲授建议

13.1 重点与难点提示(对照教材SUMMARY页整理)

单元 重点 难点
PWM原理 占空比↔强度,频率↔平滑度/音调 的对应关系 面积等效原理、惯性环节的抽象概念
HAL/SDK API 参数含义与取值范围完全不同,需要换算 分频倍数的计算(时钟源/目标频率)
蜂鸣器发声 PWM四步调用流程 CONFIG_PWM_SUPPORT编译报错排查
蜂鸣器音乐 简谱→数组的转译方法 简谱符号(横线/点/下划线)的含义
交通灯综合 GPIO输出+按键输入+PWM三者协同 状态机设计、黄灯过渡逻辑
RGB混色 三色独立PWM占空比叠加成色彩 平滑调光三原则的工程落地

13.2 课堂演示小技巧

  • 讲蜂鸣器音量前,先用同一频率、不同占空比现场对比播放,让学生"听"出差异,比讲公式更直观
  • 讲简谱转代码时,现场哼唱《两只老虎》并逐句对照数组,帮助学生建立"乐谱→数字"的直觉映射
  • 讲HAL/SDK参数区别时,把两张表格并排投影对比,突出duty和freq取值范围的数量级差异
  • 讲视觉暂留时,可现场用手机相机慢动作拍摄LED渐变,回放给学生看PWM本质上是"通断闪烁"而非真实的连续调光

13.3 常见学生疑问预判

  • "为什么占空比和亮度成正比,跟频率没关系?" → 回到面积等效原理:频率只影响"闪烁是否可见",占空比才是决定平均能量(面积)大小的参数
  • "HAL的duty是1-99,SDK是1-65535,是不是精度损失了?" → 是的,HAL为了简单易用牺牲了部分精度(99级 vs 256级),这是工程上"易用性 vs 精细度"的典型取舍,可引申到产品设计讨论
  • "为什么交通灯板三色灯不用PWM,炫彩灯板要用?" → 交通灯板只需要"亮/灭"两态模拟真实红绿灯,用GPIO足够;炫彩灯板需要连续调光混色,必须用PWM

十四、课后小作业清单汇总

以下为全部小作业的汇总列表,教师可按需删减布置,学生可用作自查清单:

  1. 实验一:画出蜂鸣器发声调用流程图;对比不同频率的听感;分析漏调 IoTPwmStop 的后果
  2. 实验二:设计一个音量渐变提示音;解释占空比只影响音量不影响音调的原因
  3. 实验三:手工完成一首儿歌的简谱转数组;编程实现并课堂展示;说明播放速度如何调节
  4. 实验四:画交通灯状态机图;实现黄灯闪烁过渡;(选做)设计行人优先逻辑
  5. 实验五:实现RGB循环呼吸灯;对比不同渐变步长的效果差异;(选做)对比HAL与SDK两种精度

十五、养老场景应用分析

本单元用到的硬件能力------按键输入、GPIO开关量控制、PWM驱动蜂鸣器(音调+音量可控)、PWM驱动RGB彩灯(平滑调光混色)------恰好对应智能养老/居家看护场景里几类最基础也最刚需的交互方式:声音提醒、灯光提示、一键呼叫。下面逐条展开,并在最后给出一张硬件能力→养老功能的映射表,便于直接迁移为教学案例或产品原型。

15.1 一键紧急呼叫(对应:按键 + 蜂鸣器 + RGB灯)

交通灯板的按键 S1 可直接复用为"紧急呼叫按钮":老人一键按下后,本地立即触发蜂鸣器高占空比报警音(响亮、不依赖网络,保证低延迟),同时 RGB 灯切换为红色持续闪烁,方便护理人员从房间外或走廊远处一眼看到求助信号。这正是实验四"按键触发状态切换+蜂鸣器提醒"的直接迁移。

15.2 服药 / 作息提醒(对应:PWM音乐 + RGB渐变)

很多老人存在听力衰退,单一"嘀嘀"声容易被忽略或与其他家电报警声混淆。实验三"简谱转程序"的能力可以用来给不同事件编写不同的提示旋律(吃药、喝水、来访客各一段短曲),配合实验五的RGB渐变(如吃药提醒用柔和的黄色呼吸灯),形成"声音+灯光"双通道提示,对听力/视力单一衰退的老人都更友好。

15.3 夜间起夜照明引导(对应:PWM平滑调光)

直接用 GPIO 通断点灯(像交通灯板那样)对老人夜间视觉是一种刺激------瞳孔在黑暗中放大,突然的强光容易致眩晕甚至增加跌倒风险。实验五掌握的"平滑调光三原则"正好可以用来设计一盏智能夜灯:检测到人体活动或按键触发后,亮度从0缓慢渐变到设定值(而不是瞬间点亮),路径照明更安全。

15.4 状态指示灯(对应:RGB语义化编码)

可以用 RGB 灯的颜色给护理人员/家属传递"看护状态"的语义信息,类似产品化的状态指示器:绿色=一切正常,黄色=需要关注(如长时间无活动),红色=异常/已呼叫。这个思路可以直接把实验四"交通灯状态机"的编程模式(红/黄/绿三态+触发条件)重新包装成"看护状态机"教学案例------学生更容易理解"为什么要学这些底层控制",因为它对应了真实产品需求。

15.5 渐强/分级提示音(对应:PWM音量控制)

实验二训练的"占空比控制音量"能力,可以用来设计从轻柔到响亮逐渐增强的提醒音,避免第一声就把老人吓到,又能保证若无响应则声音持续增强直到被注意到------这是很多商用适老化设备(如紧急呼叫器)实际采用的策略。

15.6 与 MQTT / Home Assistant 联动(本地优先 + 云端联动)

结合你正在做的 eldercare 监控场景(MQTT 接入 Home Assistant):可以让按键、蜂鸣器、RGB灯承担"本地边缘响应"的角色------例如跌倒检测传感器触发时,板子本地立即声光报警(不依赖网络、延迟最低),同时通过 MQTT 把事件上报云端/Home Assistant,触发家属手机推送。这种"本地优先 + 云端联动"的双保险架构,是工业物联网里很常见的边缘计算设计思路,也很适合放进你现有的四层测试框架,作为一个贴近真实产品的综合案例。

15.8 硬件能力 → 养老应用映射表

硬件能力(本单元实验) 养老场景功能 关键设计点
按键输入(实验四) 一键紧急呼叫 低延迟本地触发,避免依赖网络
PWM驱动蜂鸣器-音调(实验三) 差异化事件提示音(吃药/来访/求助) 不同事件用不同旋律,降低认知负担
PWM驱动蜂鸣器-音量(实验二) 渐强提醒音 从轻到响,兼顾听力好坏不同的老人
PWM驱动RGB-平滑调光(实验五) 夜间起夜安全照明 亮度渐变,避免强光刺激瞳孔致跌倒
RGB颜色语义化 看护状态指示(正常/关注/求助) 颜色编码简单直观,远距离可辨识
GPIO+按键+PWM综合状态机(实验四) 本地边缘报警 + MQTT云端联动 本地优先响应,云端负责家属通知

附:结语

从"PWM控制一个蜂鸣器发声"到"按键联动交通灯"再到"RGB平滑混色",这条实验路径本质上是在训练同一种能力:用最基础的数字信号(开关、占空比、频率)去逼近连续、自然的物理效果。这也正是嵌入式/IoT开发的核心思维方式------理解这一点,学生不仅能做完这五个实验,也能在遇到新硬件、新场景(比如养老看护)时,快速类比迁移已有知识,独立设计解决方案。

相关推荐
To_OC1 小时前
别再被跑分骗了:大模型 Benchmark 到底在考什么?
人工智能·llm·agent
qyz_hr1 小时前
待岗人员如何安置?国企末等调整制度下的分流通道设计与合规要点
人工智能
成都被卷死的程序员1 小时前
AI的Tools与Skills详解
人工智能
橙臣程1 小时前
深度学习9——transformer之注意力机制
人工智能·深度学习·transformer
网络工程小王2 小时前
【HCIE-AI】10.pytorch模型迁移分析
人工智能·学习·华为·llama
XMAIPC_Robot2 小时前
RK3588+8路AHD+双CAN工控方案|多路模拟视频同步采集+工业总线联动AI边缘检测落地
人工智能·rk3588·ai视觉·图像采集·多路ahd视频
hangyuekejiGEO2 小时前
临沂GEO技术解析与行业应用方案
人工智能·python
科技圈快迅2 小时前
2026年上海中卡RFID危险品智能柜深度解析:多系统融合的化工储运安全管控
人工智能·安全
Meya11272 小时前
实时采集 + 全域可视化,打造跨站点机房一体化U位管理方案
大数据·运维·人工智能