Skip to content

PWM设备

PWM简介

PWM ( Pulse Width Modulation , 脉冲宽度调制 ) 是一种对模拟信号电平进行数字编码的方法,通过不同频率的脉冲使用方波的占空比用来对一个具体模拟信号的电平进行编码,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替所需要波形的设备。

驱动支持

访问PWM设备前,需要保证相关驱动配置已选中。

Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。

Linux环境:在代码根目录下执行scons --menuconfig进入配置。

PWM驱动所在路径如下:

RT-Thread Components -> Device Drivers -> Using PWM device drivers

打开驱动配置

驱动配置与引脚对应关系如下:

设备名称 宏配置 GPIO 引脚名称
"pwm0" BSP_USING_PWM0 15 U3, PIN8
"pwm1" BSP_USING_PWM1 16 J2, IO_16
"pwm2" BSP_USING_PWM2 17 J2, IO_17
"pwm3" BSP_USING_PWM3 18 J2, IO_18

访问 PWM 设备

应用程序通过 RT-Thread 提供的 PWM 设备管理接口来访问 PWM 设备硬件,相关接口如下所示:

函数 描述
rt_device_find() 根据 PWM 设备名称查找设备获取设备句柄
rt_pwm_set() 设置 PWM 周期和脉冲宽度
rt_pwm_enable() 使能 PWM 设备
rt_pwm_disable() 关闭 PWM 设备

查找 PWM 设备

应用程序根据 PWM 设备名称获取设备句柄,进而可以操作 PWM 设备,查找设备函数如下所示:

rt_device_t rt_device_find(const char* name);复制错误复制成功
参数 描述
name 设备名称
返回 ——
设备句柄 查找到对应设备将返回相应的设备句柄
RT_NULL 没有找到设备

一般情况下,注册到系统的 PWM 设备名称为 pwm0,pwm1等,使用示例如下所示:

#define PWM_DEV_NAME        "pwm3"  /* PWM 设备名称 */
struct rt_device_pwm *pwm_dev;      /* PWM 设备句柄 */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);

设置 PWM 周期和脉冲宽度

通过如下函数设置 PWM 周期和占空比:

rt_err_t rt_pwm_set(struct rt_device_pwm *device,
                    int channel,
                    rt_uint32_t period,
                    rt_uint32_t pulse);
参数 描述
device PWM 设备句柄
channel PWM 通道
period PWM 周期时间 (单位纳秒 ns)
pulse PWM 脉冲宽度时间 (单位纳秒 ns)
返回 ——
RT_EOK 成功
-RT_EIO device 为空
-RT_ENOSYS 设备操作方法为空
其他错误码 执行失败

PWM 的输出频率由周期时间 period 决定,例如周期时间为 0.5ms (毫秒),则 period 值为 500000ns(纳秒),输出频率为 2KHz,占空比为 pulse / period,pulse 值不能超过 period。

使用示例如下所示:

#define PWM_DEV_NAME        "pwm3"  /* PWM设备名称 */
#define PWM_DEV_CHANNEL     0       /* PWM通道 */
struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
rt_uint32_t period, pulse;

period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);

使能 PWM 设备

设置好 PWM 周期和脉冲宽度后就可以通过如下函数使能 PWM 设备:

rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel);复制错误复制成功
参数 描述
device PWM 设备句柄
channel PWM 通道 -channel代表互补通道
返回 ——
RT_EOK 设备使能成功
-RT_ENOSYS 设备操作方法为空
其他错误码 设备使能失败

使用示例如下所示:

#define PWM_DEV_NAME        "pwm3"  /* PWM设备名称 */
#define PWM_DEV_CHANNEL     0       /* PWM通道 */
struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
rt_uint32_t period, pulse;

period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
/* 使能设备 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);

关闭 PWM 设备通道

通过如下函数关闭 PWM 设备对应通道。

rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel);复制错误复制成功
参数 描述
device PWM 设备句柄
channel PWM 通道
返回 ——
RT_EOK 设备关闭成功
-RT_EIO 设备句柄为空
其他错误码 设备关闭失败

使用示例如下所示:

#define PWM_DEV_NAME        "pwm3"  /* PWM设备名称 */
#define PWM_DEV_CHANNEL     0       /* PWM通道 */
struct rt_device_pwm *pwm_dev;      /* PWM设备句柄 */
rt_uint32_t period, pulse;

period = 500000;    /* 周期为0.5ms,单位为纳秒ns */
pulse = 0;          /* PWM脉冲宽度值,单位为纳秒ns */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
/* 使能设备 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
/* 关闭设备通道 */
rt_pwm_disable(pwm_dev,PWM_DEV_CHANNEL);

PWM使用示例

使用示例需要配置menuconfig,使能例程与外设,步骤如下:

  1. 使能例程
Application Example Config -> Enable PWM Example
  1. 使能外设驱动
Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable PWM

以下提供PWM测试实例,测试步骤如下:

  1. 根据PWM设备名称,获取PWM设备句柄。

  2. 设置PWM输出。

#include <rtthread.h>
#ifdef APP_EXAMPLE_PWM

#ifndef RT_USING_PWM
#error "Please enable rt-thread PWM device driver"
#endif

#ifndef BSP_USING_PWM
#error "Please enable on-chip peripheral pwm config"
#endif

#ifndef BSP_USING_PWM0
#error "Please enable on-chip peripheral pwm0 config"
#endif

#include <rtdevice.h>
#include "uc_pwm_app.h"

#define THREAD_STACK_SIZE 512
#define THREAD_PRIORITY 5
#define THREAD_TIMESLICE 5

#define PWM_DEVICE_NAME "pwm0"
#define PWM_DEV_CHANNEL 0 // 此值无用,共有4组pwm,每组只有1个通道

struct rt_device_pwm *pwm_dev = RT_NULL;

static void pwm_thread_entry(void *parameter)
{
    rt_uint32_t value = 0;
    /* 设置PWM周期和脉冲宽度默认值 */
    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, 10000, 0);
    /* 使能设备 */
    rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);

    while (1)
    {
        rt_thread_mdelay(1000);
        rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, 10000, value);
        value += (10000 / 10);
        if (value > 10000)
        {
            value = 0;
        }
    }
}

int pwm_app_sample(void)
{
    rt_thread_t thread = RT_NULL;

    rt_kprintf("pwm_app_sample\n");

    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEVICE_NAME);
    if (pwm_dev == RT_NULL)
    {
        rt_kprintf("find %s failed!\n", PWM_DEVICE_NAME);
        return -RT_ERROR;
    }

    /* 创建线程 */
    thread = rt_thread_create("pwm_app",
                              pwm_thread_entry,
                              RT_NULL,
                              THREAD_STACK_SIZE,
                              THREAD_PRIORITY,
                              THREAD_TIMESLICE);
    /* 创建成功则启动线程 */
    if (RT_NULL == thread)
    {
        return -RT_ERROR;
    }
    else
    {
        rt_thread_startup(thread);
    }

    return RT_EOK;
}

#endif
Back to top