#立创·梁山派·天空星# GD32F407VET6的高级定时器0输出3路互补PWM
1. 简述
仿照立创开源天空星入门手册编写,其开源的模板只有通用定时器1的PWM配置
参考来源: 立创开源天空星入门手册 第十八、PWM呼吸灯
2. PWM配置流程
- 配置通道引脚GPIO
- 配置定时器
- 配置输出结构体
- 配置定时器输出通道
- 配置定时器输出通道占空比
2.1 配置通道引脚GPIO
GD32F407VET6有2个高级定时器,定时器0、定时器7。本次使用的是定时器0,查找数据手册的第66页可知,定时器通道及其复用功能,如图2-1-1所示。
定时器0通道 | 互补通道引脚 | 普通通道引脚 |
---|---|---|
TIMER0_CH0 | PE8 | PE9 |
TIMER0_CH1 | PE10 | PE11 |
TIMER0_CH2 | PE12 | PE13 |
要操作GPIO引脚,必不可少的就是对GPIO进行配置,开启时钟,配置模式,配置输出,设置复用功能等一系列的操作。
引脚宏定义如下:
/* PE8 TIMER0_CH0_ON */
#define PWM_TIMERX
#define BSP_PWM4_RCU RCU_GPIOE
#define BSP_PWM4_PORT GPIOE
#define BSP_PWM4_PIN GPIO_PIN_8
#define BSP_PWM4_AF GPIO_AF_1
/* PE9 TIMER0_CH0 */
#define PWM_TIMERX
#define BSP_PWM1_RCU RCU_GPIOE
#define BSP_PWM1_PORT GPIOE
#define BSP_PWM1_PIN GPIO_PIN_9
#define BSP_PWM1_AF GPIO_AF_1
/* PE10 TIMER0_CH1_ON */
#define PWM_TIMERX
#define BSP_PWM5_RCU RCU_GPIOE
#define BSP_PWM5_PORT GPIOE
#define BSP_PWM5_PIN GPIO_PIN_10
#define BSP_PWM5_AF GPIO_AF_1
/* PE11 TIMER0_CH1 */
#define PWM_TIMERX
#define BSP_PWM2_RCU RCU_GPIOE
#define BSP_PWM2_PORT GPIOE
#define BSP_PWM2_PIN GPIO_PIN_11
#define BSP_PWM2_AF GPIO_AF_1
/* PE12 TIMER0_CH2_ON */
#define PWM_TIMERX
#define BSP_PWM6_RCU RCU_GPIOE
#define BSP_PWM6_PORT GPIOE
#define BSP_PWM6_PIN GPIO_PIN_12
#define BSP_PWM6_AF GPIO_AF_1
/* PE13 TIMER0_CH2 */
#define PWM_TIMERX
#define BSP_PWM3_RCU RCU_GPIOE
#define BSP_PWM3_PORT GPIOE
#define BSP_PWM3_PIN GPIO_PIN_13
#define BSP_PWM3_AF GPIO_AF_1
初始化GPIO引脚的配置,如下(其他端口类似):
/* 开启PWM1时钟 */
rcu_periph_clock_enable(BSP_PWM1_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM1_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM1_PIN);
gpio_output_options_set(BSP_PWM1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM1_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM1_PORT, BSP_PWM1_AF, BSP_PWM1_PIN);
/* 开启PWM2时钟 */
rcu_periph_clock_enable(BSP_PWM2_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM2_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM2_PIN);
gpio_output_options_set(BSP_PWM2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM2_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM2_PORT, BSP_PWM2_AF, BSP_PWM2_PIN);
/* 开启PWM3时钟 */
rcu_periph_clock_enable(BSP_PWM3_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM3_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM3_PIN);
gpio_output_options_set(BSP_PWM3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM3_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM3_PORT, BSP_PWM3_AF, BSP_PWM3_PIN);
/* 开启PWM4时钟 */
rcu_periph_clock_enable(BSP_PWM4_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM4_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM4_PIN);
gpio_output_options_set(BSP_PWM4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM4_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM4_PORT, BSP_PWM4_AF, BSP_PWM4_PIN);
/* 开启PWM5时钟 */
rcu_periph_clock_enable(BSP_PWM5_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM5_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM5_PIN);
gpio_output_options_set(BSP_PWM5_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM5_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM5_PORT, BSP_PWM5_AF, BSP_PWM5_PIN);
/* 开启PWM6时钟 */
rcu_periph_clock_enable(BSP_PWM6_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM6_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM6_PIN);
gpio_output_options_set(BSP_PWM6_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM6_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM6_PORT, BSP_PWM6_AF, BSP_PWM6_PIN);
需要注意的点就是设置复用功能的时候配置为GPIO_AF_1,因为我们使用的是引脚的AF1的功能。
2.2 配置定时器
PWM输出是依赖于定时器的,所以要对定时器进行配置,但是我们不使用定时器的中断功能,故不用对定时器的中断进行配置。
这里我们要配置定时器0的参数。关于定时器0的宏定义如下:
/* TIMER */
#define BSP_PWM_TIMER_RCU RCU_TIMER0 // 定时器时钟
#define BSP_PWM_TIMER TIMER0 // 定时器
2.3 配置输出结构体
要使用定时器的PWM功能就是用定时器的输出功能,关于输出功能的参数配置有一个结构体,如图2-3-1所示。
- outputstate:通道输出状态,一般是使能TIMER_CCX_ENABLE,使能PWM输出到端口。
- outputnstate:互补通道输出状态,一般是使能TIMER_CCXN_ENABLE,使能PWM输出到端口。
- ocpolarity:通道输出的极性,也就是配置为低电平有效还是高电平有效,这里配置为高电平有效TIMER_OC_POLARITY_HIGH。
- ocnpolarity:互补通道输出的极性,也就是配置为低电平有效还是高电平有效,这里配置为高电平有效TIMER_OCN_POLARITY_HIGH。
- ocidlestate:通道空闲输出状态,也就是配置为低电平有效还是高电平有效,这里配置为低电平有效TIMER_OC_IDLE_STATE_LOW。
- ocnidlestate:互补通道空闲输出状态,也就是配置为低电平有效还是高电平有效,这里配置为高电平有效TIMER_OCN_IDLE_STATE_LOW。
注意:通道输出的极性 和 互补通道输出的极性需要配置为相同电平,才是互补输出。
参考配置,如下:
/* 定义定时器参数结构体 */
timer_oc_parameter_struct timer_oc_initpara;
/* 通道输出状态 */
timer_oc_initpara.outputstate = TIMER_CCX_ENABLE;
/* 互补通道输出状态 */
timer_oc_initpara.outputnstate = TIMER_CCXN_ENABLE;
/* 通道输出的极性 */
timer_oc_initpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
/* 互补通道输出的极性 */
timer_oc_initpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
/* 通道空闲输出状态 */
timer_oc_initpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
/* 互补通道空闲输出状态 */
timer_oc_initpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
2.4 配置定时器输出通道
配置好输出通道参数之后,需要初始化这个结构体,并且还需要配置使用定时器的通道几进行输出。
void timer_channel_output_config(
uint32_t timer_periph,uint16_t channel, timer_oc_parameter_struct* ocpara);
这个函数是配置定时器通道的输出功能,有三个参数,第一个参数就是要使能的定时器外设,第二个参数是要使能的定时器通道,第三个参数是配置的输出结构体。
配置定时器输出功能代码如下:
/* 配置定时器输出功能 */
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_0, &timer_oc_initpara);
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_1, &timer_oc_initpara);
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_2, &timer_oc_initpara);
2.5 配置定时器输出通道占空比
void timer_channel_output_pulse_value_config(
uint32_t timer_periph, uint16_t channel, uint32_t pulse);
这个函数是配置定时器通道输出的脉冲值。有三个参数,第一个参数是要配置的定时器,第二个参数是要配置的定时器通道,第三个参数是要设置的脉冲值。脉冲值的取值范围为(0-65535)。一般我们调节占空比也是调用这个函数,通过设置这个通道的输出脉冲值,改变不同的占空比。
这里我们将占空比设置为30%,配置如下:
/* 配置定时器通道输出脉冲值 */
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_0, 2999);
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_1, 2999);
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_2, 2999);
这个函数是配置外设定时器通道输出比较模式。有三个参数,第一个参数是要配置的定时器外设,第二个参数是要配置的定时器通道,第三个参数是要配置的比较模式。
关于第三个参数的可选选项如图2-5-1所示。

这里设置为PWM模式0,也就是配置为TIMER_OC_MODE_PWM0。配置代码如下:
/* 配置定时器通道输出比较模式 */
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_0,
TIMER_OC_MODE_PWM0);
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_1,
TIMER_OC_MODE_PWM0);
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_2,
TIMER_OC_MODE_PWM0);
2.6 配置定时器输出优先级配置(高级定时器才需要配置)
/* 配置定时器输出优先级配置,高级定时器配置才有输出 */
timer_primary_output_config(BSP_PWM_TIMER, ENABLE);
2.7 使能定时器
/* 使能定时器 */
timer_enable(BSP_PWM_TIMER);
3. 最终效果——输出波形
这是使用正点原子DS100示波器查看的PE9、PE8的输出波形,如下图3-1、图3-2所示。
4. 完整参考代码
4.1 pwm.h
#ifndef PWM_H
#define PWM_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "board.h"
/* PE8 TIMER0_CH0_ON */
#define PWM_TIMERX
#define BSP_PWM4_RCU RCU_GPIOE
#define BSP_PWM4_PORT GPIOE
#define BSP_PWM4_PIN GPIO_PIN_8
#define BSP_PWM4_AF GPIO_AF_1
/* PE9 TIMER0_CH0 */
#define PWM_TIMERX
#define BSP_PWM1_RCU RCU_GPIOE
#define BSP_PWM1_PORT GPIOE
#define BSP_PWM1_PIN GPIO_PIN_9
#define BSP_PWM1_AF GPIO_AF_1
/* PE10 TIMER0_CH1_ON */
#define PWM_TIMERX
#define BSP_PWM5_RCU RCU_GPIOE
#define BSP_PWM5_PORT GPIOE
#define BSP_PWM5_PIN GPIO_PIN_10
#define BSP_PWM5_AF GPIO_AF_1
/* PE11 TIMER0_CH1 */
#define PWM_TIMERX
#define BSP_PWM2_RCU RCU_GPIOE
#define BSP_PWM2_PORT GPIOE
#define BSP_PWM2_PIN GPIO_PIN_11
#define BSP_PWM2_AF GPIO_AF_1
/* PE12 TIMER0_CH2_ON */
#define PWM_TIMERX
#define BSP_PWM6_RCU RCU_GPIOE
#define BSP_PWM6_PORT GPIOE
#define BSP_PWM6_PIN GPIO_PIN_12
#define BSP_PWM6_AF GPIO_AF_1
/* PE13 TIMER0_CH2 */
#define PWM_TIMERX
#define BSP_PWM3_RCU RCU_GPIOE
#define BSP_PWM3_PORT GPIOE
#define BSP_PWM3_PIN GPIO_PIN_13
#define BSP_PWM3_AF GPIO_AF_1
/**
* TIMER
*
**/
#define BSP_PWM_TIMER_RCU RCU_TIMER0 // 定时器时钟
#define BSP_PWM_TIMER TIMER0 // 定时器
/**
*
*
*/
void pwm_init(void);
#ifdef __cplusplus
}
#endif
#endif // !PWM_H
4.2 pwm.c
#include "pwm.h"
static void PWM_GPIO_Init(void)
{
/* 开启PWM1时钟 */
rcu_periph_clock_enable(BSP_PWM1_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM1_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM1_PIN);
gpio_output_options_set(BSP_PWM1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM1_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM1_PORT, BSP_PWM1_AF, BSP_PWM1_PIN);
/* 开启PWM2时钟 */
rcu_periph_clock_enable(BSP_PWM2_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM2_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM2_PIN);
gpio_output_options_set(BSP_PWM2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM2_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM2_PORT, BSP_PWM2_AF, BSP_PWM2_PIN);
/* 开启PWM3时钟 */
rcu_periph_clock_enable(BSP_PWM3_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM3_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM3_PIN);
gpio_output_options_set(BSP_PWM3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM3_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM3_PORT, BSP_PWM3_AF, BSP_PWM3_PIN);
/* 开启PWM4时钟 */
rcu_periph_clock_enable(BSP_PWM4_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM4_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM4_PIN);
gpio_output_options_set(BSP_PWM4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM4_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM4_PORT, BSP_PWM4_AF, BSP_PWM4_PIN);
/* 开启PWM5时钟 */
rcu_periph_clock_enable(BSP_PWM5_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM5_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM5_PIN);
gpio_output_options_set(BSP_PWM5_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM5_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM5_PORT, BSP_PWM5_AF, BSP_PWM5_PIN);
/* 开启PWM6时钟 */
rcu_periph_clock_enable(BSP_PWM6_RCU);
/* 配置IO参数 */
gpio_mode_set(BSP_PWM6_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM6_PIN);
gpio_output_options_set(BSP_PWM6_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,
BSP_PWM6_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM6_PORT, BSP_PWM6_AF, BSP_PWM6_PIN);
}
static void PWM_TIMER_Init(void)
{
/* 定义定时器结构体 */
timer_parameter_struct timer_initpara;
/* 开启定时器时钟 */
rcu_periph_clock_enable(BSP_PWM_TIMER_RCU);
/* 重置定时器 */
timer_deinit(BSP_PWM_TIMER);
/* 时钟预分频值 PSC_CLK= 168MHZ / 168 = 1MHZ */
timer_initpara.prescaler = 168 - 1;
/* 中央对齐模式3 */
timer_initpara.alignedmode = TIMER_COUNTER_CENTER_BOTH;
/* 向上计数 */
timer_initpara.counterdirection = TIMER_COUNTER_UP;
/*周期T = 10000 1MHZ = 10ms f = 100HZ */
timer_initpara.period = 10000 - 1;
/* 分频因子 */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
/* 重复计数器 0-255 */
timer_initpara.repetitioncounter = 0;
/* 初始化定时器 */
timer_init(BSP_PWM_TIMER, &timer_initpara);
/* 定义定时器参数结构体 */
timer_oc_parameter_struct timer_oc_initpara;
/* 通道输出状态 */
timer_oc_initpara.outputstate = TIMER_CCX_ENABLE;
/* 互补通道输出状态 */
timer_oc_initpara.outputnstate = TIMER_CCXN_ENABLE;
/* 通道输出的极性 */
timer_oc_initpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
/* 互补通道输出的极性 */
timer_oc_initpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
/* 通道空闲输出状态 */
timer_oc_initpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
/* 互补通道空闲输出状态 */
timer_oc_initpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
/* 配置定时器输出功能 */
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_0, &timer_oc_initpara);
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_1, &timer_oc_initpara);
timer_channel_output_config(BSP_PWM_TIMER, TIMER_CH_2, &timer_oc_initpara);
/* 配置定时器通道输出脉冲值 */
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_0, 2999);
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_1, 2999);
timer_channel_output_pulse_value_config(BSP_PWM_TIMER, TIMER_CH_2, 2999);
/* 配置定时器通道输出比较模式 */
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_0,
TIMER_OC_MODE_PWM0);
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_1,
TIMER_OC_MODE_PWM0);
timer_channel_output_mode_config(BSP_PWM_TIMER, TIMER_CH_2,
TIMER_OC_MODE_PWM0);
/* 配置定时器输出优先级配置,高级定时器配置才有输出 */
timer_primary_output_config(BSP_PWM_TIMER, ENABLE);
/* 使能定时器 */
timer_enable(BSP_PWM_TIMER);
}
void pwm_init(void)
{
PWM_GPIO_Init();
PWM_TIMER_Init();
}