5.12 PWM设备
2026/7/19大约 5 分钟设备驱动驱动PWM脉宽调制呼吸灯
5.12 PWM设备
📚 本节导读
学习时长: 约 25 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: C 语言基础、MCU 定时器/PWM 基础知识、5.1 设备驱动框架
🎯 学习目标
- 理解 OneOS PWM 设备驱动框架的设计
- 掌握 PWM 周期和占空比的配置方法
- 掌握 PWM 通道的使能与禁用
- 能够实现 LED 呼吸灯、舵机控制等 PWM 应用
一、概述
PWM(Pulse Width Modulation)是利用定时器产生可调占空比方波的技术,广泛应用于 LED 调光、电机调速、舵机控制等场景。OneOS 将 PWM 抽象为设备,提供统一的周期/占空比配置接口。PWM 设备驱动位于 drivers/misc/ 目录下,核心头文件为 pwm.h,实现文件为 pwm.c。
PWM 设备框架的特点:
- 多通道支持:每个 PWM 设备可管理多个定时器通道
- 独立配置:每个通道可独立设置周期和占空比
- 控制命令:通过
os_device_control()发送配置命令 - 简洁 API:提供
os_pwm_enable/disable/set_period/set_pulse专用接口
二、核心数据结构
2.1 PWM 配置结构体 os_pwm_configuration
struct os_pwm_configuration
{
uint32_t channel; /* PWM 通道号 */
uint32_t period; /* PWM 周期(单位:定时器时钟周期) */
uint32_t pulse; /* PWM 脉宽(单位:定时器时钟周期),pulse <= period */
};2.2 PWM 设备结构体 os_pwm_device_t
struct os_pwm_device
{
struct os_device parent; /* 继承自 os_device_t */
const struct os_pwm_ops *ops; /* PWM 操作函数表 */
uint32_t period; /* 当前周期(缓存) */
uint32_t max_value; /* 最大计数值(HAL 层使用) */
};
typedef struct os_pwm_device os_pwm_device_t;2.3 PWM 操作函数表 struct os_pwm_ops
struct os_pwm_ops
{
os_err_t (*enabled)(struct os_pwm_device *dev, uint32_t channel, os_bool_t enable);
os_err_t (*set_period)(struct os_pwm_device *dev, uint32_t channel, uint32_t period);
os_err_t (*set_pulse)(struct os_pwm_device *dev, uint32_t channel, uint32_t pulse);
os_err_t (*control)(struct os_pwm_device *dev, int cmd, void *args);
};| 函数指针 | 说明 |
|---|---|
enabled | 使能/禁用指定通道的 PWM 输出 |
set_period | 设置指定通道的 PWM 周期 |
set_pulse | 设置指定通道的 PWM 脉宽(占空比) |
control | 扩展控制命令(HAL 层自定义) |
三、API 详解
3.1 使能与禁用
os_err_t os_pwm_enable(struct os_pwm_device *pwm, uint32_t channel);
os_err_t os_pwm_disable(struct os_pwm_device *pwm, uint32_t channel);3.2 设置周期
os_err_t os_pwm_set_period(struct os_pwm_device *pwm, uint32_t channel, uint32_t period);| 参数 | 说明 |
|---|---|
pwm | PWM 设备指针 |
channel | PWM 通道号 |
period | 周期值(单位:定时器时钟周期) |
注意:
period的单位取决于 HAL 层定时器的时钟频率。例如时钟为 1MHz,period=1000表示周期为 1ms(频率 1kHz)。
3.3 设置脉宽(占空比)
os_err_t os_pwm_set_pulse(struct os_pwm_device *pwm, uint32_t channel, uint32_t pulse);| 参数 | 说明 |
|---|---|
pulse | 脉宽值(单位:定时器时钟周期),pulse <= period |
占空比 =
pulse / period× 100%。例如period=1000, pulse=500表示 50% 占空比。
3.4 控制命令
#define OS_PWM_CMD_ENABLE IOC_PWM(0x00) /* 使能 PWM */
#define OS_PWM_CMD_DISABLE IOC_PWM(0x01) /* 禁用 PWM */
#define OS_PWM_CMD_SET_PERIOD IOC_PWM(0x02) /* 设置周期 */
#define OS_PWM_CMD_SET_PULSE IOC_PWM(0x03) /* 设置脉宽 */通过 os_device_control() 发送,需传入 os_pwm_configuration 结构体。
3.5 注册 PWM 设备
os_err_t os_device_pwm_register(struct os_pwm_device *device, const char *name);四、代码示例
4.1 基本使用:LED 调光
#include <oneos_config.h>
#include <device.h>
#include <misc/pwm.h>
void pwm_basic_example(void)
{
os_pwm_device_t *pwm_dev;
/* 查找 PWM 设备 */
pwm_dev = (os_pwm_device_t *)os_device_open_s("pwm1");
if (pwm_dev == OS_NULL)
{
os_kprintf("PWM device not found!\r\n");
return;
}
/* 配置 PWM 通道 1:周期 1000,占空比 50% */
os_pwm_set_period(pwm_dev, 1, 1000); /* 周期 = 1000 */
os_pwm_set_pulse(pwm_dev, 1, 500); /* 脉宽 = 500(50% 占空比) */
os_pwm_enable(pwm_dev, 1); /* 使能 PWM 输出 */
os_kprintf("PWM CH1: period=1000, pulse=500, duty=50%%\r\n");
}4.2 LED 呼吸灯效果
void pwm_breathing_led(void)
{
os_pwm_device_t *pwm_dev;
uint32_t period = 1000;
int32_t pulse;
int32_t step = 10;
pwm_dev = (os_pwm_device_t *)os_device_open_s("pwm1");
if (pwm_dev == OS_NULL)
return;
os_pwm_set_period(pwm_dev, 1, period);
os_pwm_enable(pwm_dev, 1);
pulse = 0;
while (1)
{
/* 渐亮:占空比从 0% 到 100% */
for (pulse = 0; pulse <= period; pulse += step)
{
os_pwm_set_pulse(pwm_dev, 1, pulse);
os_task_msleep(10);
}
/* 渐暗:占空比从 100% 到 0% */
for (pulse = period; pulse >= 0; pulse -= step)
{
os_pwm_set_pulse(pwm_dev, 1, pulse);
os_task_msleep(10);
}
}
}4.3 使用控制命令接口
void pwm_control_example(void)
{
os_device_t *dev;
struct os_pwm_configuration config;
dev = os_device_open_s("pwm1");
if (dev == OS_NULL)
return;
/* 配置 PWM 通道 2 */
config.channel = 2;
config.period = 20000; /* 20ms 周期(50Hz,舵机常用频率) */
config.pulse = 1500; /* 1.5ms 脉宽(舵机中位) */
os_device_control(dev, OS_PWM_CMD_SET_PERIOD, &config);
os_device_control(dev, OS_PWM_CMD_SET_PULSE, &config);
os_device_control(dev, OS_PWM_CMD_ENABLE, &config);
os_kprintf("PWM CH2: period=20000, pulse=1500\r\n");
}4.4 多通道独立控制
void pwm_multi_channel(void)
{
os_pwm_device_t *pwm_dev;
pwm_dev = (os_pwm_device_t *)os_device_open_s("pwm1");
if (pwm_dev == OS_NULL)
return;
/* 通道 1:LED 调光,1kHz,30% 占空比 */
os_pwm_set_period(pwm_dev, 1, 1000);
os_pwm_set_pulse(pwm_dev, 1, 300);
os_pwm_enable(pwm_dev, 1);
/* 通道 2:舵机控制,50Hz,1.5ms 中位 */
os_pwm_set_period(pwm_dev, 2, 20000);
os_pwm_set_pulse(pwm_dev, 2, 1500);
os_pwm_enable(pwm_dev, 2);
/* 通道 3:蜂鸣器,4kHz,50% 占空比 */
os_pwm_set_period(pwm_dev, 3, 250);
os_pwm_set_pulse(pwm_dev, 3, 125);
os_pwm_enable(pwm_dev, 3);
os_kprintf("PWM 3 channels configured\r\n");
}五、注意事项
- 周期和脉宽单位:
period和pulse的单位是定时器时钟周期,实际时间取决于 HAL 层时钟频率 - 脉宽不大于周期:
pulse <= period,否则 PWM 行为未定义 - 先配置后使能:建议先设置周期和脉宽,最后使能输出,避免产生意外的波形
- 通道独立性:同一 PWM 设备的不同通道共享定时器时钟,但周期和脉宽可独立设置
- 占空比分辨率:
period越大,占空比可调分辨率越高,但 PWM 频率越低
📝 本节小结
- OneOS PWM 设备通过
os_pwm_device_t统一抽象,HAL 层实现os_pwm_ops接口 - 核心操作为设置周期(
os_pwm_set_period)和脉宽(os_pwm_set_pulse) - 支持多通道独立配置,每个通道可设置不同的占空比
- 典型应用:LED 呼吸灯、舵机控制、电机调速、蜂鸣器驱动