CKS32F4xx系列产品Timer定时器的基本使用方法-比较输出

描述

 

 

 

比较输出简介

比较输出可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形,简称脉宽调制,这也是利用微处理器的数字输出来对模拟威廉希尔官方网站 进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,PWM原理如下图所示:

mcu

图中,我们假定定时器工作在向上计数PWM模式,且当CNT时,输出0,当CNT>=CCRx时输出1。那么就可以得到如上的 PWM,示意图:当CNT值小于CCRx的时候,IO输出低电平(0),当CNT值大于等于CCRx的时候,IO输出高电平(1),当CNT达到ARR值的时候,重新归零,然后重新向上计数,依次循环。改变CCRx的值,就可以改变PWM输出的占空比,改变ARR的值,就可以改变PWM输出的频率,这就是 PWM输出的原理。

CKS32F4的定时器除了TIM6和7。其他的定时器都可以用来产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。而通用定时器也能同时产生多达4路的PWM输出。这里仅使用TIM14的CH1产生一路PWM输出。要使CKS32F4的通用定时器TIMx 产生PWM输出,除了上一章介绍的寄存器外,我们还会用到3个寄存器,来控制PWM的。这三个寄存器分别是:

捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。对于捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器一般有2个:TIMx _CCMR1和TIMx _CCMR2,不过TIM14只有一个。TIMx_CCMR1控制CH1和2,而TIMx_CCMR2控制CH3和4。以下我们将以TIM14为例进行介绍。TIM14_CCMR1寄存器各位描述如下图所示:

mcu

该寄存器的有些位在不同模式下,功能不一样,所以在图中,我们把寄存器分了2层,上面一层对应输出而下面的则对应输入。关于该寄存器的详细说明,请参考《CKS32F4xx

中文参考手册》这里我们需要说明的是模式设置位 OC1M,此部分由3位组成。总共可以配置成7种模式,我们使用的是PWM模式,所以这3位必须设置为110/111。

这两种PWM模式的区别就是输出电平的极性相反。另外CC1S用于设置通道的方向(输入/输 出)默认设置为0,就是设置通道作为输出使用。注意:这里是因为我们的TIM14只有1个通道,所以才只有第八位有效,高八位无效,其他有多个通道的定时器,高八位也是有效的,具体请参考《CKS32F4xvx 中文参考手册》对应定时器的寄存器描述。

接下来,我们介绍TIM14的捕获/比较使能寄存器(TIM14_CCER),该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如下图所示:

mcu

该寄存器比较简单,我们这里只用到了CC1E位,该位是输入/捕获1输出使能位,要想PWM从IO口输出,这个位必须设置为1,所以我们需要设置该位为1。因为TIM14只有1个通道,所以才只有低四位有效,如果是其他定时器,该寄存器的其他位也可能有效。

最后,我们介绍一下捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有4个,对应4 个通道CH1~4。不过TIM14只有一个,即:TIM14_CCR1,该寄存器的各位描述如下图所示:

mcu

在输出模式下,该寄存器的值与CNT的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。

如果是通用定时器,则配置以上三个寄存器就够了,但是如果是高级定时器,则还需要配置:刹车和死区寄存器(TIMx_BDTR),该寄存器各位描述如下图所示:

mcu

该寄存器,我们只需要关注最高位:MOE位,要想高级定时器的PWM正常输出,则必须设置MOE位为1,否则不会有输出。注意:通用定时器不需要配置这个。其他位我们这里就不详细介绍了。

PWM实际跟上一章节一样使用的是定时器的功能,所以相关的函数设置同样在库函数文件 CKS32f4xx_tim.h和CKS32f4xx_tim.c文件中。

1)开启TIM14和GPIO时钟,配置PF9选择复用功能AF9(TIM14)输出

要使用TIM14,我们必须先开启TIM14的时钟,这点相信大家看了这么多代码,应该明白了。这里我们还要配置PF9为复用(AF9)输出,才可以实现TIM14_CH1的PWM经过PF9输出。库函数使能 TIM14时钟的方法是:

 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //>>TIM14 时钟使能

 

这在前面章节已经提到过。当然,这里我们还要使能GPIOF的时钟。然后我们要配置PF9引脚映射至AF9,复用为定时器14,调用的函数为:

 

GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //>>GPIOF9 复用为定时器 14 

 

这个方法跟我们串口实验讲解一样,调用的同一个函数,最后设置PF9为复用功能输出这里我们只列出GPIO初始化为复用功能的一行代码:

 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //>>复用功能

 

这里还需要说明一下,对于定时器通道的引脚关系,大家可以查看CKS32F4对应的数据手册,比如我们PWM实验,我们使用的是定时器14的通道1,对应的引脚PF9可以从数据手册表中查看:

mcu

2)初始化TIM14,设置TIM14的ARR和PSC等参数

在开启了TIM14的时钟之后,我们要设置ARR和 PSC两个寄存器的值来控制输出PWM的周期。这在库函数是通过TIM_TimeBaseInit函数实现的,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为:

 

TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值 
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值 
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx

 

3)设置TIM14_CH1的PWM模式,使能TIM14的 CH1输出

设置TIM14_CH1为PWM模式(默认是冻结的)通过配置TIM14_CCMR1的相关位来控制TIM14_CH1的模式。在库函数中,PWM通道设置是通过函数 TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我们使用的是通道1,所以使用的函数是TIM_OC1Init()。

 

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

 

这种初始化格式大家学到这里应该也熟悉了,所以我们直接来看看结构体TIM_OCInitTypeDef的定义:

 

TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值 
typedef struct 
{ 
uint16_t TIM_OCMode; 
uint16_t TIM_OutputState; 
uint16_t TIM_OutputNState; */ 
uint16_t TIM_Pulse; 
uint16_t TIM_OCPolarity; 
uint16_t TIM_OCNPolarity; 
uint16_t TIM_OCIdleState; 
uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef;

 

这里我们讲解一下与我们要求相关的几个成员变量:参数TIM_OCMode设置模式是PWM还是输出比较,这里我们是PWM模式。

参数TIM_OutputState用来设置比较输出使能,也就是使能PWM输出到端口。

参数TIM_OCPolarity用来设置极性是高还是低。其他的参数TIM_OutputNState,TIM_OCNPolarity,TIM_OCIdleState和 TIM_OCNIdleState是高级定时器才用到的。要实现我们上面提到的场景,方法是:

 

TIM_OCInitTypeDef TIM_OCInitStructure; 
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //>>选择模式 PWM 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //>>比较输出使能 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //>>输出极性低 
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //>>根据指定的参数初始化外设TIM1 4OC1

 

4)使能TIM14

在完成以上设置了之后,我们需要使能TIM14。使能TIM14的方法前面已经讲解过:

 

TIM_Cmd(TIM14, ENABLE); //>>使能 TIM14

 

5)修改TIM14_CCR1来控制占空比

最后,在经过以上设置之后,PWM其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改TIM14_CCR1则可以控制 CH1的输出占空比。在库函数中,修改TIM14_CCR1占空比的函数是:

 

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);

 

理所当然,对于其他通道,分别有一个函数名字,函数格式为TIM_SetComparex(x=1,2,3,4)。

通过以上5个步骤,我们就可以控制TIM14的CH1输出PWM波了。这里特别提醒一下大家,高级定时器虽然和通用定时器类似,但是高级定时器要想输出PWM,必须还要设置一个MOE位(TIMx_BDTR 的第15位),以使能主输出,否则不会输出PWM。库函数设置的函数为:

 

void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState)

 

 

代码示例

TIM3时钟来自于APB1域,我们通过APB1总线下的时钟使能函数来使能TIM3的时钟。调用的函数是:

 

//>>TIM14 PWM 部分初始化 
//>>PWM 输出初始化 
//>>arr:自动重装值 psc:时钟预分频数 
void TIM14_PWM_Init(u32 arr,u32 psc) 
{ 
GPIO_InitTypeDef GPIO_InitStructure; 
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
TIM_OCInitTypeDef TIM_OCInitStructure; 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//TIM14 时钟使能 
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //使能 PORTF 时钟 
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GF9 复用为 TIM14 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIOF9 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 
//速度 50MHz 
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化 PF9 
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频 
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器 14 
//初始化 TIM14 Channel1 PWM 模式 
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM 调制模式 1 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性低 
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //初始化外设 TIM1 4OC1 
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //使能预装载寄存器 
TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE 使能 
TIM_Cmd(TIM14, ENABLE); //使能 TIM14 
TIM_SetCompare1(TIM14,300); //>>设置pwm的占空比为300/500 = 60%
}

 

此部分代码包含了上面介绍的PWM输出设置的前5个步骤。这里我们关于TIM14的设置就不再说了。接下来,我们看看主程序里面的main函数如下:

 

int main(void) 
{ 
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//>>设置系统中断优先级分组 2 
delay_init(168); //>>初始化延时函数 
TIM14_PWM_Init(500-1,84-1); //>>定时器时钟为 84M,分频系数为 84,所以计数频率 
//>>为 84M/84=1Mhz,重装载值 500,所以 PWM 频率为 1M/500=2Khz. 
while(1) 
{ 
} 
}

 

这里,我们先设置好了NVIC终端优先级,然后初始化延时函数和timer,在timer的初始化参数中我们把PWM的频率设置成2K,将占空比设置成60%,完成PWM输出设置。

 

 

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分