比较输出简介
比较输出可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形,简称脉宽调制,这也是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,PWM原理如下图所示:
图中,我们假定定时器工作在向上计数PWM模式,且当CNT
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寄存器各位描述如下图所示:
该寄存器的有些位在不同模式下,功能不一样,所以在图中,我们把寄存器分了2层,上面一层对应输出而下面的则对应输入。关于该寄存器的详细说明,请参考《CKS32F4xx
中文参考手册》这里我们需要说明的是模式设置位 OC1M,此部分由3位组成。总共可以配置成7种模式,我们使用的是PWM模式,所以这3位必须设置为110/111。
这两种PWM模式的区别就是输出电平的极性相反。另外CC1S用于设置通道的方向(输入/输 出)默认设置为0,就是设置通道作为输出使用。注意:这里是因为我们的TIM14只有1个通道,所以才只有第八位有效,高八位无效,其他有多个通道的定时器,高八位也是有效的,具体请参考《CKS32F4xvx 中文参考手册》对应定时器的寄存器描述。
接下来,我们介绍TIM14的捕获/比较使能寄存器(TIM14_CCER),该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如下图所示:
该寄存器比较简单,我们这里只用到了CC1E位,该位是输入/捕获1输出使能位,要想PWM从IO口输出,这个位必须设置为1,所以我们需要设置该位为1。因为TIM14只有1个通道,所以才只有低四位有效,如果是其他定时器,该寄存器的其他位也可能有效。
最后,我们介绍一下捕获/比较寄存器(TIMx_CCR1~4),该寄存器总共有4个,对应4 个通道CH1~4。不过TIM14只有一个,即:TIM14_CCR1,该寄存器的各位描述如下图所示:
在输出模式下,该寄存器的值与CNT的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。
如果是通用定时器,则配置以上三个寄存器就够了,但是如果是高级定时器,则还需要配置:刹车和死区寄存器(TIMx_BDTR),该寄存器各位描述如下图所示:
该寄存器,我们只需要关注最高位: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可以从数据手册表中查看:
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输出设置。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !