Q_dGHvwj · 2022年12月14日 · 江苏

【GD32F427开发板试用】FOC矢量算法研究系列之一:PWM实现呼吸灯

前言

有幸被选为此次开发板测评活动的参与者,万分感谢。收到板子后迫不及待的拆来查看,画风整齐美观,简洁的设计,全面含盖了主芯片的所有引脚,测试如需用到引脚,需个人自行焊接排针。本次测评先以一份PWM输出实现呼吸灯的代码开篇,采用定时器实现PWM输出。
呼吸灯,就是指灯光设备的亮度随着时间由暗到亮逐渐增强,再由亮到暗逐渐衰减,很有节奏感地一起一伏,就像是在呼吸一样,被广泛应用在手机、电脑等电子设备的指示中。

一.相关知识介绍

脉冲宽度调制(PWM) :是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。
频率 :时钟速度 1GHZ = 1000MHZ = 1000 000 KHZ =1 000 000 000 HZ(如12MHz:1秒12 000 000个脉冲)
占空比 :占空比是指在一个脉冲循环内,通电时间(有效电平)相对于一个脉冲总时间所占的比例。(可以简单理解为该高、低电平的占脉冲总时间的比例)。

PWM原理如下图所示:
 title=
这就是一个简单的PWM原理示意图。图中,我们假定定时器工作在向上计数PWM模式,且当CNT<CCRx时,输出0,当CNT>=CCRx时输出1。那么就可以得到如上的PWM示意图:当CNT值小于CCRx的时候,IO输出低电平(0),当CNT值大于等于CCRx的时候,IO输出高电平(1),当CNT达到ARR值的时候,重新归零,然后重新向上计数,依次循环。改变CCRx的值,就可以改变PWM输出的占空比,改变ARR的值,就可以改变PWM输出的频率,这就是PWM输出的原理。
查看GD32F4xx系列器件的用户手册,可以发现,其中除了TIM5和6(基本定时器)以外,其他的定时器都可以用来产生PWM输出。这里考虑到板子自带的LED2是接在了PC6引脚上,通过引脚复用功能的重映射配置TIMER2\\_CH0到 PC6上,由TIMER2\\_CH0输出PWM波来控制LED2的亮度,如呼吸一样的闪烁。

二.代码实现

本次以兆易创新库开发的方式进行代码的编写。

1.配置GPIO

本实验使用PC6作为定时器PWM输出通道,先对它进行初始化。用作PWM输出通道的引脚需要被配置为复用推挽输出模式。关于引脚功能复用的介绍详见GD32F427xx\_Datasheet\_Rev1.2这份芯片数据手册的第2.6小节Pin definitions。

/*!
    \brief      configure the GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOC);
    
    /*Configure PC6(TIMER2 CH0) as alternate function*/
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);

    gpio_af_set(GPIOC, GPIO_AF_2, GPIO_PIN_6);
}

2.配置定时器模式

在timer\\_config()函数中,完成了呼吸灯所需要的定时器PWM输出模式配置。

/*!
    \brief      configure the TIMER peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void timer_config(void)
{
    /* -----------------------------------------------------------------------
    TIMER2 configuration: generate 1 PWM signals with variable duty cycles:
    TIMER2CLK = SystemCoreClock / 200 = 1MHz
    ----------------------------------------------------------------------- */
    timer_oc_parameter_struct timer_ocinitpara;
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER2);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);

    timer_deinit(TIMER2);

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

    /* CH0 configuration in PWM mode */
    timer_ocinitpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocinitpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocinitpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;

    timer_channel_output_config(TIMER2,TIMER_CH_0,&timer_ocinitpara);


    /* CH0 configuration in PWM mode1,variable duty cycle*/
    timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,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);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER2);
    /* auto-reload preload enable */
    timer_enable(TIMER2);
}

3.主循环中延时函数5ms的引用

借助演示代码systick.c中的延时函数,来实现精确的5ms延时。
首先引用头文件:

#include "systick.h"

然后即可直接调用systick.c中的系统时钟配置函数systick\_config(),进行系统定时器中断的相关配置。

4.最终主函数逻辑

经过代码的整合,加上循环逻辑,不断的修改PWM波的占空比,就可以实现呼吸灯的效果了。

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    uint16_t i = 0;
    FlagStatus breathe_flag = SET;
    
    gpio_config();
    timer_config();
    systick_config();
    
    while(1)
    {
        /* delay a time in milliseconds */
        delay_1ms(5);
        if(SET == breathe_flag) 
            {
                i++;
            }
        else
            {
                i--;
            }
        if(250 < i)
            {
                breathe_flag = RESET;
            }
        if(0 >= i)
            {
                breathe_flag = SET;
            }
        
        TIMER_CH0CV(TIMER2) = (uint32_t)i;
    }
}

5.最终效果视频展示

https://www.bilibili.com/vide...

三.后续

接下来将回归正题,接着进行FOC矢量算法相关的实验演示,研究SVPWM原理,Park与反Park变换,Clark与反Clark变换等。

推荐阅读
关注数
10711
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息