CC3200——PWM

版权声明:虽为原创,欢迎转载。 https://blog.csdn.net/m0_37655357/article/details/86489658

1、PWM由定时器产生,且只能由16位的定时器产生。因此能够分频。

每个引脚根据选择的功能,可以配置成不同的PWM模式,比如下面这个:

工作在模式3时,作为GT_CCP07,只能输出PWM,不能作为捕获;

工作在模式12时,作为GT_CCP02,只能捕获外部脉冲,不能输出。

2、定时器产生PWM时,是向下计数的,根据是否设置输出信号翻转,决定输出的PWM波形。由下面这个函数决定。

这个函数下面有这么一段话:

This function sets the PWM output level for the specified timer. If the bInvert parameter is true, then the timer's output is made active low; otherwise, it is made active high.

也即是如果设置了输出信号翻转,则低电平有效,那么当定时器的当前值大于比较值时,输出有效电平。只有向下计数到达比较值时,输出另一电平。下图形象的说明了这一点。

3、PWM计数器虽是16位,但是加上分频器的8位,相当于一共可以使用24位。其中计数器的16位在高位。

2的24次方等于16777216,约为167万。

这样使得CC3200能够输出周期更长,频率更低的PWM,而不是只能输出高频方波。

4、既然计数器是24位,那么PWM的比较器的值也应该是24位,但是这24位数据存放在两个寄存器中。

下面这个函数能够设置比较值的低16位:

下面这个函数能够设置比较值的高8位:

5、PWM配置

(1)引脚配置不在使用GPIO了,而是使用TIMER一族的函数。首先使能输出PWM引脚所在的时钟分组,比如我想让GPIO10输出pwm,根据下图,发现他在方式3时能够作为PWM06输出,那么在查阅1中的图一,可以知道他在TIMEA3的A号定时器上。那么我们就需要使能这个定时器。

MAP_PRCMPeripheralClkEnable(PRCM_TIMERA3, PRCM_RUN_MODE_CLK);

然后利用下面这个函数选择该引脚的PWM输出所在的工作模式

    //
    // Configure PIN_64 for TIMERPWM5 GT_PWM05
    //
    MAP_PinTypeTimer(PIN_64, PIN_MODE_3);

(2)配置PWM的工作方式,需要用到5个函数

  • 首先配置定时器和预分频值:
    //
    // Set GPT - Configured Timer in PWM mode.
    //
    MAP_TimerConfigure(ulBase,ulConfig);
    MAP_TimerPrescaleSet(ulBase,ulTimer,0);
  • 确定输出信号是否翻转 
    //
    // Inverting the timer output if required
    //
    MAP_TimerControlLevel(ulBase,ulTimer,ucInvert); //ture是低电平有效,other则高电平有效
  • 装载定时器初始值
    //
    // Load value set to ~0.5 ms time period
    //
    MAP_TimerLoadSet(ulBase,ulTimer,TIMER_INTERVAL_RELOAD);
  • 装载比较值
    //
    // Match value set so as to output level 0
    //
    MAP_TimerMatchSet(ulBase,ulTimer,TIMER_INTERVAL_RELOAD); 

此处初始比较值也设置为最大,是为了让led初始时处于灭的状态,因为这样的话,pwm会一直输出有效电平,这里的有效电平是低电平。

上面这5个函数在SDK的pwm例程中的main.c文件中被封装成了一个函数

//****************************************************************************
//
//! Setup the timer in PWM mode
//!
//! \param ulBase is the base address of the timer to be  configured
//! \param ulTimer is the timer to be setup (TIMER_A or  TIMER_B)
//! \param ulConfig is the timer configuration setting
//! \param ucInvert is to select the inversion of the output
//!
//! This function  
//!    1. The specified timer is setup to operate as PWM
//!
//! \return None.
//
//****************************************************************************
void SetupTimerPWMMode(unsigned long ulBase, unsigned long  ulTimer,
                       unsigned long ulConfig, unsigned char  ucInvert)

注意:

    当需要同时配置一个定时器组中的两个pwm输出的时候,模式设置函数中要将TIMER_CFG_A_PWM和TIMER_CFG_B_PWM进行或运算,如下面代码所示。不能单独配置,否则前一个配置模式会被后面的配置给覆盖掉。

    //
    // TIMERA3 (TIMER B) as YELLOW of RGB light. GPIO 10 -->  PWM_6
    //
    SetupTimerPWMMode(TIMERA3_BASE, TIMER_A,
            (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM |  TIMER_CFG_B_PWM), 1);
    //
    // TIMERA3 (TIMER A) as GREEN of RGB light. GPIO 11 --> PWM_7
    //
    SetupTimerPWMMode(TIMERA3_BASE, TIMER_B,
            (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM |  TIMER_CFG_B_PWM), 1);

这个函数其实是对库函数的进一步封装:MAP_TimerPrescaleSet(ulBase,ulTimer,0);

因为他们不兼容,而第一个参数又一样,所以必须使用或运算。

(6)使能定时器     MAP_TimerEnable(TIMERA2_BASE,TIMER_B);

至此,定时器就开始在指定端口输出PWM。

(7)关于可变占空比的pwm

官方的SDK的pwm例程中,是利用pwm控制呼吸灯的效果。

因此需要连续改变pwm的占空比。

可以在程序运行过程中,调用函数修改比较值即可。

void UpdateDutyCycle(unsigned long ulBase, unsigned long ulTimer,
                     unsigned char ucLevel)
{
    //
    // Match value is updated to reflect the new dutycycle  settings
    //
     MAP_TimerMatchSet(ulBase,ulTimer,(ucLevel*DUTYCYCLE_GRANULARITY));
}

(8)关于占空比的计算

首先要确定需要输出pwm的周期。比如说0.5ms,据此确定定时器装载的初始值。(0.5*10的-3次方)/(1/80M) = 40000

比如说占空比需要50%,那么比较器的值就是20000;

如果考虑输出占空比可调,首先需要考虑你需要输出多少级可调?比如说100级可调,意思就是LED的亮度有100个等级。

那么40000/100 = 400,这个就是每次调节的步长。

因此(7)的那个更新比较值的函数的第三个参数有个宏:#define DUTYCYCLE_GRANULARITY   157

就是每次更新比较器的步长。

这个函数需要在主函数中调用来修改比较值。而定时器输出pwm是与主函数并行运行的,也就是一旦是能了定时器,就开始输出PWM了,接下来主函数该干什么干什么就行了。

猜你喜欢

转载自blog.csdn.net/m0_37655357/article/details/86489658