打印
[Kinetis]

Kinetis系统开发之PWM模块

[复制链接]
727|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Vitality1|  楼主 | 2015-3-28 10:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

  PWM模块,对我们搞过电机控制的算是再熟悉不过了,也算是MCU中最常用的模块之一了,本来PWM模块该算是属于定时器模块范围内的,不过这里由于它应用的太广泛了,索性就单拿出来开一篇,源代码可以从本篇博客下面的附件中下载,下面按照老套路来分步介绍一下Kinetis的PWM模块:

1、Kinetis的PWM模块,是在飞思卡尔已经成熟应用多年的8位单片机上的PWM模块上扩展而来的(即早期的HCS08系列的Timer PWM Module),而以飞思卡尔在汽车电子的老大地位来说,自然其PWM模块的性能是没得说的,毕竟是经过工业现场多年的成熟应用考验过了;

2、Kinetis内部PWM模块的具体特性如下,仍旧是挑了几个重点特色简单介绍一下,当然由于PWM模块属于FTM模块的范围内,所以少不了牵涉到一些定时器的一些特性:

(1)时钟源可选择,FTM的时钟源可以来自系统时钟或外部时钟。可对时钟分频,分频比为1,2,4,8,16,32,64,128,这属于定时器的特性;

(2)最多3个FTM定时器FTM0、FTM1、FTM2,即可以有3个自由计数器,也即可以存在独立的3路PWM模块;

(3)所有的通道都可以设置为中心对齐的PWM输出模式,且某个FTM定时器中的每对通道都可以级联以产生PWM信号;

(4) PWM通道可成对工作在相同输出或互补输出,也可各通道独立输出,当通道成对互补输出时可使用死区插入功能,这对一些全桥控制电路有很大意义,省去了外围死区电路;

(5)可软件控制PWM的输出,即屏蔽或者开启单独某个通道。

3、基本特性介绍完毕,下面就直入主题,开始着手PWM软件驱动的编写,这里就挨个寄存器的介绍了,太麻烦了,这次就直接列出代码,并附带详细的注释,代码风格仍旧采用模块化的概念,参数可选择,大家可以对照着Kinetis的数据手册了解其含义,个人觉着这种方式反而效果更好,呵呵:

(1)PWM初始化函数

/**********************************************************************************
@ Routine:FTM_initPWM
@ Parameter: ftm    FTM模块
                    FTM0
                    FTM1
                    FTM2
              channel PWM通道号
                      FTM0--0~7,FTM1--0~1, FTM2--0~1
              div   时钟分频数
                      000 Divide by 1
                      001 Divide by 2
                      010 Divide by 4
                      011 Divide by 8
                      100 Divide by 16
                      101 Divide by 32
                      110 Divide by 64
                      111 Divide by 128
              polarity 左对齐方式下,
                       0--先低后高
                       1--先高后低
              period  PWM周期
              duty    PWM占空比
                      0 =< duty <= period
@ Description:PWM初始化
**********************************************************************************/
static void FTM_initPWM(FTM_MemMapPtr ftm, uint8 channel, uint8 div, uint8 polarity, uint16 period, uint16 duty)
{
  if(FTM0==ftm)
  {
    SIM_SCGC6 |= SIM_SCGC6_FTM0_MASK;                       /* 使能FTM0时钟 */
  }
  else if(FTM1==ftm)
  {
    SIM_SCGC6 |= SIM_SCGC6_FTM1_MASK;                       /* 使能FTM1时钟 */
  }
  else if(FTM2==ftm)
  {
    SIM_SCGC3 |= SIM_SCGC3_FTM2_MASK;                       /* 使能FTM2时钟 */
  }
  FTM_MODE_REG(ftm) |= FTM_MODE_WPDIS_MASK;                 /* 禁用写保护 */
  if(polarity)
    FTM_CnSC_REG(ftm,channel) = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK)&(~FTM_CnSC_ELSA_MASK);      
                                                            /* (MSB = 1, ELSB:ELSA = 10)左对齐,先高后低 */
  else
    FTM_CnSC_REG(ftm,channel) = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK);
                                                            /* (MSB = 1, ELSB:ELSA = 01)右对齐,先低后高 */
  FTM_COMBINE_REG(ftm) = 0;                                 /* DECAPEN=0,双边沿捕捉禁止,COMBINE=0,不级联 */
  FTM_QDCTRL_REG(ftm) &= ~FTM_QDCTRL_QUADEN_MASK;           /* 设置QUADEN = 0,不使用正交解码 */
  FTM_MODE_REG(ftm) &= ~FTM_MODE_FTMEN_MASK;                /* 使能兼容型TPM,不使用FTM特定的寄存器 */
  FTM_MODE_REG(ftm) |= FTM_MODE_INIT_MASK;                  /* 使能初始化通道输出状态 */
  FTM_OUTINIT_REG(ftm) |= polarity << channel;              /* 根据极性设置初始通道状态 */
  FTM_OUTMASK_REG(ftm) |= (1 << channel);                   /* 禁止channel通道PWM输出 */
  FTM_MOD_REG(ftm) = period - 1;                            /* 计数终值,周期为(MOD-CNTIN+1)*时钟周期 */
  FTM_CNTIN_REG(ftm) = 0;                                   /* 计数初值 */
  FTM_CNT_REG(ftm) = 0;                                     /* 复位FTM计数器为CNTIN */
  FTM_CnV_REG(ftm,channel) = duty;                          /* 设置占空比 */
  FTM_SC_REG(ftm) = (FTM_SC_CLKS(1) | FTM_SC_PS(div)) & (~FTM_SC_CPWMS_MASK);
                                                            /* 选择BusClock时钟分频,CPWMS = 0,即左对齐 */
}

(2)PWM启动函数,注意上面的PWM初始化之后PWM没有输出,需要此部分代码启动已设置好的PWM

/**********************************************************************************
@ Routine:Start_PWM
@ Parameter: ftm   FTM模块
                      FTM0
                      FTM1
                      FTM2
              channel PWM通道号
                      FTM0--0~7,FTM1--0~1, FTM2--0~1  
@ Description:启动PWM
**********************************************************************************/
void Start_PWM(FTM_MemMapPtr ftm, uint8 channel)
{
  FTM_CNT_REG(ftm) = 0;
  FTM_OUTMASK_REG(ftm) &= ~(1 << channel);                   /* 使能channel通道PWM输出 */
}

(3)PWM关闭函数,可以动态关闭PWM通道,关闭之后可以用PWM启动函数重新开启PWM

/**********************************************************************************
@ Routine:Stop_PWM
@ Parameter: ftm   FTM模块
                      FTM0
                      FTM1
                      FTM2
              channel PWM通道号
                      FTM0--0~7,FTM1--0~1, FTM2--0~1  
@ Description:停止PWM
**********************************************************************************/
void Stop_PWM(FTM_MemMapPtr ftm, uint8 channel)
{
  FTM_OUTMASK_REG(ftm) |= (1 << channel);                    /* 禁止channel通道PWM输出 */
}

(4)PWM参数设置函数,PWM初始化之后,也可以通过该函数动态修改PWM参数

/**********************************************************************************
@ Routine:Set_PWM_Parameter
@ Parameter: ftm   FTM模块
                      FTM0
                      FTM1
                      FTM2
              channel PWM通道号
                      FTM0--0~7,FTM1--0~1, FTM2--0~1
              period  PWM周期
              duty    PWM占空比
@ Description:停止PWM
**********************************************************************************/
void Set_PWM_Parameter(FTM_MemMapPtr ftm, uint8 channel,uint16 period, uint16 duty)
{
  FTM_CNT_REG(ftm) = 0;                                     /* 复位FTM计数器为CNTIN */
  FTM_MOD_REG(ftm) = period - 1;                            /* 计数终值,周期为(MOD-CNTIN+1)*时钟周期 */
  FTM_CnV_REG(ftm,channel) = duty;
}

4、驱动编写完毕之后,就可以在主函数内调用各个函数应用PWM功能了,这里给出一个简单的应用,直接放在main函数下即可,具体实现功能为使能FTM0的CH4通道(PWM周期为48KHz、占空比为50%),使能FTM2的CH0通道(PWM周期为40Hz),注意同一个FTM定时器下的多个通道其PWM周期是一样的,所以如果想要得到两种周期的PWM的话就需要使用两个FTM定时器,这点有点不方便。

//insert the port router code
  PORTD_PCR4 = PORT_PCR_MUX(4);         /* 设置引脚PTD4引脚为FTM0_CH4功能 */
  PORTB_PCR18 = PORT_PCR_MUX(3);        /* 设置引脚PTB18引脚为FTM2_CH0功能 */
  //insert your PWM initialization function
  FTM_initPWM(FTM0,4,1,1,500,250);      /* 使能FTM0的CH4通道,2分频Busclk48MHz/2=24MHz,
                                           左对齐,周期为48kHz=24MHz/500,占空比50% */
  FTM_initPWM(FTM2,0,5,0,37500,468);    /* 使能FTM2的CH0通道,32分频Busclk48MHz/32=1.5MHz,
                                           右对齐,周期为40Hz=1.5MHz/37500=1200*48kHz,低电平时间为15/48kHz */


相关帖子

沙发
Vitality1|  楼主 | 2015-3-28 10:43 | 只看该作者

5、将上述代码添加到工程中,运行之后,可以从示波器上看到PWM的波形图(图中示波器只显示了其中一部分),如下所示,是不是很帅,哈哈:


使用特权

评论回复
板凳
powerful1| | 2015-3-28 10:55 | 只看该作者
PWM模块该算是属于定时器模块范围内的

使用特权

评论回复
地板
energy1| | 2015-3-28 11:20 | 只看该作者
Kinetis的PWM模块,是在飞思卡尔已经成熟应用多年的8位单片机上的PWM模块上扩展而来的

使用特权

评论回复
5
vigous1| | 2015-3-28 11:43 | 只看该作者
请问FTM是在边沿对齐PWM模式下的么

使用特权

评论回复
6
FSL_TICS_ZJJ| | 2015-4-2 11:34 | 只看该作者
非常感谢你关于Kinetis的经验分享 !

使用特权

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

本版积分规则

81

主题

421

帖子

9

粉丝