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

打开驱动配置

ap模组中,8088 没有引出 pwm 引脚,应使用 ap 模组中 8288 的 pwm 引脚

上述配置选中后,相关的GPIO配置也需要配置,打开源码文件:board/board.h代码默认打开了"PWM0"的配置,头文件定义如下:

#define BSP_USING_PWM0

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

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

访问PWM设备

访问PWM设备,库中提供了以下接口:

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

查找PWM设备

查找PWM设备,函数原型如下所示:

rt_device_t rt_device_find(const char* name);
  • 参数

    [IN]name:PWM设备名称,目前注册到的系统中的PWM设备名称为"pwm0"、"pwm1"和"pwm2"。名称与GPIO等关系请查看打开驱动配置的描述

  • 返回值

    RT_NULL:失败,设备不存在。

    非RT_NULL:成功,该返回值是操作PWM设备的句柄,在后续的接口中作为函数入参。

控制PWM设备

控制指定PWM设备,函数原型如下所示:

rt_err_t rt_device_control(rt_device_t dev, int cmd, void* arg);
  • 参数

    [IN]dev:PWM设备句柄,查找设备函数的返回值

    [IN]cmd:命令控制字,在这里主要支持以下宏定义

    // 宏定义所在文件相对路径:
    // rt-thread/components/drivers/include/drivers/rt_drv_pwm.h
    #define PWM_CMD_ENABLE      (128 + 0)
    #define PWM_CMD_DISABLE     (128 + 1)
    #define PWM_CMD_SET         (128 + 2)
    

    [INOUT]arg:对应结构体为 struct rt_pwm_configuration 定义如下:

    // 结构体定义所在文件相对路径:
    // rt-thread/components/drivers/include/drivers/rt_drv_pwm.h
    struct rt_pwm_configuration
    {
        rt_uint32_t channel;        // 通道号0-n
        rt_uint32_t period;         // pwm 周期所占系统时钟周期数,单位(1/131M)s
        rt_uint32_t pulse;          // 一个 pwm 周期中,高电平所占时钟周期数,单位(1/131M)s
        // RT_TRUE  : The channel of pwm is complememtary.
        // RT_FALSE : The channel of pwm is nomal.
        rt_bool_t  complementary;   // 是否互补通道,驱动根据通道号判断
    };
    
    pwm时钟使用系统主时钟,系统主时钟宏 BSP_CLOCK_SYSTEM_FREQ_HZ 定义在 board/board.h 中。 8288 默认为 96000000 Hz, 那么 pwm 一个时钟周期为 (1 / 96M) 秒,设置周期为 100 个时钟周期,脉冲宽度为 50 个时钟周期,则 pwm 输出的占空比为 50%

  • 返回值

    0,正常

    其他:错误,RT-Thread定义的错误类型。

设置PWM周期和脉冲宽度

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

rt_err_t rt_pwm_set(struct rt_device_pwm *device,
                    int channel,
                    rt_uint32_t period,
                    rt_uint32_t pulse);
  • 参数

    [IN]device:PWM设备句柄,查找设备函数的返回值

    [IN]channel:通道号0-n

    [IN]period:pwm 周期所占时钟时钟周期数,单位:1 / 96M 秒

    [IN]pulse:一个 pwm 周期中,高电平所占时钟周期数,单位:1 / 96M 秒

  • 返回值

    0,正常。

    其他:错误,RT-Thread定义的错误类型。

使能PWM设备

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

rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel);
  • 参数

    [IN]device:PWM设备句柄,查找设备函数的返回值

    [IN]channel:通道号0-n

  • 返回值

    0,使能成功。

    其他:错误,RT-Thread定义的错误类型。

关闭PWM设备

通过如下函数关闭 PWM 设备:

rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel);
  • 参数

    [IN]device:PWM设备句柄,查找设备函数的返回值

    [IN]channel:通道号0-n

  • 返回值

    0,关闭成功。

    其他:错误,RT-Thread定义的错误类型。

PWM使用示例

使用示例需要配置menuconfig打开配置(默认关闭),路径如下:

wiota APP -> open pwm, default close(_PWM_APP_)

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

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

  2. 设置PWM输出。

#include <rtthread.h>
#ifdef _PWM_APP_
#include <rtdevice.h>
#include "uc_pwm_app.h"

#define PWM_DEVICE_NAME    "pwm1"
#define PWM_DEV_CHANNEL     1

struct rt_device_pwm *pwm_dev = RT_NULL;
static struct rt_pwm_configuration pwm_cfg;

int pwm_app_init(int channel, rt_uint32_t period, rt_uint32_t pulse)
{
    rt_err_t ret = RT_EOK;

    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;
    }

    pwm_cfg.channel = channel;
    pwm_cfg.complementary = RT_TRUE;
    pwm_cfg.period = period;
    pwm_cfg.pulse = pulse;

    ret = rt_device_control(pwm_dev, PWM_CMD_SET, &pwm_cfg);
    if(ret != RT_EOK)
    {
        rt_kprintf("enable %s failed!\n", PWM_DEVICE_NAME);
    }
    return ret;
}

int pwm_app_disable(void)
{
    rt_err_t ret = RT_EOK;

    if(pwm_dev == RT_NULL)
    {
        return RT_ENOMEM;
    }

    ret = rt_device_control(pwm_dev, PWM_CMD_DISABLE, RT_NULL);
    if (ret != RT_EOK)
    {
        rt_kprintf("start %s failed!\n", PWM_DEVICE_NAME);
        return -RT_ERROR;
    }
    return ret;
}

int pwm_app_enable(void)
{
    rt_err_t ret = RT_EOK;

    if(pwm_dev == RT_NULL)
    {
        return RT_ENOMEM;
    }

    ret = rt_device_control(pwm_dev, PWM_CMD_ENABLE, RT_NULL);
    if (ret != RT_EOK)
    {
        rt_kprintf("start %s failed!\n", PWM_DEVICE_NAME);
        return -RT_ERROR;
    }
    return ret;
}

void pwm_app_sample(void)
{
    rt_kprintf("pwm test demo.\r\n");

    // 设置 pwm 周期 3000 个系统时钟周期 (3000 * (1 / 96000000)) 秒,其中高电平时间为 300 个系统时钟周期(300 * (1 / 96000000)) 秒,占空比就是 10%
    pwm_app_init(PWM_DEV_CHANNEL, 3000, 300);
    pwm_app_enable();
}

#endif
Back to top