xld0932 发表于 2024-2-1 10:56

【小华工控新品HC32F448】05.通过单缓存实现TIMER6输出不同PWM占空比功能

<div class='showpostmsg'> 本帖最后由 xld0932 于 2024-2-1 11:32 编辑

<p><strong>1.概述</strong></p>

<p>小华HC32F448系列MCU带有一个高级控制定时器 6(Timer6)外设,它是一个 16 位计数宽度的高性能定时器,能在各种复杂应用场景中提供丰富、灵活的搭配组合和各种中断、事件、 PWM 输出。该定时器支持锯齿波和三角波两种波形模式,可生成各种 PWM 波形(单边对齐独立 PWM、双边对称独立 PWM、双边对称互补 PWM、双边非对称 PWM等);单元间可实现软件同步和硬件同步(同步启动、停止、清零、刷新等);各基准值寄存器支持缓存功能(单级缓存和双级缓存);支持脉宽测量和周期测量;支持 2 相正交编码计数和 3 相正交编码计数;支持 EMB 控制。</p>

<p>&nbsp;</p>

<p><strong>2.功能框图</strong></p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p><strong>3.例程功能</strong></p>

<p>3.1.我们参考官方的示例程序,结合EV_F448_LQ80_Rev1.0开发板,通过TIMER6的PWM三角波模式,通过单缓存输出占空比动态配置的功能</p>

<p>&nbsp;</p>

<p>3.2.示例程序</p>

<pre>
<code class="language-cpp">#define EXAMPLE_PERIPH_WE               (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM)
#define EXAMPLE_PERIPH_WP               (LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_SRAM)

#define TMR6_1_PWMA_PORT                (GPIO_PORT_A)
#define TMR6_1_PWMA_PIN               (GPIO_PIN_08)
#define TMR6_1_PWMA_FUNC                (GPIO_FUNC_3)
#define TMR6_1_PWMB_PORT                (GPIO_PORT_A)
#define TMR6_1_PWMB_PIN               (GPIO_PIN_07)
#define TMR6_1_PWMB_FUNC                (GPIO_FUNC_3)

#define PWM_PERIODVALUE               (3125U)

static uint8_tu8Duty_pos    = 1U;
static uint16_t au16Cmp_buf[] = {PWM_PERIODVALUE/10, PWM_PERIODVALUE/10, 0, PWM_PERIODVALUE/10, PWM_PERIODVALUE/10, PWM_PERIODVALUE};

static void Duty_Set(CM_TMR6_TypeDef *TMR6x, uint32_t u32Index, uint16_t cmp_value)
{
    if (TMR6_GetCompareValue(TMR6x, u32Index) != cmp_value) {
      TMR6_SetCompareValue(TMR6x, u32Index, cmp_value);
      if (cmp_value == 0U) {
            if (u32Index % 2U) {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_DOWN_CNT_MATCH_B, TMR6_PWM_HOLD);
            } else {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_DOWN_CNT_MATCH_A, TMR6_PWM_HOLD);
            }
      } else if (cmp_value == PWM_PERIODVALUE) {
            if (u32Index % 2U) {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_OVF, TMR6_PWM_INVT);
            } else {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_OVF, TMR6_PWM_INVT);
            }
      } else {
            if (u32Index % 2U) {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_OVF, TMR6_PWM_HOLD);
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_B, TMR6_STAT_DOWN_CNT_MATCH_B, TMR6_PWM_HIGH);
            } else {
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_OVF, TMR6_PWM_HOLD);
                TMR6_PWM_SetPolarity(TMR6x, TMR6_CH_A, TMR6_STAT_DOWN_CNT_MATCH_A, TMR6_PWM_HIGH);
            }
      }
    }
}

static void Tmr6_UnderFlow_CallBack(void)
{
    TMR6_ClearStatus(CM_TMR6_1, TMR6_FLAG_UDF);
    Duty_Set(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf);
    Duty_Set(CM_TMR6_1, TMR6_CMP_REG_D, au16Cmp_buf);
    if (++u8Duty_pos &gt;= sizeof(au16Cmp_buf)/sizeof(au16Cmp_buf)) {
      u8Duty_pos = 0;
    }
}

int32_t main(void)
{
    stc_tmr6_init_t stcTmr6Init;
    stc_tmr6_pwm_init_t stcPwmInit;
    stc_irq_signin_config_t stcIrqRegiConf;
    stc_tmr6_buf_config_t stcBufConfig;

    /* Unlock peripherals or registers */
    LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
    /* Configure BSP */
    BSP_CLK_Init();

    (void)TMR6_StructInit(&amp;stcTmr6Init);
    (void)TMR6_PWM_StructInit(&amp;stcPwmInit);
    (void)TMR6_BufFuncStructInit(&amp;stcBufConfig);

    FCG_Fcg2PeriphClockCmd(FCG2_PERIPH_TMR6_1, ENABLE);

    /* Timer6 PWM output port configuration */
    GPIO_SetFunc(TMR6_1_PWMA_PORT, TMR6_1_PWMA_PIN, TMR6_1_PWMA_FUNC);
    GPIO_SetFunc(TMR6_1_PWMB_PORT, TMR6_1_PWMB_PIN, TMR6_1_PWMB_FUNC);

    TMR6_DeInit(CM_TMR6_1);
    /* Timer6 general count function configuration */
    stcTmr6Init.sw_count.u32CountMode = TMR6_MD_TRIANGLE;
    stcTmr6Init.sw_count.u32ClockDiv = TMR6_CLK_DIV32;
    stcTmr6Init.u32PeriodValue = PWM_PERIODVALUE;
    (void)TMR6_Init(CM_TMR6_1, &amp;stcTmr6Init);

    /* General compare buffer function configure */
    stcBufConfig.u32BufNum = TMR6_BUF_SINGLE;
    stcBufConfig.u32BufTransCond = TMR6_BUF_TRANS_OVF;
    (void)TMR6_GeneralBufConfig(CM_TMR6_1, TMR6_CH_A, &amp;stcBufConfig);
    (void)TMR6_GeneralBufConfig(CM_TMR6_1, TMR6_CH_B, &amp;stcBufConfig);
    TMR6_GeneralBufCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);
    TMR6_GeneralBufCmd(CM_TMR6_1, TMR6_CH_B, ENABLE);
    /* Set General Compare RegisterA Value */
    TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf); /* General comprare register C, buffer for GCMAR */
    TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_D, au16Cmp_buf); /* General comprare register D, buffer for GCMBR */

    /* Configure PWM output CHA */
    stcPwmInit.u32CompareValue = au16Cmp_buf;
    stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HIGH;
    stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32UdfPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32OvfPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32StopPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32StartPolarity = TMR6_PWM_LOW;
    (void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_A, &amp;stcPwmInit);
    /* CHB */
    stcPwmInit.u32CompareValue = au16Cmp_buf;
    stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HIGH;
    stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_HOLD;
    (void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_B, &amp;stcPwmInit);
    /* PWM pin function set */
    TMR6_SetFunc(CM_TMR6_1, TMR6_CH_A, TMR6_PIN_CMP_OUTPUT);
    TMR6_SetFunc(CM_TMR6_1, TMR6_CH_B, TMR6_PIN_CMP_OUTPUT);
    /* PWM output command */
    TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);
    TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_B, ENABLE);

    /* Enable interrupt */
    TMR6_IntCmd(CM_TMR6_1, TMR6_INT_UDF, ENABLE);

    stcIrqRegiConf.enIRQn = INT002_IRQn;
    stcIrqRegiConf.enIntSrc = INT_SRC_TMR6_1_UDF;
    stcIrqRegiConf.pfnCallback = &amp;Tmr6_UnderFlow_CallBack;
    (void)INTC_IrqSignIn(&amp;stcIrqRegiConf);
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIO_15);
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);

    /* Start timer6 */
    TMR6_Start(CM_TMR6_1);

    for (;;) {
      ;
    }
}</code></pre>

<p>&nbsp;</p>

<p>3.3.运行结果</p>

<p>我们使用逻辑分析仪来测试PA8和PA7的输出波形,看到PA8(Timer6_1 PWMA)和PA7(Timer6_1 PWMB)输出频率为1KHz(10%-&gt;10%之间的频率),且占空比按照10%-&gt;10%-&gt;0%-&gt;10%-&gt;10%-&gt;100%循环变化。</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p><strong>4.扩展</strong></p>

<p>在3.3中的运行结果是不是有点看不懂,没关系,我们将代码修改一下,如下所示:</p>

<pre>
<code class="language-cpp">static uint16_t au16CmpB_buf[] = {PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2, PWM_PERIODVALUE/2};

static void Tmr6_UnderFlow_CallBack(void)
{
    TMR6_ClearStatus(CM_TMR6_1, TMR6_FLAG_UDF);
    Duty_Set(CM_TMR6_1, TMR6_CMP_REG_C, au16Cmp_buf);
    Duty_Set(CM_TMR6_1, TMR6_CMP_REG_D, au16CmpB_buf);
    if (++u8Duty_pos &gt;= sizeof(au16Cmp_buf)/sizeof(au16Cmp_buf)) {
      u8Duty_pos = 0;
    }
}

int32_t main(void)
{
......
    /* CHB */
    stcPwmInit.u32CompareValue = au16CmpB_buf;
    stcPwmInit.u32CountDownMatchBPolarity = TMR6_PWM_HIGH;
    stcPwmInit.u32CountUpMatchBPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32CountDownMatchAPolarity = TMR6_PWM_HOLD;
    stcPwmInit.u32CountUpMatchAPolarity = TMR6_PWM_HOLD;
    (void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_B, &amp;stcPwmInit);
......
}</code></pre>

<p>&nbsp;</p>

<p>通过上述的修改,这样我们可以把CHB固定在50%输出占空比&hellip;&hellip;运行监测的波形如下所示:</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>为了更好的理解上图中波形的含义,我们需要参考UM手册中19.3.5小节的比较输出功能,19.3.14.2小节中的双边对称独立PWM输出功能,我们可以通过如下图,可以直观理解上图中的输出波形:</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">&nbsp;</div>

<div style="text-align: center;"></div>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Ceph 发表于 2024-9-6 04:25

xhsc
页: [1]
查看完整版本: 【小华工控新品HC32F448】05.通过单缓存实现TIMER6输出不同PWM占空比功能