[牛人杂谈] PWM 初始化

[复制链接]
3391|17
 楼主| mintspring 发表于 2016-5-15 12:16 | 显示全部楼层 |阅读模式
PWM就是脉冲宽度调制。说白了就是可以输出波形,波形的频率、高电平宽度/低电平宽度都可以调节。PWMIP的功能很多,除了输出基本的波形,还能捕获、输出互补的波形、中心对齐的波形或者触发ADC进行采样,以及刹车等等功能。
新唐芯片的PWM有的多达24路,频率可以到100M或者更高。
下面的demo,只demo简单的PWM输出波形的功能。从PWM0的通道0输出100HZ的波形,高电平占30%。要使用更复杂的功能,需要详细研读TRM(技术参考手册)
  1. int32_t PWM_init (void)
  2. {
  3.     /* 使能PWM0通道0/1的时钟 */
  4. CLK_EnableModuleClock(PWM0_CH01_MODULE);
  5. /* PWM0 IP选择HCLK作时钟源 */
  6. CLK_SetModuleClock(PWM0_CH01_MODULE, CLK_CLKSEL1_PWM0_CH01_S_HCLK, 0);

  7.     /* 配置 PB8 和 PB9用作PWM0的通道0和通道1 */
  8.     SYS->PB_H_MFP = (SYS->PB_H_MFP & ~(SYS_PB_H_MFP_PB8_MFP_Msk | SYS_PB_H_MFP_PB9_MFP_Msk))
  9. | SYS_PB_H_MFP_PB8_MFP_PWM0_CH0 | SYS_PB_H_MFP_PB9_MFP_PWM0_CH1;

  10.     /* PWM0 frequency is 100Hz, duty 30% */
  11.     PWM_ConfigOutputChannel(PWM0, 0, 100, 30);
  12.     /* 使能PWM0的通道0输出功能 */
  13.     PWM_EnableOutput(PWM0, PWM_CH_0_MASK);
  14. /* 开始输出波形 */
  15.     PWM_Start(PWM0, PWM_CH_0_MASK);

  16.     while(1);
  17. }
之后从PB8就会量到100HZ的波形,占空比30%。


 楼主| mintspring 发表于 2016-5-15 12:16 | 显示全部楼层
函数PWM_ConfigOutputChannel(PWM0, 0, 100, 30); 通过修改下面四个寄存器实现功能


²  PWM0 选择 HCLK 做时钟源,假设 HCLK工作在 32M,预分频之后 PWM0 频率=32M/32=1M
PWM0->PRES= (PWM0->PRES&~PWM_PRES_CP01_Msk) | 0x1F;//divided by (CP01 + 1)
PWM0->CLKSEL= PWM_CLK_DIV_1<<PWM_CLKSEL_CLKSEL0_Pos;//通道0输入时钟再
         除以1                                                                                                                        
²  PWM0 Timer 0 工作在连续模式 ,将会连续输出 PWM 波形
PWM0->CTL = PWM_CTL_CH0MOD_Msk;//continuousmode
²  设置频率和占空比。频率=1M/10000 = 100HZ,总共计数 10000,duty 时间占 3000*/
PWM0->DUTY0 = 3000<<PWM_DUTY0_CM_Pos| 10000;

 楼主| mintspring 发表于 2016-5-15 12:17 | 显示全部楼层
我觉得直接修改寄存器更有弹性,不过就是要熟悉这四个寄存器。
²  PRES就是 PWM的预分频寄存器。PWM的时钟源经过 PRES预分频之后传给 PWM0的
CLKSEL 寄存器
²  PWM0的 CLKSEL可以再次进行分频,所以 PWM可以输出很慢的频率
²  CTL寄存器用于设定 PWMTimer 工作在 one-shot模式还是连续模式,以及波形是否要反转等等
²  DUTY寄存器用于设定 PWM输出波形的频率和占空比

cowboy2014 发表于 2016-5-15 22:26 | 显示全部楼层
芯片手册里面怎么知道用哪个GPIO可以输出PWM呢?
zhcxq 发表于 2016-5-19 10:39 | 显示全部楼层
假设PWM分辩率为256级,能输出的最高频率是多少?
500days 发表于 2016-5-20 20:54 | 显示全部楼层
用GPIO模拟的PWM和硬件PWM主要差在什么地方呢
捉虫天师 发表于 2016-5-20 22:44 | 显示全部楼层
PWMIP的功能很多,除了输出基本的波形,还能捕获、输出互补的波形、中心对齐的波形或者触发ADC进行采样,以及刹车等等功能。
xidaole 发表于 2016-5-21 15:54 | 显示全部楼层
PWMIP   如何触发ADC进行采样?
wahahaheihei 发表于 2016-5-21 16:08 | 显示全部楼层
/* PWM0 frequency is 100Hz, duty 30% */
    PWM_ConfigOutputChannel(PWM0, 0, 100, 30);
这个有4个参数,第一个,是选择哪个发生器,第二个选择通道号,第三个和第四个分母分子
天灵灵地灵灵 发表于 2016-5-21 23:32 | 显示全部楼层
新唐芯片的PWM有的多达24路,频率可以到100M或者更高。
 楼主| mintspring 发表于 2016-5-24 21:12 | 显示全部楼层
天灵灵地灵灵 发表于 2016-5-21 23:32
新唐芯片的PWM有的多达24路,频率可以到100M或者更高。

24路够你随便用了,应该是没有胜任不了的场合。
killer2014 发表于 2016-5-25 14:49 | 显示全部楼层
参考BSP里面的DEMO配置就可以啦, 我都用过了。
 楼主| mintspring 发表于 2016-6-12 11:13 | 显示全部楼层
不掰着手册做几遍,你是真不熟练。
wahahaheihei 发表于 2016-6-12 17:47 | 显示全部楼层
PWM就是脉冲宽度调制,也就是占空比可变的脉冲波形.
脉冲宽度调制是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。
wahahaheihei 发表于 2016-6-12 17:48 | 显示全部楼层
PWM控制技术就是对半导体开关器件的导通和关断进行控制,使输出端得到一系列幅值相等而宽度不相等的脉冲,用这些脉冲来代替正弦波或其他所需要的波形。按一定的规则对各脉冲的宽度进行调制,既可改变逆变电路输出电压的大小,也可改变输出频率。
wahahaheihei 发表于 2016-6-12 17:50 | 显示全部楼层
电流跟踪型PWM变流电路就是对变流电路采用电流跟踪控制。也就是,不用信号波对载波进行调制,而是把希望输出的电流作为指令信号,把实际电流作为反馈信号,通过二者的瞬时值比较来决定逆变电路各功率器件的通断,使实际的输出跟踪电流的变化。采用滞环比较方式的电流跟踪型变流器的特点:
①硬件电路简单;
②属于实时控制方式,电流响应快;
③不用载波,输出电压波形中不含特定频率的谐波分量;
④与计算法和调制法相比,相同开关频率时输出电流中高次谐波含量较多;
⑤采用闭环控制.
wahahaheihei 发表于 2016-6-12 17:51 | 显示全部楼层
若令频率不变,直接改变脉冲的宽度,亦即控制开关元件的导通时间;比如现在是高电平导通,那么方波的A越大,B越小,导通时间就长;否则就越短。
 楼主| mintspring 发表于 2016-6-13 21:38 | 显示全部楼层
新唐M051 pwm使用程序
  1. #include "PWM.h"
  2. #define EN_EXT_OSC       0
  3. #define COMPLEMENT_MODE         0x00000020
  4. #define DEAD_ZONE_INTERVAL      0xC8FF0000
  5. #define PWM_ENABLE              0x01010101

  6. #if     EN_EXT_OSC
  7. #define PWM_CLOCK_SOURCE        0x00000000  //使用外部振荡12MHz
  8. #else  
  9. #define PWM_CLOCK_SOURCE        0xF0000000  //使用内部RC振荡22.1184MHz
  10. #endif
  11. #define PWM_PRESCALAE           0x0000C731  //PWM01预分频0x31(49),PWM23预分频0xC7(199)
  12. #define PWM_CLOCK_DIVIDER       0x00004444  //输入时钟分频1
  13. #define PWM_OUTPUT_INVERT       0x00040000
  14. #define PWM_OUTPUT_ENABLE       0x0000000F   //PWM0、1、2、3输出使能
  15. #define PWM_CMR_VALUE   0x0
  16. #define PWM_CNR_VALUE       0x1000      //4096
  17. /*
  18. PWM频率=PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1)
  19. (1)使用外部晶振12MHz
  20. PWM频率=12000000/(49+1)*4097 =58.57Hz
  21. (2)使用内部RC振荡22.1184MHz
  22. PWM频率=22118400/(49+1)*4097 =107.97Hz
  23. */
  24. #define LED_DARKING             0
  25. #define LED_BRIGHTING   1
  26. STATIC UINT32 g_unPWMCMRValue=PWM_CNR_VALUE;
  27. STATIC UINT32 g_unLedStat=LED_DARKING;
  28. /****************************************
  29. *函数名称:PWMInit
  30. *输    入:无
  31. *输    出:无
  32. *功    能:PWM初始化
  33. ******************************************/
  34. VOID PWMInit(VOID)
  35. {
  36.     P2_MFP |= ~(P20_AD8_PWM0 | P21_AD9_PWM1 | P22_AD10_PWM2 | P23_AD11_PWM3);
  37. P2_MFP |= (PWM0 | PWM1 | PWM2 | PWM3);   //使能P2.0~P2.3为PWM输出   
  38.     P2_PMD &= ~Px0_PMD;                       //配置P2.0~P2.3为推挽输出
  39. P2_PMD |= Px0_OUT;
  40. P2_PMD &= ~Px1_PMD;
  41. P2_PMD |= Px1_OUT;
  42. P2_PMD &= ~Px2_PMD;
  43. P2_PMD |= Px2_OUT;
  44. P2_PMD &= ~Px3_PMD;
  45. P2_PMD |= Px3_OUT;
  46.     APBCLK |= PWM01_CLKEN | PWM23_CLKEN;                        //使能PWM0~3时钟
  47. CLKSEL1 = PWM_CLOCK_SOURCE;                 //选择PWM0~3时钟源
  48.    
  49. PPRA = PWM_PRESCALAE | DEAD_ZONE_INTERVAL;                  //选择PWM0~3时钟预分频和死区间隔
  50.     CSRA = PWM_CLOCK_DIVIDER;                                   //选择PWM0~3时钟分频
  51.     PCRA = 0x08080808 | PWM_OUTPUT_INVERT | COMPLEMENT_MODE;    //PWM0~3自动重装载
  52.     CNR0A = CNR1A = CNR2A = CNR3A = PWM_CNR_VALUE;              //PWM0~3计数值
  53.     CMR0A = CMR1A = CMR2A = CMR3A = PWM_CMR_VALUE;              //PWM0~3比较值
  54.     PIERA  |= PWMIE3 | PWMIE2 | PWMIE1 | PWMIE0 ;    //使能PWM0~3中断
  55.     NVIC_ISER |= PWMA_INT;                                      //使能PWM0~3中断
  56.     POEA = PWM_OUTPUT_ENABLE;                                   //PWM输出使能
  57.     PCRA |= PWM_ENABLE;                                         //PWM使能,启动
  58. }
  59. /****************************************
  60. *函数名称:PWMA_IRQHandler
  61. *输    入:无
  62. *输    出:无
  63. *功    能:中断服务函数-PWMA
  64. ******************************************/
  65. VOID PWMA_IRQHandler(VOID)
  66. {
  67.   switch(g_unLedStat)            //检查LED状态
  68.   {
  69.    case  LED_DARKING:         //LED状态渐暗
  70.   {
  71.     if(g_unPWMCMRValue < PWM_CNR_VALUE)
  72.     {
  73.      g_unPWMCMRValue+=50;
  74.     }
  75.     else
  76.     {
  77.        g_unLedStat = LED_BRIGHTING;
  78.      g_unPWMCMRValue=PWM_CNR_VALUE;
  79.     }  
  80.   }break;
  81.   case  LED_BRIGHTING:         //LED状态渐亮
  82.   {
  83.     if(g_unPWMCMRValue>=50)
  84.     {
  85.      g_unPWMCMRValue-=50;
  86.     }
  87.     else
  88.     {
  89.        g_unLedStat = LED_DARKING;
  90.      g_unPWMCMRValue=PWM_CMR_VALUE;   
  91.     }
  92.   }break;
  93.   default:break;  
  94.   }
  95.   CMR0A = CMR1A = CMR2A = CMR3A = g_unPWMCMRValue;  //设置PWM0~3比较值
  96.      PIIRA = PIIRA;                           
  97. }
  98. /****************************************
  99. *函数名称:main
  100. *输    入:无
  101. *输    出:无
  102. *功    能:函数主体
  103. ******************************************/
  104. INT32 main(VOID)
  105. {
  106.    PROTECT_REG                         //ISP下载时保护FLASH存储器
  107.   (
  108.    PWRCON |= XTL12M_EN;                   //默认时钟源为外部晶振
  109.    while((CLKSTATUS & XTL12M_STB) == 0);                //等待12MHz时钟稳定  
  110.    CLKSEL0 = (CLKSEL0 & (~HCLK)) | HCLK_12M;              //设置外部晶振为系统时钟
  111.    PWMInit();              //PWM初始化
  112.   )
  113.      while(1);
  114. }



您需要登录后才可以回帖 登录 | 注册

本版积分规则

303

主题

4972

帖子

24

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