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,使能例程与外设,步骤如下:
- 使能例程
Application Example Config -> Enable PWM Example
- 使能外设驱动
Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable PWM
以下提供PWM测试实例,测试步骤如下:
-
根据PWM设备名称,获取PWM设备句柄。
-
设置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