用CCS分析解读CC3200 SDK工具包的PWM示例程序

CC3200一共有4组定时器TimerA0-A3,每个定时器有2个子定时器,如TimerA0A、TimerA0B、TimerA1A、TimerA1B等。根据不同的功能需要,可以在引脚配置文件中选择不同的模式,如下图,模式3代表输出PWM,模式12代表捕获外部脉冲。
在这里插入图片描述
在这里插入图片描述
图源自:CC3200-PWM
PWM示例程序在“example\pwm”目录中。C3200 GPTA2B、GPTA3B、GPTA3A分别通过PWM05(PIN_64)、PWM06(PIN_01)、PWM07(PIN_02)输出PWM信号(占空比由0到1)控制3个LED的亮度(由灭逐渐到亮)。PWM项目包含主函数文件、引脚配置程序文件和CCS启动程序文件。
在这里插入图片描述
在这里插入图片描述

  1. PWM操作
    PWM操作主要是初始化PWM模块InitPWMModules(),主要内容是设置PWM模式SetupTimerPWMMode()。
void InitPWMModules()
{
    //
    // Initialization of timers to generate PWM output
    //
    MAP_PRCMPeripheralClkEnable(PRCM_TIMERA2, PRCM_RUN_MODE_CLK);
    MAP_PRCMPeripheralClkEnable(PRCM_TIMERA3, PRCM_RUN_MODE_CLK);

    //
    // TIMERA2 (TIMER B) as RED of RGB light. GPIO 9 --> PWM_5
    //
    SetupTimerPWMMode(TIMERA2_BASE, TIMER_B,
            (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM), 1);
    //
    // 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_TimerEnable(TIMERA2_BASE,TIMER_B);
    MAP_TimerEnable(TIMERA3_BASE,TIMER_A);
    MAP_TimerEnable(TIMERA3_BASE,TIMER_B);
}
void SetupTimerPWMMode(unsigned long ulBase, unsigned long ulTimer,
                       unsigned long ulConfig, unsigned char ucInvert)
{
    //
    // 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);
    
    //
    // 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);

}

SetupTimerPWMMode()主要包括下列内容。

  • 配置定时器:TimerConfigure()
  • 设置预分频:TimerPrescaleSet()
  • 控制输出电平:TimerControlLevel()
  • 设置定时器初值:TimerLoadSet()
  • 设置定时器匹配:TimerMatchSet()
    (1)配置定时器
void TimerConfigure(unsigned long ulBase, unsigned long ulConfig);

参数说明:

  • ulBase:定时器基地址,TimerA2和TimerA3的基地址分别是0x4003 2000和0x4003 3000,在hw_memmap.h中定义。

  • ulConfig:定时器配置,主要包括下列值。
    1.TIMER_CFG_SPLIT_PAIR:双16位定时器
    2.TIMER_CFG_A_PWM:子定时器A PWM输出
    3.TIMER_CFG_B_PWM:子定时器B PWM输出
    TimerA2的设置值是1和3,因为此程序涉及到了TimerA2B。
    TimerA3的设置值是1、2和3,因为此程序涉及到了TimerA3A、TimerA3B。
    当需要同时配置一个定时器组中的两个pwm输出的时候,模式设置函数中要2和3进行或运算,如下所示。不能单独配置,否则前一个配置模式会被后面的配置给覆盖掉。在这里插入图片描述

    注意:Timer项目和PWM项目中TimerConfigure()的主要区别是配置值的不同,Timer项目中配置值是TIMER_CFG_PERIODIC(32位周期定期器)。
    (2)设置预分频

void TimerPrescaleSet(unsigned long ulBase, unsigned long ulTimer,unsigned long ulValue)

参数说明:

  • ulBase:定时器基地址。
  • ulTimer:子定时器选择,TimerA2的设置值是TIMER_B,TimerA3的设置值是TIMER_A和TIMER_B。
  • ulValue:预分频值,设置值都是0,即不分频。

在这里插入图片描述
(3)控制输出电平

void TimerControlLevel(unsigned long ulBase, unsigned long ulTimer,tBoolean bInvert)

参数说明:

  • ulBase:定时器基地址。
  • ulTimer:子定时器选择。
  • bInvert:定时器输出电平,true表示低电平,false表示高电平。此示例程序都设置为1,也就是PWM模式下输出的有效电平为低电平,对应的LED的熄灭状态。
    在这里插入图片描述
    (4)设置定时器初值
void TimerLoadSet(unsigned long ulBase, unsigned long ulTimer,unsigned long ulValue)

参数说明:

  • ulBase:定时器基地址。
  • ulTimer:子定时器选择。
  • ulValue:定时器初值。此示例程序设置的是40035.
MAP_TimerLoadSet(ulBase,ulTimer,TIMER_INTERVAL_RELOAD);
.....
#define TIMER_INTERVAL_RELOAD   40035 /* =(255*157) */

(5)设置定时器匹配值

void TimerMatchSet(unsigned long ulBase, unsigned long ulTimer,unsigned long ulValue)

参数说明:

  • ulBase:定时器基地址。
  • ulTimer:子定时器选择。
  • ulValue:定时器初值。
    (6)允许定时器
void TimerEnable(unsigned long ulBase, unsigned long ulTimer)

(7)更新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));
}
...
#define DUTYCYCLE_GRANULARITY   157
  1. 占空比的计算
    系统的时钟是80MHz的,首先确定PWM的周期,比如说0.5ms,据此确定定时器装载的初始值。(0.5*10的-3次方)/(1/80M) = 40000,也就是说定时器从40000向下计数就是0.5ms。
    在这里插入图片描述

从另外一张图举例,图和上面40000不是对应的,只是为了形象点。看出,定时器的初值为0xC350(十进制50000),然后比较值为0x411A(十进制16666),PWM输出的原理是定时器向下计数,当定时器的值大于比较值时输出有效电平,小于比较值时输出另一电平。也就是定时器从50000数到16666这一段时间输出有效电平,16666到0这一段时间输出另一电平。而有效电平的设置是在控制输出电平TimerControlLevel()中的bInvert参数设定的,此示例程序都设置为1,也就是PWM模式下输出的有效电平为高电平,对应的LED的点亮状态。
然后我们要考虑占空比可调,我们需要考虑LED亮度一共有多少等级可以调节。示例中设置的是0-254一共255个等级,那每个等级之间的步长就是40000/255约等于157,不能除尽。所以我们调节定时器的初值为255*157=40035(周期0.5004735ms),这样就可以达到255等级,每个等级步长均为157。所以其实我们是通过改变UpdataDutyCycle函数的uclevel值,去改变那个比较值,让PWM输出有效电平的时间产生改变。

下图是主函数循环函数,主要是改变iLoopCnt以此来改变LED灯亮度等级,从0开始往上递增。

    while(1)
    {
        //
        // RYB - Update the duty cycle of the corresponding timers.
        // This changes the brightness of the LEDs appropriately.
        // The timers used are as per LP schematics.
        //
        for(iLoopCnt = 0; iLoopCnt < 255; iLoopCnt++)
        {
            UpdateDutyCycle(TIMERA2_BASE, TIMER_B, iLoopCnt);
            UpdateDutyCycle(TIMERA3_BASE, TIMER_B, iLoopCnt);
            UpdateDutyCycle(TIMERA3_BASE, TIMER_A, iLoopCnt);
            MAP_UtilsDelay(800000);
        }
     }

以下为具体的占空比更新函数,引用了TimerMatchSet函数改变匹配值,也就是匹配值。我们可以看到匹配值从等级0,慢慢增加,对应的就是比较值0、157、314…所以我们可以推出在前面一段时间,整个周期低电平是占了一大半时间的,对应的就是LED处于熄灭状态。当比较值慢慢增加,有效电平即低电平所占的时间慢慢减少,高电平所占的时间慢慢增加,也就是LED点亮的时间慢慢增加,从视觉上来说,就是LED变亮了。

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));
}

参考文献:《ARM Cortex-M4+Wi-Fi MCU应用指南-CC3200 CCS基础篇》郭书军编著 电子工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值