有两个 PWM 示例:
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
#define MIN_PERIOD PWM_SEC(1U) / 128U
#define MAX_PERIOD PWM_SEC(1U)
int main(void)
{
uint32_t max_period;
uint32_t period;
uint8_t dir = 0U;
// 校准 PWM 周期
max_period = MAX_PERIOD;
while (pwm_set_dt(&pwm_led0, max_period, max_period / 2U)) {
max_period /= 2U; // 如果失败,降低周期
}
period = max_period;
while (1) {
// 设置占空比 = 50%
pwm_set_dt(&pwm_led0, period, period / 2U);
// 周期翻倍或减半,实现频率变化
period = dir ? (period * 2U) : (period / 2U);
k_sleep(K_SECONDS(4U));
}
}
#define PWM_SEC(1U) // 1秒周期
#define PWM_SEC(1U) / 128U // 1/128秒 ≈ 7.8ms
// 获取 LED PWM 设备
const struct device *led_pwm = DEVICE_DT_GET(LED_PWM_NODE_ID);
// 开灯
led_on(led_pwm, led);
// 关灯
led_off(led_pwm, led);
// 设置亮度 (0-100)
led_set_brightness(led_pwm, led, level);
// 闪烁
led_blink(led_pwm, led, on_time_ms, off_time_ms);
// 逐渐增加亮度
for (level = 0; level <= MAX_BRIGHTNESS; level++) {
led_set_brightness(led_pwm, led, level);
k_sleep(K_MSEC(CONFIG_FADE_DELAY));
}
// 逐渐减少亮度
for (level = MAX_BRIGHTNESS; level >= 0; level--) {
led_set_brightness(led_pwm, led, level);
k_sleep(K_MSEC(CONFIG_FADE_DELAY));
}
/ {
aliases {
pwm-led0 = &pwm_led0;
};
pwmleds {
compatible = "pwm-leds";
pwm_led0: pwm_led_0 {
pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
label = "LED 0";
};
};
};
// 从设备树别名获取
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
// 直接从节点获取
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_NODELABEL(my_pwm));
if (!pwm_is_ready_dt(&pwm_led0)) {
printk("PWM device not ready\n");
}
// 使用 pwm_dt_spec
int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period, uint32_t pulse);
// 直接指定通道
int pwm_set(const struct device *dev, uint32_t ch, uint32_t period, uint32_t pulse, pwm_flags_t flags);
参数说明:
| 参数 | 单位 | 说明 |
|---|---|---|
| period | 纳秒 | PWM 周期 |
| pulse | 纳秒 | 脉冲宽度(高电平时间) |
| flags | - | 极性等标志 |
// 50% 占空比
pwm_set_dt(&pwm_led0, period, period / 2);
// 25% 占空比
pwm_set_dt(&pwm_led0, period, period / 4);
// 75% 占空比
pwm_set_dt(&pwm_led0, period, period * 3 / 4);
// 频率 = 1 / 周期
PWM_SEC(1) // 1 Hz (1秒)
PWM_MSEC(20) // 50 Hz (20ms)
PWM_USEC(50) // 20 kHz (50μs)
PWM_POLARITY_NORMAL // 正极性:高电平有效
PWM_POLARITY_INVERTED // 反极性:低电平有效
&pwm0 {
status = "okay";
ch0-pin = <13>; // LED1
ch1-pin = <14>; // LED2
ch2-pin = <15>; // LED3
};
// 从设备树获取 LED 规范
static const struct led_dt_spec led0 = LED_DT_SPEC_GET_OR(DT_ALIAS(led0), {0});
// 开/关
led_on(dev, num);
led_off(dev, num);
// 设置亮度 (0-255 或 0-100,取决于驱动)
led_set_brightness(dev, num, level);
// 闪烁 (部分驱动支持)
led_blink(dev, num, delay_on, delay_off);
// 获取颜色 (RGB LED)
led_set_color(dev, num, color);
void breathing_led(const struct device *led, uint8_t num)
{
int direction = 1; // 1=变亮, -1=变暗
uint8_t brightness = 0;
while (1) {
led_set_brightness(led, num, brightness);
brightness += direction * 5;
if (brightness >= 100) direction = -1;
if (brightness <= 0) direction = 1;
k_msleep(30); // 约 30fps
}
}
// 舵机通常需要 50Hz (20ms) 周期
// 脉宽 1ms = 0°, 1.5ms = 90°, 2ms = 180°
#define SERVO_PERIOD PWM_MSEC(20) // 20ms 周期
#define SERVO_MIN PWM_USEC(500) // 0.5ms
#define SERVO_MAX PWM_USEC(2500) // 2.5ms
void servo_set_angle(const struct device *pwm, uint8_t ch, uint8_t angle)
{
uint32_t pulse = SERVO_MIN + (angle * (SERVO_MAX - SERVO_MIN) / 180);
pwm_set(pwm, ch, SERVO_PERIOD, pulse, 0);
}
| 问题 | 答案 |
|---|---|
| PWM 周期怎么设? | pwm_set_dt(&spec, period, pulse) 第一个参数 |
| 占空比怎么算? | pulse / period * 100% |
| 呼吸灯怎么实现? | 循环改变 led_set_brightness() 的亮度值 |
| 舵机控制频率? | 通常 50Hz (20ms 周期) |
| nRF54L15 PWM 在哪配? | 设备树 pwm0 节点 |
| 示例 | 驱动层级 | 控制方式 |
|---|---|---|
| blinky_pwm | PWM 直接驱动 | 改变周期 |
| led/pwm | LED 子系统 | 亮度/闪烁 |
| Button GPIO | GPIO 输入 | 轮询/中断 |
小白 🤖 2026-03-14