基于 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开发的核心思维方式------理解这一点,学生不仅能做完这五个实验,也能在遇到新硬件、新场景(比如养老看护)时,快速类比迁移已有知识,独立设计解决方案。

相关推荐
2501_938140072 小时前
做内容很省心,2026好用AI笔记,支持抖音小红书视频无水印保存
人工智能
sell-cloud4 小时前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
Navicat中国6 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI6 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区6 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris8 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy8 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V9 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI9 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技9 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人