4 - 输入/输出:FTM(PWM输出,脉冲计数)

本文将介绍K60(Freescale Kinetis K60)和XS128(Freescale S12XS128)的ADC用法。
K60使用了野火的12年版底层库,请参考《三天入门 Cortex-M4—Kinetis 系列 野火 Kinetics 开发板教程》。
XS128请参考飞思卡尔提供的Datasheet.

PWM模块产生脉冲,用于控制电机。通过改变其占空比,可以控制电机输出的大小。
脉冲计数(XS128的TIM)模块相当于一个计数器,可以对脉冲输入进行计数,用于测速编码器。
PWM输出和输入模块都不占用运算资源,只要配置好,它们就能自己工作。
K60的脉冲计数我忘了怎么做了,所以这里只提供XS128的方法。


K60 - PWM

电机初始化,初始化PWM输出。

/********************************************************************
** 函数名称: motor_init()
** 功能描述: 电机初始化
** 入口:
** 出口:
** 说明: 初始化PWM输出通道,设置输出频率,初始占空比。
*********************************************************************/
void motor_init()
{
    //初始化FTM0_CH0 CH1 CH2 CH3输出频率为 16kHZ,占空比为 50% 的PWM;
    FTM_PWM_init(MOTOR_FTMN,MOTOR_FTMCH0,MOTOR_FREQ,MOTOR_INIT_VAL); //初始化CH0
    FTM_PWM_init(MOTOR_FTMN,MOTOR_FTMCH1,MOTOR_FREQ,MOTOR_INIT_VAL); //初始化CH1
    FTM_PWM_init(MOTOR_FTMN,MOTOR_FTMCH2,MOTOR_FREQ,MOTOR_INIT_VAL); //初始化CH2
    FTM_PWM_init(MOTOR_FTMN,MOTOR_FTMCH3,MOTOR_FREQ,MOTOR_INIT_VAL); //初始化CH3
}

程序中可以随时调用以下函数来改变占空比

FTM_PWM_Duty(MOTOR_FTMN,MOTOR_FTMCH1,0); //设置CH1占空比为0 (没有输出)
FTM_PWM_Duty(MOTOR_FTMN,MOTOR_FTMCH2,5000); //设置CH2占空比为50%(精度是10000,所以5000就是50%)

用到的宏定义

#define  MOTOR_FTMN       FTM0           //使用FTM0模块,请参考野火手册
#define  MOTOR_FTMCH0     CH0
#define  MOTOR_FTMCH1     CH1
#define  MOTOR_FTMCH2     CH2 
#define  MOTOR_FTMCH3     CH3 
#define  MOTOR_FREQ 16000           //电机频率   16KHz
#define  MOTOR_INIT_VAL 5000           //电机初始值,精度1/10000  即5000/10000 50%

XS128 - PWM

XS128的PWM初始化需要仔细一点,因为有好多寄存器啊orz
先上代码,这里需要用到4个通道

/**************************************************
* 函数名称: void PWM_init() 
* 功能描述: PWM初始化函数
* 说明: 
***************************************************/
void PWM_init() 
{
    PWME = 0X00;       //关闭通道使能
    PWMPOL=0xff;     //先输出高电平,计数到DTY时,反转电平
    
    PWMCLK = 0xFF;   //时钟源选择0145通道选择SA,2367SB
    PWMPRCLK = 0X52; //A时钟4分频,B时钟32分频
                                         //ClockA = fbus / 4;  ClockB = fbus / 32;
                                      
    PWMCAE=0x00;      //选择输出模式为左对齐输出模式
                                           
    PWMSCLA = 10;    //SA = clockA /( 2 * PWMSCLA )
    PWMSCLB = 1;      //SB = clockB /( 2 * PWMSCLB )
    
    PWMCTL_CON01=0;          //通道不级联
    PWMCTL_CON45=0;          //通道不级联
    
    PWMPER0 =(char) 200;     //PWMx Period = Channel Clock Period * (2 * PWMPERx)
    PWMDTY0 = (unsigned char) 100;      //Duty Cycle = [PWMDTYx / PWMPERx] * 100%  占空比=100/200=50%
    PWMPER1 =(unsigned char) 200;     //PWMx Period = Channel Clock Period * (2 * PWMPERx)
    PWMDTY1 = (unsigned char) 100;      //Duty Cycle = [PWMDTYx / PWMPERx] * 100%   占空比=100/200=50%
    
    PWMPER4 =(unsigned char) 200;     //PWMx Period = Channel Clock Period * (2 * PWMPERx)
    PWMDTY4 = (unsigned char) 100;      //Duty Cycle = [PWMDTYx / PWMPERx] * 100%   占空比=100/200=50%
    PWMPER5 =(unsigned char) 200;     //PWMx Period = Channel Clock Period * (2 * PWMPERx)
    PWMDTY5 = (unsigned char) 100;      //Duty Cycle = [PWMDTYx / PWMPERx] * 100%   占空比=100/200=50%
    
   // PWM输出频率计算
   // PWMx Frequency = Clock (A, B, SA, or SB) / PWMPERx
   // 0145通道使用了SA.
   // Bus Freq = 80MHz
   // Clock A Freq = 80MHz/4 = 20MHz
   // Clock SA Freq = 20MHz/(2*10) = 1MHz
   // PWM0 Freq = 1MHz/200 = 5KHz
   // 电机脉冲输出频率为5KHz
    
    //使能
    PWME_PWME0 = 1;
    PWME_PWME1 = 1;
    PWME_PWME4 = 1;
    PWME_PWME5 = 1;
}

PWM初始化后,程序可以直接改变PWMDTY0,PWMDTY1,PWMDTY4,PWMDTY5的值来改变输出的占空比。

 PWMDTY0 = (unsigned char) 200;  //设置通道0的占空比为100%
 PWMDTY1 = (unsigned char) 0;  //设置通道1的占空比为0
 PWMDTY4 = (unsigned char) 200;  // 设置通道4的占空比为100%
 PWMDTY5 = (unsigned char) 0;  //设置通道5的占空比为0

PWM_block_diagram
PWM的框图。每个通道时钟由Bus Clock经过分频得到,每个通道都有自己的计数器,有周期和占空比属性。

PWMCLK
PWM通道时钟选择,1245通道时钟设置为0时用ClockA,设置为1时用ClockSA.

PWMPRCLK
PWMPRCLK配置Clock A和Clock B的频率,它们由Bus Clock分频而得。

XS128 - 脉冲计数

初始化TIM计数

void TIM_Init(void) 
{ 
  /**************** For Encoder Counting ********************/
   TCNT =0x00;
   TSCR1=0x80;         //TIMER 定时器使能
   TSCR2 = 0x06;       // Timer Prescale.  Bus Clock/64
   
   PACTL=0xc0;         //PT7 PIN,PACN32 16BIT,FALLing edge,NO INTERRUPT   0xc0 = 1100 0000
   
   TFLG1=0xFF;         //清中断标志位 
}

读取计数值

    //获得速度L
    SPEED_EN_L = 0; //计数禁止
    NowSpeedL = PACNT;  //读取寄存器的值
    PACNT = 0;  //清零计数器
    SPEED_EN_L = 1; //计数允许