脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。调整PWM的周期、PWM的占空比而达到控制充电电流的目的.
老规矩,先让我们来看pwm.c中的源码:
#include "pwm.h"
#include "led.h"
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIO外设时钟使能
//设置该引脚为复用输出功能,输出TIM,CH1的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_8; //TIM_CH1
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period=arr;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler=psc;//设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision= 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_OCInitStructure.TIM_OCMode= TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse= 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity= TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM1,&TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH1预装载使能
TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIMx在ARR上的预装载寄存器
TIM_Cmd(TIM1,ENABLE); //使能TIM1
}
这里我们要配置PA8为复用输出,这是因为TIM1_CH1通道将使用PA8的复用功能作为输出。
首先,我要介绍一下占空比:
占空比是PWM的最重要的参数
8位的PWM是0-255(2^8),比如用PWM控制一个电源正极的开关当PWM频率足够高的时候,开关后的电压是 = 电压占空比比如你用5V电源,用一个MOS管控制电源输出的话给MOS管30%的占空比,那么就是输出5V30%的电压
然后再说说怎么实现这个占空比。8位的定时器,如果做PWM,要输出30%的占空比,那么定时器从0~255*30%的计数值内(也就是76内)要输出高电平。然后比较当前的计数值跟76,计数值小于76就输出高电平,大于76的时候就输出低电平。
再让我们来看一下TIM_TimeBaseStructure这个结构体的各个成员
typedef struct
{
uint16_t TIM_OCMode;
uint16_tTIM_OutputState;
uint16_t TIM_OutputNState;*/
uint16_tTIM_Pulse;
uint16_tTIM_OCPolarity;
uint16_tTIM_OCNPolarity;
uint16_tTIM_OCIdleState;
uint16_tTIM_OCNIdleState;
}TIM_OCInitTypeDef;
参数TIM_OCMode设置模式是PWM还是输出比较,这里我们是PWM模式。(PWM有两种模式,一种是向上计数,一种是向下计数)
参数TIM_OutputState用来设置比较输出使能,也就是使能PWM输出到端口。(用计数值和用占空比计算得到的数进行比较,这里用上面提到的76举例,就是比较计数值与76的大小,根据下面TIM_OCPolarity定义的值判断,大于76时输出高电平还是小于76时输出低电平,所以使能输出比较结果,就是允许输出PWM)
参数TIM_OCPolarity用来设置极性是高还是低。(取值为TIM_OCPolarity_High时,计数值比76小时定义为高电平,比76大时定义为低电平,取值为TIM1_OCPolarity_Low时相反)
其他参数 TIM_OutputNState ,TIM_OCNPolarity , TIM_OCIdleState 和 TIM_OCNIdleState 是高级定时器TIM1和TIM8才用到的。
这里我们只要使用通用定时器的功能,所以没有必要初始化这些成员。
配置好了之后用TIM_OC1Init(TIM1,&OCInitStructure)函数初始化TIM1 OC1;
如果是高级定时器,则还需要配置:刹车和死区寄存器(TIMx_BDTR),该寄存器,我们只需要关注最高位:MOE位,要想高级定时器的PWM正常输出,则必须设置MOE位为1,否则不会有输出。注意:通用定时器不需要配置这个。其他位我们这里就不多说。
接下来的三个使能还是要看定时器结构的
1.jpg如上图,这里我就不多说了。
最后我要解释一下关于为什么LED是渐变的,虽然TIM1计数器中的计数值要与76比较,但是这一个周期的时间十分短暂,导致低电平时间过短,达到人眼无法分辨的频率,所以我们觉得LED一直是亮着的,这个时候决定LED变化的只有主函数中最后一段代码中的函数TIM_SetCompare1(TIM1,led0pwmval)中的led0pwmval这个参数决定的占空比,从而影响电压进而影响电流大小,最后导致了LED的亮度的改变。
网友评论