[DemoCode下载] 使用 PWM 生成具有可变占空比的波形

[复制链接]
803|7
 楼主| 捉虫天师 发表于 2024-1-24 23:05 | 显示全部楼层 |阅读模式
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
  4. * $Revision: 4 $
  5. * $Date: 20/07/02 5:46p $
  6. * @brief
  7. *           Change duty cycle of output waveform by configured period.
  8. *
  9. * SPDX-License-Identifier: Apache-2.0
  10. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2020 Nuvoton Technology Corp. All rights reserved.
  11. ******************************************************************************/
  12. #include <stdio.h>
  13. #include "NuMicro.h"

  14. /*---------------------------------------------------------------------------------------------------------*/
  15. /* Global variables                                                                                        */
  16. /*---------------------------------------------------------------------------------------------------------*/


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

  18. /**
  19. * [url=home.php?mod=space&uid=247401]@brief[/url]       PWM0 IRQ Handler
  20. *
  21. * @param       None
  22. *
  23. * [url=home.php?mod=space&uid=266161]@return[/url]      None
  24. *
  25. * [url=home.php?mod=space&uid=1543424]@Details[/url]     ISR to handle PWM0 interrupt event
  26. */
  27. void PWM0_IRQHandler(void)
  28. {
  29. }

  30. void SYS_Init(void)
  31. {

  32.     /* Unlock protected registers */
  33.     SYS_UnlockReg();

  34.     /*---------------------------------------------------------------------------------------------------------*/
  35.     /* Init System Clock                                                                                       */
  36.     /*---------------------------------------------------------------------------------------------------------*/
  37.     /* Enable HIRC clock */
  38.     CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

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

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

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

  45.     /* Enable UART peripheral clock */
  46.     CLK_EnableModuleClock(UART0_MODULE);

  47.     /* Enable PWM0 module clock */
  48.     CLK_EnableModuleClock(PWM0_MODULE);

  49.     /* Reset PWM0 module */
  50.     SYS_ResetModule(PWM0_RST);

  51.     /* Update System Core Clock */
  52.     SystemCoreClockUpdate();

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

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

  63. /**
  64. * @brief       Calculate the comparator value of new duty by configured period
  65. *
  66. * @param       pwm                  The pointer of the specified PWM module
  67. *
  68. * @param       u32ChannelNum        PWM channel number. Valid values are between 0~5
  69. *
  70. * @param       u32DutyCycle         Target generator duty cycle percentage. Valid range are between 0 ~ u32CycleResolution.
  71. *                                   If u32CycleResolution is 100, and u32DutyCycle is 10 means 10%, 20 means 20% ...
  72. *
  73. * @param       u32CycleResolution   Target generator duty cycle resolution. The value in general is 100.
  74. *
  75. * @return      The compatator value by new duty cycle
  76. */
  77. uint32_t CalNewDutyCMR(PWM_T *pwm, uint32_t u32ChannelNum, uint32_t u32DutyCycle, uint32_t u32CycleResolution)
  78. {
  79. //    return (u32DutyCycle * (PWM_GET_CNR(pwm, u32ChannelNum) + 1) / u32CycleResolution);
  80.     return (u32DutyCycle * (PWM_GET_CNR(pwm, u32ChannelNum)) / u32CycleResolution);
  81. }

  82. /*---------------------------------------------------------------------------------------------------------*/
  83. /*  Main Function                                                                                          */
  84. /*---------------------------------------------------------------------------------------------------------*/
  85. int32_t main(void)
  86. {
  87.     uint8_t  u8Option;
  88.     uint32_t u32NewCMR = 0;

  89.     /* Unlock protected registers */
  90. //    SYS_UnlockReg();

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

  93.     /* Lock protected registers */
  94.     SYS_LockReg();

  95.     /* Reset UART module */
  96.     SYS_ResetModule(UART0_RST);

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

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

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

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

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

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

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

  122.     while(1)
  123.     {
  124.         printf("\nSelect new duty: \n");
  125.         printf("[1] 100%% \n");
  126.         printf("[2] 75%% \n");
  127.         printf("[3] 25%% \n");
  128.         printf("[4] 0%% \n");
  129.         printf("[Other] Exit \n");
  130.         u8Option = getchar();

  131.         if(u8Option == '1')
  132.         {
  133.             u32NewCMR = PWM_GET_CNR(PWM0, 0) + 1;
  134.         }
  135.         else if(u8Option == '2')
  136.         {
  137.             u32NewCMR = PWM_GET_CNR(PWM0, 0);
  138.             u32NewCMR = u32NewCMR * (100-75)/100;
  139.         }
  140.         else if(u8Option == '3')
  141.         {
  142.             u32NewCMR = PWM_GET_CNR(PWM0, 0);
  143.             u32NewCMR = u32NewCMR * (100-25)/100;
  144.         }
  145.         else if(u8Option == '4')
  146.         {
  147.             u32NewCMR = PWM_GET_CNR(PWM0, 0);
  148.         }
  149.         else
  150.         {
  151.             printf("Exit\n");
  152.             break;
  153.         }
  154.         /* Set new comparator value to register */
  155.         PWM_SET_CMR(PWM0, 0, u32NewCMR);
  156.     }

  157.     /* Stop PWM counter */
  158.     PWM_Stop(PWM0, PWM_CH_0_MASK);
  159.     /* Disable output of PWM0 channel 0 */
  160.     PWM_DisableOutput(PWM0, PWM_CH_0_MASK);

  161.     while(1);

  162. }


 楼主| 捉虫天师 发表于 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 输出的脉冲宽度。
冬天下雪 发表于 2024-1-25 11:34 | 显示全部楼层
这种可变占空比的应用场景是什么呢?
勇敢的大白菜 发表于 2024-1-25 11:38 | 显示全部楼层
冬天下雪 发表于 2024-1-25 11:34
这种可变占空比的应用场景是什么呢?

一般在灯光显示的环境。
小明的同学 发表于 2024-1-28 19:40 | 显示全部楼层
PWM_SET_CMR(PWM0, 0, u32NewCMR);
其实就是修改这个函数参数。
埃娃 发表于 2024-1-29 10:17 来自手机 | 显示全部楼层
调节占空比可以调节亮度
您需要登录后才可以回帖 登录 | 注册

本版积分规则

216

主题

3284

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部