打印
[DemoCode下载]

使用 PWM 生成具有可变占空比的波形

[复制链接]
179|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
捉虫天师|  楼主 | 2024-1-24 23:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
* $Revision: 4 $
* $Date: 20/07/02 5:46p $
* @brief
*           Change duty cycle of output waveform by configured period.
*
* SPDX-License-Identifier: Apache-2.0
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2020 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#include <stdio.h>
#include "NuMicro.h"

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/


uint32_t CalNewDutyCMR(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32DutyCycle, uint32_t u32CycleResolution);

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]       PWM0 IRQ Handler
*
* @param       None
*
* [url=home.php?mod=space&uid=266161]@return[/url]      None
*
* [url=home.php?mod=space&uid=1543424]@Details[/url]     ISR to handle PWM0 interrupt event
*/
void PWM0_IRQHandler(void)
{
}

void SYS_Init(void)
{

    /* Unlock protected registers */
    SYS_UnlockReg();

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Enable HIRC clock */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Waiting for HIRC clock ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Switch HCLK clock source to HIRC and HCLK source divide 1 */
    CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));

    /* Select HIRC as the clock source of UART0 */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));

    /* Enable UART peripheral clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Enable PWM0 module clock */
    CLK_EnableModuleClock(PWM0_MODULE);

    /* Reset PWM0 module */
    SYS_ResetModule(PWM0_RST);

    /* Update System Core Clock */
    SystemCoreClockUpdate();

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set PB multi-function pins for UART0 RXD=PB.6 and TXD=PB.4 */
    SYS->GPB_MFP1 = (SYS->GPB_MFP1 & ~(SYS_GPB_MFP1_PB4MFP_Msk | SYS_GPB_MFP1_PB6MFP_Msk)) |        \
                    (SYS_GPB_MFP1_PB4MFP_UART0_TXD | SYS_GPB_MFP1_PB6MFP_UART0_RXD);

    /* Set PB multi-function pins for PWM0 Channel 0 */
    SYS->GPB_MFP1 = (SYS->GPB_MFP1 & (~SYS_GPB_MFP1_PB5MFP_Msk)) |
                    SYS_GPB_MFP1_PB5MFP_PWM0_CH0;
}

/**
* @brief       Calculate the comparator value of new duty by configured period
*
* @param       pwm                  The pointer of the specified PWM module
*
* @param       u32ChannelNum        PWM channel number. Valid values are between 0~5
*
* @param       u32DutyCycle         Target generator duty cycle percentage. Valid range are between 0 ~ u32CycleResolution.
*                                   If u32CycleResolution is 100, and u32DutyCycle is 10 means 10%, 20 means 20% ...
*
* @param       u32CycleResolution   Target generator duty cycle resolution. The value in general is 100.
*
* @return      The compatator value by new duty cycle
*/
uint32_t CalNewDutyCMR(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32DutyCycle, uint32_t u32CycleResolution)
{
//    return (u32DutyCycle * (PWM_GET_CNR(pwm, u32ChannelNum) + 1) / u32CycleResolution);
    return (u32DutyCycle * (PWM_GET_CNR(pwm, u32ChannelNum)) / u32CycleResolution);
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Main Function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
    uint8_t  u8Option;
    uint32_t u32NewCMR = 0;

    /* Unlock protected registers */
//    SYS_UnlockReg();

    /* Init System, IP clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS_LockReg();

    /* Reset UART module */
    SYS_ResetModule(UART0_RST);

    /* Configure UART0 and set UART0 baud rate */
    UART_Open(UART0, 115200);

    printf("+-----------------------------------------------------------------------------------+\n");
    printf("|                          PWM Driver Sample Code                                   |\n");
    printf("|                                                                                   |\n");
    printf("+-----------------------------------------------------------------------------------+\n");
    printf("  This sample code will use PWM0 channel 0 to output waveform, and switch duty cycle.\n");
    printf("  I/O configuration:\n");
    printf("    waveform output pin: PWM0 channel 0(PB.5)\n");
    printf("\nOutput waveform is 1200 Hz and it's duty is 50%.\n");

    /*
      Configure PWM0 channel 0 init period and duty(up counter type).
      Period is HIRC / (prescaler * (CNR + 1))
      Duty ratio = (CMR) / (CNR + 1)
      Period = 48 MHz / (1 * (39,999 + 1)) = 1200 Hz
      Duty ratio = (40,000) / (19,999 + 1) = 50%
    */

    /* PWM0 channel 0 frequency is 1200 Hz, duty 50%, */
    PWM_ConfigOutputChannel(PWM0, 0, 1200, 50);

    /* Enable output of PWM0 channel 0 */
    PWM_EnableOutput(PWM0, PWM_CH_0_MASK);

    /* ZeroLevel: High, CmpUpLevel: nothing, PeriodLevel: nothing, CmpDownLevel: Low */
    PWM_SET_OUTPUT_LEVEL(PWM0, PWM_CH_0_MASK, PWM_OUTPUT_NOTHING, PWM_OUTPUT_NOTHING, PWM_OUTPUT_HIGH, PWM_OUTPUT_LOW);

    /* Start PWM counter */
    PWM_Start(PWM0, PWM_CH_0_MASK);

    while(1)
    {
        printf("\nSelect new duty: \n");
        printf("[1] 100%% \n");
        printf("[2] 75%% \n");
        printf("[3] 25%% \n");
        printf("[4] 0%% \n");
        printf("[Other] Exit \n");
        u8Option = getchar();

        if(u8Option == '1')
        {
            u32NewCMR = PWM_GET_CNR(PWM0, 0) + 1;
        }
        else if(u8Option == '2')
        {
            u32NewCMR = PWM_GET_CNR(PWM0, 0);
            u32NewCMR = u32NewCMR * (100-75)/100;
        }
        else if(u8Option == '3')
        {
            u32NewCMR = PWM_GET_CNR(PWM0, 0);
            u32NewCMR = u32NewCMR * (100-25)/100;
        }
        else if(u8Option == '4')
        {
            u32NewCMR = PWM_GET_CNR(PWM0, 0);
        }
        else
        {
            printf("Exit\n");
            break;
        }
        /* Set new comparator value to register */
        PWM_SET_CMR(PWM0, 0, u32NewCMR);
    }

    /* Stop PWM counter */
    PWM_Stop(PWM0, PWM_CH_0_MASK);
    /* Disable output of PWM0 channel 0 */
    PWM_DisableOutput(PWM0, PWM_CH_0_MASK);

    while(1);

}


使用特权

评论回复
沙发
捉虫天师|  楼主 | 2024-1-24 23:06 | 只看该作者
这个程序是一个用于演示单片机的 PWM(脉冲宽度调制)功能的示例代码,该单片机可能来自 Nuvoton Technology Corp。

头文件和定义
头文件: 代码包含了必要的头文件,包括 stdio.h 和 Nuvoton 单片机库(NuMicro.h)。
全局变量: 有一个全局变量 u32NewCMR 用于存储 PWM 的新比较器值。
SYS_Init 函数
SYS_Init 函数: 此函数初始化系统,配置时钟(使用 HIRC - 高速内部 RC 振荡器),设置 UART 和 PWM 模块。
PWM0_IRQHandler 函数
PWM0_IRQHandler 函数: 这是 PWM0 的空中断服务例程(ISR)。目前未执行任何操作。
CalNewDutyCMR 函数
CalNewDutyCMR 函数: 此函数根据所需的占空比、通道编号和周期分辨率计算新的比较器值,并返回计算结果。

使用特权

评论回复
板凳
捉虫天师|  楼主 | 2024-1-24 23:06 | 只看该作者
main 函数: 主函数是程序核心逻辑的所在。
初始化: 执行系统初始化,包括设置时钟源、配置 PWM 和 UART,并通过 UART 打印一些信息。
PWM 配置: 配置 PWM0 通道 0 的频率和占空比,启用 PWM 输出。
用户输入循环: 进入一个循环,通过 UART 接收用户输入,根据输入设置新的比较器值,然后将其应用于 PWM。
停止 PWM: 用户输入退出后,停止 PWM 计数器并禁用 PWM 输出。

使用特权

评论回复
地板
捉虫天师|  楼主 | 2024-1-24 23:06 | 只看该作者
该程序的主要目的是演示如何使用 PWM 生成具有可变占空比的波形。用户可以通过输入选择不同的占空比,从而改变 PWM 输出的脉冲宽度。

使用特权

评论回复
5
冬天下雪| | 2024-1-25 11:34 | 只看该作者
这种可变占空比的应用场景是什么呢?

使用特权

评论回复
6
勇敢的大白菜| | 2024-1-25 11:38 | 只看该作者
冬天下雪 发表于 2024-1-25 11:34
这种可变占空比的应用场景是什么呢?

一般在灯光显示的环境。

使用特权

评论回复
7
小明的同学| | 2024-1-28 19:40 | 只看该作者
PWM_SET_CMR(PWM0, 0, u32NewCMR);
其实就是修改这个函数参数。

使用特权

评论回复
8
埃娃| | 2024-1-29 10:17 | 只看该作者
调节占空比可以调节亮度

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

183

主题

3012

帖子

7

粉丝