RISC-V技术论坛
直播中

ouxiaolong

11年用户 470经验值
擅长:嵌入式技术 光电显示
私信 关注
[经验]

【兆易创新GD32VF103R-START开发板试用体验】PWM输出

开发环境:
IDE:MounRiver Studio
开发板:GD32VF103R-START
MCU:GD32VF103RB

1 PWM输出的工作原理脉冲宽度调制(PWM),是英文“Pulse WidthModulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。
GD32 的定时器除了 TIMER5 和 6(基本定时器)。其他的定时器都可以用来产生 PWM 输出。每个定时器有四个通道,每一个通道都有一个捕获比较寄存器,,将寄存器值和计数器值比较,通过比较结果输出高低电平,便可以实现脉冲宽度调制模式(PWM信号)。
关于定时器的相关寄存器的基本原理,请看参考手册。下面谈谈如何使用定时器的寄存器进行PWM输出的。若配置脉冲计数器TIMERx_CNT为向上计数,而重载寄存器TIMERx_CAR配置为N,即TIMERx_CNT的当前计数值数值X在CK_TIMER时钟源的驱动下不断累加,当TIMERx_CNT的数值X大于N时,会重置TIMERx_CNT数值为0重新计数。而在TIMERx_CNT计数的同时,TIMERx_CNT的计数值X会与比较寄存器TIMERx_CHxCV预先存储了的数值A进行比较,当脉冲计数器TIMERx_CNT的数值X小于比较寄存器TIMERx_CHxCV的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。如此循环,得到的输出脉冲周期就为重载寄存器TIMERx_CAR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMERx_CHxCV的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为A/(N+1)。
估计很多初学者看了上面的一段话都很蒙圈,没关系,下面以向上计数模式为例进行讲解。
                               20220521-1.png
在PWM输出模式下,除了CNT(计数器当前值)、CAR(自动重装载值)之外,还多了一个值CHxCV(捕获/比较寄存器值)。当CNT小于CHxCV时,CHxCV通道输出低电平;当CNT等于或大于CHxCV时,CHxCV通道输出高电平。因此得到PWM的一个周期如下:
1.定时器从0开始向上计数;2.当0-t1段,定时器计数器CNT值小于CHxCV值,输出低电平;3.t1-t2段,定时器计数器CNT值大于CHxCV值,输出高电平;4.当CNT值达到CAR时,定时器溢出,重新向上计数...循环此过程。
至此一个PWM周期完成。针对PWM重点关注两个寄存器,CAR寄存器确定PWM频率,CHxCV寄存器确定占空比
上文提到了PWM的输出模式,下面讲解PWM的工作模式:l  PWM模式1(向上计数)  :计数器从0计数加到自动重装载值(CAR),然后重新从0开始计数,并且产生一个计数器溢出事。l  PWM模式2(向下计数)  :计数器从自动重装载值(CAR)减到0,然后重新从重装载值(CAR)开始递减,并且产生一个计数器溢出事件。
这里我们仅利用 TIMER2产生多路 PWM 输出。如果要产生多路输出,大家可以根据我们的代码稍作修改即可。具体不同定时器对应引脚在对应芯片数据手册的引脚说明(pin description) 中查看。
关于PWM的相关寄存器请参看GD32VF103参考手册。
2 PWM输出实现2.1 PWM代码分析本章要实现通过TIMER2实现2路方波的输出,以TIMER2_CH0 输出 PWM 为例进行讲解。下面我们介绍通过库函数来配置该功能的步骤。1) 开启 TIMER2 时钟以及GPIO的时钟,配置 PA6为复用输出。要使用 TIMER2,我们必须先开启 TIMER2的时钟,这点相信大家看了这么多代码,应该明白了。库函数使能 TIMER2及PA6时钟的方法是:/* enable the GPIOA clock */rcu_periph_clock_enable(RCU_GPIOA);//Enable TIMER2 clockrcu_periph_clock_enable(RCU_TIMER2); 库函数设置 AFIO 时钟的方法是:/* 开启复用功能时钟 */rcu_periph_clock_enable(RCU_AF); 2) 初始化 TIMER2,设置 TIMER2的 CAR 和 PSC。在开启了 TIMER2 的时钟之后,我们要设置 CAR 和 PSC 两个寄存器的值来控制输出 PWM 的周期。这在库函数是通过timer_init()函数实现的,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为:/* TIMER2 configuration */timer_init_struct.prescaler         = 0;timer_init_struct.alignedmode       = TIMER_COUNTER_EDGE;timer_init_struct.counterdirection  = TIMER_COUNTER_UP;timer_init_struct.period            = 999;timer_init_struct.clockdivision     = TIMER_CKDIV_DIV1;timer_init_struct.repetitioncounter= 0;timer_init(TIMER2,&timer_init_struct);  3) 设置 TIMER2_CH0的 PWM 模式,使能 TIMER2的 CH0输出。接下来,我们要设置 TIMER2_CH0为 PWM 模式(默认是冻结的),在库函数中,PWM通道设置是通过函数 timer_channel_output_config()来设置的,我们直接来看看结构体 timer_oc_parameter_struct的定义:/* channel output parameterstructure definitions */typedef struct {    uint16_t outputstate;                       /*!< channel outputstate */    uint16_t outputnstate;                      /*!< channel complementaryoutput state */    uint16_t ocpolarity;                        /*!< channel outputpolarity */    uint16_t ocnpolarity;                       /*!< channelcomplementary output polarity */    uint16_t ocidlestate;                       /*!< idle state ofchannel output */    uint16_t ocnidlestate;                      /*!< idle state ofchannel complementary output */} timer_oc_parameter_struct; 该结构体主要配置通道的状态,极性等,还需要设置占空比等配置,不同的通道需要分别设置。/* PWM Mode configuration:Channel0 */timer_channel_output_config(TIMER2,TIMER_CH_0, &timer_oc_init_struct); /* 通道2占空比设置 */timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0, CH0CV_Val);/* PWM模式0 */timer_channel_output_mode_config(TIMER2,TIMER_CH_0,TIMER_OC_MODE_PWM0);/* 不使用输出比较影子寄存器 */timer_channel_output_shadow_config(TIMER2,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);       4) 使能 TIM3。我们需要使能 TIMER2。使能 TIMER2的方法前面已经讲解过:timer_enable(TIMER2);最后看下主函数代码:/* Includes*********************************************************************/
#include "gd32vf103.h"
#include "gd32vf103r_led_start.h"
#include "gd32vf103r_systick_start.h"
#include "gd32vf103r_timx_start.h"

/*!
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{  
    /* configure the TIMER peripheral */
    timer2_init();

    while(1)
    {

    }
} 是不是很简单,这里进行了PWM初始化,最核心的就是timer2_init()函数,其代码如下:

/* Includes*********************************************************************/
#include "gd32vf103r_timx_start.h"


/*
    brief      configure PWM GPIO
    param[in]  none
    param[out] none
    retval     none
*/
static void timer_gpio_init(void)
{
    /* enable the GPIOA clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* configure GPIOA port */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

    /* enable the GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);

    /* configure GPIOB port */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
}

/*
    brief      configure the TIMER peripheral
    param[in]  none
    param[out] none
    retval     none
  */
void timer2_init(void)
{
    /* TIMER2 configuration: generate PWM signals with different duty cycles */
    /* 定义一个定时器初始化结构体 */
    timer_parameter_struct timer_init_struct;
    /* 定义一个定时器输出比较参数结构体*/
    timer_oc_parameter_struct timer_oc_init_struct;

        /* PWM信号电平跳变值 */
    uint16_t CH0CV_Val = 250;
    uint16_t CH2CV_Val = 500;

    /* -----------------------------------------------------------------------
    TIMER2 Channel0 duty cycle = (TIMER2_CH0CV/ TIMER2_CAR+1)* 100% = 25%
    TIMER2 Channel2 duty cycle = (TIMER2_CH2CV/ TIMER2_CAR+1)* 100% = 50%
    ----------------------------------------------------------------------- */
    // gpio init
    timer_gpio_init();

      //Enable TIMER2 clock
    rcu_periph_clock_enable(RCU_TIMER2);
    /* 开启复用功能时钟 */
    rcu_periph_clock_enable(RCU_AF);

    timer_deinit(TIMER2);

    /* TIMER2 configuration */
    timer_init_struct.prescaler         = 0;
    timer_init_struct.alignedmode       = TIMER_COUNTER_EDGE;
    timer_init_struct.counterdirection  = TIMER_COUNTER_UP;
    timer_init_struct.period            = 999;
    timer_init_struct.clockdivision     = TIMER_CKDIV_DIV1;
    timer_init_struct.repetitioncounter = 0;
    timer_init(TIMER2, &timer_init_struct);

    /* PWM初始化 */
    timer_oc_init_struct.outputstate  = TIMER_CCX_ENABLE;       /* 通道使能 */
    timer_oc_init_struct.outputnstate = TIMER_CCXN_DISABLE;     /* 通道互补输出使能(定时器2无效) */
    timer_oc_init_struct.ocpolarity   = TIMER_OC_POLARITY_HIGH; /* 通道极性 */
    timer_oc_init_struct.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;/* 互补通道极性(定时器2无效)*/
    timer_oc_init_struct.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;/* 通道空闲状态输出(定时器2无效)*/
    timer_oc_init_struct.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;/*互补通道空闲状态输出(定时器2无效) */

    /* PWM Mode configuration: Channel0 */
    timer_channel_output_config(TIMER2, TIMER_CH_0, &timer_oc_init_struct);

    /* 通道0占空比设置 */
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, CH0CV_Val);
    /* PWM模式0 */
    timer_channel_output_mode_config(TIMER2,TIMER_CH_0,TIMER_OC_MODE_PWM0);
    /* 不使用输出比较影子寄存器 */
    timer_channel_output_shadow_config(TIMER2,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);

    /* PWM Mode configuration: Channel1 */
    timer_channel_output_config(TIMER2, TIMER_CH_2, &timer_oc_init_struct);

    /* 通道2占空比设置 */
    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_2, CH2CV_Val);
    /* PWM模式0 */
    timer_channel_output_mode_config(TIMER2,TIMER_CH_2,TIMER_OC_MODE_PWM0);
    /* 不使用输出比较影子寄存器 */
    timer_channel_output_shadow_config(TIMER2,TIMER_CH_2,TIMER_OC_SHADOW_DISABLE);

    /* 自动重装载影子比较器使能 */
    timer_auto_reload_shadow_enable(TIMER2);

    /* TIMER2 enable */
    timer_enable(TIMER2);
}
2.2 PWM周期、占空比分析根据前面的参数配置,我们可以算出PWM的输出周期:
PWM=1/(Tclk/(psc+1))*(arr+1)

                              这里我们 arr=999  psc=0 Tclk=108Mhz ,
PWM=1/(108Mhz/(1))*(999+1)=1/108ms

因此PWM的输出频率108KHz,周期是9.26us。
PWM的占空比为:
Dutycycle=(CHxCV/CAR+1)* 100%
PWM自动重装值为999,2个通道的跳变值分别为250,500。因此,TIMER2的2个通道的占空比分别为25%,50%。 3 PWM输出的实验现象在前面我们输出了TIM3 的通道  0(PA6)、2(PB0)不同占空比的 PWM 信号。接下来就看看PWM的输出,PWM 信号可以通过示波器看到,下面笔者就是用逻辑分析仪查看波形。
首先笔者使用的逻辑分析仪是Kingst LA5016,当然啦,其他的也可以,关于逻辑分析仪的相关使用笔者这里就不介绍了,可以查看官方资料。
首先将通道 0(PA6)、2(PB0)分别接到逻辑分析仪的CH0 – CH3,然后下载程序到板子中,打开Kingst VIS,然后进行采样。
20220521-2.png
我们就可以看到不同通道的实际周期,占空比等信息。


20220521-3.png

更多回帖

发帖
×
20
完善资料,
赚取积分