1、实验简介

参考网址:https://gitee.com/Lockzhiner-Electronics/lz3863/tree/master/apps/b2_buzzer_pwm

1.1、实验目的

本实验旨在帮助学习者掌握 OpenHarmony 轻量系统中 PWM(脉宽调制) 外设的基本使用方法。通过本实验,你将学会:

  1. 理解 PWM 的工作原理及占空比、频率等核心概念;
  2. 将 GPIO 引脚复用为 PWM 输出功能;
  3. 使用 IoT Hardware 接口初始化 PWM 并输出指定频率与占空比的信号;
  4. 结合 RTOS 线程与 osDelay() 控制蜂鸣器鸣响时长;
  5. 完成案例代码的编译、烧录与现象观察。

1.2、实验内容

本案例在 LZ3863-星闪开发板上,通过 GPIO11 引脚输出 PWM3 信号,驱动板载蜂鸣器发声。

项目 说明
控制引脚 GPIO11(IOT_IO_NAME_GPIO_11
引脚功能 复用为 PWM3 输出(IOT_IO_FUNC_GPIO_11_PWM3_OUT
PWM 端口 PWM3(端口号 3
输出频率 2000 Hz
输出占空比 50%(鸣响时)
鸣响时长 约 1000 ms(osDelay(100),1 tick = 10 ms)
任务名称 buzzer_pwm_main

程序将蜂鸣器控制逻辑封装在独立的 RTOS 线程中:上电后蜂鸣器鸣响约 1 秒,随后停止输出。

1.3、实验环境

项目 说明
硬件 LZ3863-星闪开发板、USB 数据线
软件 OpenHarmony v5.1.0 源码、hb 编译工具
调试工具 串口助手(波特率 115200,可选,用于查看调试日志)
案例路径 applications/sample/wifi-iot/app/b2_buzzer_pwm/

2、基础知识

2.1、什么是 PWM

PWM(Pulse Width Modulation,脉宽调制) 是一种通过快速切换数字信号高低电平,模拟模拟量输出的技术。在固定周期内,高电平持续时间占整个周期的比例称为 占空比(Duty Cycle),切换频率称为 频率(Frequency)

PWM 的两个核心参数:

参数 说明 本实验取值
频率(freq) 每秒 PWM 周期数,单位 Hz 2000 Hz
占空比(duty) 高电平时间占周期的百分比,范围 1~99 50%

对于蜂鸣器等有源/无源发声器件,合适的频率和占空比可使其产生清晰可闻的声音。本实验使用 2000 Hz、50% 占空比的方波驱动蜂鸣器。

2.2、引脚复用(Mux)

与 GPIO 实验类似,WS63 芯片的 IO 引脚支持多种功能复用。使用 PWM 前,必须通过 IoSetFunc() 将引脚配置为对应的 PWM 输出模式,而非普通 GPIO 模式。

本实验使用:

#define PWM_GPIO      IOT_IO_NAME_GPIO_11               // PWM 引脚号
#define PWM_GPIO_FUNC IOT_IO_FUNC_GPIO_11_PWM3_OUT      // 复用为 PWM3 输出
#define PWM_PORT      3                                 // PWM 端口号

注意:GPIO 引脚与 PWM 端口的对应关系需查阅 WS63 芯片手册及开发板原理图。本案例使用 GPIO11 对应 PWM3 端口。

2.3、蜂鸣器驱动原理

蜂鸣器是一种电声转换器件,接入 PWM 信号后,其内部振荡电路或压电片随方波频率振动而发声。频率越高,音调越高;占空比影响有效驱动功率,进而影响音量。

开发板已将蜂鸣器与驱动电路连接至 GPIO11(PWM3),用户只需通过 PWM API 输出指定频率和占空比的信号即可控制发声。将占空比设为 0 或调用 IoTPwmStop() 可停止发声。

2.4、核心 API 介绍

2.4.1、头文件
#include <stdio.h>
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_pwm.h"
#include "ohos_init.h"
2.4.2、PWM 常用 API
API 名称 功能说明
IoTGpioInit 初始化指定 GPIO 引脚
IoSetFunc 设置引脚复用功能(如 PWM 输出)
IoTPwmInit 初始化指定 PWM 端口
IoTPwmDeinit 解除 PWM 端口初始化
IoTPwmStart 启动 PWM 输出(指定占空比与频率)
IoTPwmStop 停止 PWM 输出
2.4.3、IoTPwmInit — 初始化 PWM 端口
unsigned int IoTPwmInit(unsigned int port);
参数 说明
port PWM 端口号,本实验为 3(PWM3)

返回值:IOT_SUCCESS 表示成功,IOT_FAILURE 表示失败。

2.4.4、IoTPwmStart — 启动 PWM 输出
unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq);
参数 说明
port PWM 端口号
duty 占空比,取值范围 1~99;设为 0 可等效停止输出
freq 输出频率,单位 Hz
2.4.5、IoTPwmStop — 停止 PWM 输出
unsigned int IoTPwmStop(unsigned int port);
参数 说明
port PWM 端口号

本案例通过 IoTPwmStart(PWM_PORT, 0, FREQUENCY) 将占空比设为 0 来停止蜂鸣器,效果与调用 IoTPwmStop() 类似。

2.4.6、osDelay — 线程延时
osStatus_t osDelay(uint32_t ticks);

本系统默认 1 tick = 10 ms,因此 osDelay(100) ≈ 延时 1000 ms(1 秒)。蜂鸣器在鸣响后延时 1 秒再关闭输出。

2.4.7、APP_FEATURE_INIT — 应用入口注册
APP_FEATURE_INIT(buzzer_pwm_example);

该宏将 buzzer_pwm_example 注册为应用特性初始化函数,系统启动完成后自动调用,无需手动修改 main() 函数。


3、程序设计

3.1、程序架构

本案例文件目录结构

b2_buzzer_pwm/
├── buzzer_pwm_example.c   # 主程序源码
├── BUILD.gn               # GN 编译配置
├── README_zh.md           # 案例简要说明
└── 实验手册.md             # 本实验手册

本案例采用 两层任务结构

系统启动
    │
    ▼
buzzer_pwm_example()           ← APP_FEATURE_INIT 注册,系统启动时自动执行
    │
    ▼
buzzer_pwm_main()              ← 蜂鸣器 PWM 控制任务
    ├── IoTGpioInit()          ← 初始化 GPIO
    ├── IoSetFunc()            ← 配置引脚复用为 PWM3
    ├── IoTPwmInit()           ← 初始化 PWM 端口
    ├── IoTPwmStart(50%, 2kHz) ← 启动蜂鸣器鸣响
    ├── osDelay(100)           ← 延时约 1 秒
    └── IoTPwmStart(0%, 2kHz)  ← 停止蜂鸣器输出

3.2、源文件说明

文件 说明
buzzer_pwm_example.c 主程序源码,包含蜂鸣器 PWM 控制逻辑
BUILD.gn GN 编译配置文件,定义静态库 buzzer_pwm_example

3.3、关键代码分析

(1)宏定义 — 引脚与 PWM 配置
#define PWM_GPIO      IOT_IO_NAME_GPIO_11               // GPIO 引脚(需支持 PWM 功能)
#define PWM_GPIO_FUNC IOT_IO_FUNC_GPIO_11_PWM3_OUT      // 引脚功能配置为 PWM3
#define PWM_PORT      3                                 // PWM 端口号
#define FREQUENCY     2000                              // PWM 频率:2000 Hz
(2)蜂鸣器控制任务 — buzzer_pwm_main

buzzer_pwm_main 是核心工作线程,完成 GPIO 与 PWM 初始化后,输出 50% 占空比、2000 Hz 的 PWM 信号驱动蜂鸣器,延时约 1 秒后关闭:

void buzzer_pwm_main(void *arg)
{
    (void)arg;

    // 初始化 GPIO
    IoTGpioInit(PWM_GPIO);

    // 设置 GPIO 复用功能为 PWM
    (void)IoSetFunc(PWM_GPIO, PWM_GPIO_FUNC);

    // 初始化 PWM 端口
    if (IoTPwmInit(PWM_PORT) != 0)
    {
        printf("[PWM] IoTPwmInit failed!\n");
        return;
    }

    printf("[PWM] buezer test started.\n");
    IoTPwmStart(PWM_PORT, 50, FREQUENCY);   // 50% 占空比,2000 Hz,蜂鸣器开始鸣响
    osDelay(100);                            // 延时约 1000 ms
    IoTPwmStart(PWM_PORT, 0, FREQUENCY);     // 占空比设为 0,停止鸣响
}
(3)应用启动入口 — buzzer_pwm_example

系统启动后,通过 APP_FEATURE_INIT 宏自动调用此函数,创建蜂鸣器控制线程:

static void buzzer_pwm_example(void)
{
    osThreadAttr_t attr = {0};
    attr.name       = "buzzer_pwm_main";
    attr.stack_size = 2048;
    attr.priority   = osPriorityNormal;

    if (osThreadNew(buzzer_pwm_main, NULL, &attr) == NULL)
    {
        printf("[BuzzerTest] Failed to create buzzer_pwm_main thread!\n");
    }
}

APP_FEATURE_INIT(buzzer_pwm_example);

3.4、程序执行流程

PWM3/GPIO11 buzzer_pwm_main buzzer_pwm_example 系统启动 PWM3/GPIO11 buzzer_pwm_main buzzer_pwm_example 系统启动 蜂鸣器开始鸣响 蜂鸣器停止鸣响 APP_FEATURE_INIT 触发 osThreadNew(buzzer_pwm_main) IoTGpioInit(GPIO11) IoSetFunc(GPIO11, PWM3_OUT) IoTPwmInit(3) IoTPwmStart(50%, 2000Hz) osDelay(100) ≈ 1000ms IoTPwmStart(0%, 2000Hz)

4、编译步骤

4.1、确认案例目录

确认案例已位于 OpenHarmony 源码目录下:

applications/sample/wifi-iot/app/b2_buzzer_pwm/
├── buzzer_pwm_example.c
├── BUILD.gn
└── 实验手册.md

若从外部复制,请将 b2_buzzer_pwm 目录放到上述 app/ 路径下。

4.2、修改 BUILD.gn(注册编译组件)

编辑 applications/sample/wifi-iot/app/BUILD.gn,在 features 列表中添加本案例:

lite_component("app") {
  features = [
    "startup",
    "b2_buzzer_pwm:buzzer_pwm_example",   // 添加此行
  ]
}

4.3、修改 SDK 配置文件

步骤 1:编辑 device/soc/hisilicon/ws63v100/sdk/build/config/target_config/ws63/config.py

找到 'ws63-liteos-app' 配置段,在其 'ram_component' 列表中添加:

"buzzer_pwm_example"

步骤 2:编辑 device/soc/hisilicon/ws63v100/sdk/libs_url/ws63/cmake/ohos.cmake

找到 "ws63-liteos-app" 对应的 set(COMPONENT_LIST 部分,添加:

"buzzer_pwm_example"

4.4、执行编译

在 OpenHarmony 源码根目录下执行:

rm -rf out
hb set -root .
# 通过上下方向键选择 ws63 对应的编译分支(如 nearlink_dk_3863 / ws63-liteos-app)
hb build -f

编译成功后,固件输出路径通常在 out/ws63/ 目录下。

4.5、烧录固件

使用开发板配套的烧录工具,将编译生成的固件烧写到 LZ3863-星闪开发板。具体烧录步骤请参考开发板用户手册。


5、运行结果

5.1、串口配置(可选)

若需查看调试日志,可打开串口助手:

参数
波特率 115200
数据位 8
停止位 1
校验位

5.2、预期现象

烧录并复位开发板后,可观察到:

  • 开发板 蜂鸣器鸣响约 1 秒 后自动停止;
  • 鸣响频率稳定,音调适中(2000 Hz);
  • 每次上电或复位仅鸣响一次,不会重复。

5.3、结果分析

现象 说明
蜂鸣器鸣响约 1 秒 IoTPwmStart(50, 2000) 输出有效 PWM 信号,osDelay(100) 保持约 1000 ms
鸣响后自动停止 IoTPwmStart(0, 2000) 将占空比设为 0,PWM 无有效驱动
串口输出启动日志 PWM 初始化成功后打印 [PWM] buezer test started.
仅鸣响一次 任务执行完毕后退出循环,不会重复触发

若 PWM 初始化失败,串口可能输出:

[PWM] IoTPwmInit failed!

若任务创建失败,串口可能输出:

[BuzzerTest] Failed to create buzzer_pwm_main thread!

5.4、常见问题排查

问题 可能原因 解决方法
蜂鸣器完全无声 案例未加入编译或烧录了错误固件 核对 4.2、4.3 节三处配置,重新编译烧录
蜂鸣器持续鸣响不停止 osDelay 未执行或占空比未清零 检查任务是否正常运行,确认 IoTPwmStart(0, ...) 被调用
串口报 IoTPwmInit failed 引脚复用或 PWM 端口配置错误 确认 PWM_GPIOPWM_GPIO_FUNCPWM_PORT 与硬件一致
音调异常或音量微弱 频率或占空比不合适 尝试调整 FREQUENCY(如 1000~4000 Hz)或占空比(30~70%)
编译报错找不到 buzzer_pwm_example BUILD.gn 或 config.py 未正确修改 逐步核对 4.2、4.3 节的配置项
引脚无响应 引脚复用功能未正确设置 确认 IoSetFunc()IoTPwmInit() 之前调用

6、实验扩展

完成基本实验后,可尝试以下扩展练习:

  1. 修改鸣响时长:将 osDelay(100) 改为 osDelay(50)(约 500 ms)或 osDelay(200)(约 2 s),观察蜂鸣器发声时间变化;
  2. 调整音调:修改 FREQUENCY 为 1000 Hz 或 4000 Hz,感受不同频率下的音调高低;
  3. 改变占空比:将占空比从 50 改为 30 或 70,观察音量变化;
  4. 使用 IoTPwmStop:将 IoTPwmStart(PWM_PORT, 0, FREQUENCY) 替换为 IoTPwmStop(PWM_PORT),对比停止方式;
  5. 周期性鸣响:在 buzzer_pwm_main 中加入循环,实现"嘀—嘀—嘀"间歇鸣响效果;
  6. 结合其他案例:配合 b3_adc_key 按键案例,实现按键触发蜂鸣器报警。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐