函数定义
设置PWM参数
该函数可以设定指定PWM通道的周期和占空参数。
rt_err_t rt_pwm_set ( struct rt_device_pwm * device,
int channel,
rt_uint32_t period,
rt_uint32_t pulse
)
2
3
4
5
函数参数和返回值含义如下:
参数:
- device PWM设备句柄
- channel 指定的PWM通道
- period 周期
- pulse 占空比
- 返回 RT_OK 设置成功;RT_EIO 未找到pwm设备。
打开PWM通道
调用此函数可以使能指定的PWM通道
rt_err_t rt_pwm_enable ( struct rt_device_pwm * device,
int channel
)
2
3
函数参数和返回值含义如下:
参数:
- device PWM设备句柄
- channel 指定的PWM通道
- 返回 RT_OK 设置成功;RT_EIO 未找到pwm设备。
关闭PWM通道
调用此函数可以关闭指定的PWM通道
rt_err_t rt_pwm_disable ( struct rt_device_pwm * device,
int channel
)
2
3
函数参数和返回值含义如下:
参数:
- device PWM设备句柄
- channel 指定的PWM通道
- 返回 RT_OK 设置成功;RT_EIO 未找到pwm设备。
获取系统时钟节拍值
该函数将返回自操作系统启动以来到当前的系统时钟计数值
rt_tick_t rt_tick_get ( void )
函数参数和返回值含义如下:
参数:
- 返回 当前系统节拍计数值
介绍
黄山派拥有,2个GPTIM(通用定时器)、2个LPTIM(低功耗定时器)、1个ATIM(高级定时器)可以在 PWM 模式下工作,用于硬件定时器:
- 通用定时器(GPTIM) GPTIM 为系统 PCLK 实现了一个 16 位计数器,提供 1-65536 分频器。 它有4个输入/输出通道。 GPTIM 可用于 PWM 以生成波形信号或测量输入信号。
- 低功耗定时器(LPTIM) LPTIM 为系统 PCLK 或低功耗时钟实现 16 位计数器,提供 1-128 分频器。 LPTIM 可用于 PWM 以生成波形信号。
- 高级定时器(ATIM) ATIM 为系统 PCLK 实现了一个 32 位计数器,提供 1-65536 分频器。它有6个通道,通道1-3可分别配置为输入或输出模式, 其中每个通道可输出两路带死区保护的互补PWM,通道4可配置为输入或输出模式,可输出单路PWM,通道5~6可配置为输出比较模式。
这里我们还需要去配置图形化终端执行 scons --board=sf32lb52-lchspi-ulp --menuconfig 后,使用⇧和⇩方向键在不同菜单项间移动,按Enter键进入子菜单,进On-chip Peripheral RTOS Drivers->Enable pwm 选择Using PWM2,Space选中菜单项,按D保存并退出menuconfig。如下下图所示:
- pwm(x): x为设备编号,如pwm2、pwm3,需要注意的是设备编号从2开始,设备pwm2对应外设GPTIM1,pwm3对应外设GPTIM2,以此类推
- pwmlp(x):x为设备编号,如pwmlp1、pwmlp2,对应外设LPTIM1和LPTIM2
- pwma(x):x为设备编号,如pwma1,对应外设ATIM1
注:黄山派的任意引脚都支持PWM功能,可以通过以下代码进行绑定,需要注意第二个参数GPTIM1_CH2要根据menuconfig配置的实际硬件定时器修改,一个通道(CH)绑定一个不能重复。
程序编写
#include "rtthread.h"
#include "bf0_hal.h"
#include "drv_io.h"
#include "stdio.h"
#include "string.h"
#include <board.h>
#define PWM_DEV_NAME "pwm2" // PWM设备名称
#define PWM_CHANNEL 2 // PWM通道号
#define PWM_PERIOD (10 * 1000 * 1000) //(ns) -> freq = 1,000,000,000/PWM_PERIOD (hz)
uint32_t tick = 0; // 记录时间戳
uint32_t diff = 0; // 记录时间差
/*
- Function : pin_irq()
- Description : 引脚中断回调函数 - 用于频率测量
- Input : args 用户参数
- Return : 无
- Other : 通过计算相邻上升沿的时间差来测量PWM频率
*/
void pin_irq(void *args)
{
// 根据电平和时间戳计算频率
uint32_t now = rt_tick_get(); // 获取当前时间戳
if (tick == 0)
{
tick = now; // 初始化时间戳
}
else
{
diff = now - tick; // 计算时间差
tick = now; // 更新时间戳
}
}
/*
- Function : pwm_example()
- Description : PWM输出与频率测量示例
- Input : 无
- Return : 无
- Other : 配置PWM输出,中断测量其频率
*/
void pwm_example(void)
{
HAL_PIN_Set(PAD_PA30, GPTIM1_CH2, PIN_NOPULL, 1); // 配置为 PWM引脚
static struct rt_device_pwm *pwm_dev = RT_NULL;
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME); // 查找PWM设备
if (pwm_dev == RT_NULL)
{
rt_kprintf("PWM device not found\n");
return;
}
rt_kprintf("PWM device found\n");
rt_err_t r = rt_device_open((rt_device_t)pwm_dev, RT_DEVICE_FLAG_RDWR); // 打开PWM设备
if (r != RT_EOK)
{
rt_kprintf("PWM device open failed\n");
return;
}
rt_pwm_set(pwm_dev, PWM_CHANNEL, PWM_PERIOD, PWM_PERIOD / 2);
// 打印PWM周期和占空比
rt_kprintf("PWM period: %d Hz, duty: %d\n", 1000000000 / PWM_PERIOD, (PWM_PERIOD / 2) * 100 / PWM_PERIOD);
rt_pwm_enable(pwm_dev, PWM_CHANNEL);
rt_pin_mode(32, PIN_MODE_INPUT); // 配置为输入模式
rt_pin_attach_irq(32, PIN_IRQ_MODE_RISING, pin_irq, RT_NULL); // 配置中断回调函数,上升沿触发中断
rt_pin_irq_enable(32, PIN_IRQ_ENABLE); // 使能中断
}
/**
* @brief Main program
* @param None
* @retval 0 if success, otherwise failure number
*/
int main(void)
{
pwm_example();
while (1)
{
rt_kprintf("Frequency: %d Hz\n", RT_TICK_PER_SECOND / diff);
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
注:考虑到部分小伙伴没有示波器,不好直观的看到频率我们为了方便验证测试结果,可以将PWM输出引脚接到一个GPIO上,通过中断记录时间来测量频率(为什么不用定时器捕获呢?因为你还没学到这个功能---)
查看原理图与程序,我们需要短接PA32和PA30进行测试,PA30为输出,PA32为输入。
原理图如下图所示:
实际位置,如下图所示:
短接PA32和PA30后,编译烧录代码,打开串口助手,就可以看到打印PWM的频率的了,可以修改PWM的频率观察是否正确(因为使用的是GPIO中断和系统tick,所以不建议PWM频率超过500Hz),如下图所示: