一、PWM的原理简单介绍

1、占空比

PWM通常用来驱动舵机、电机,或是让LED灯呈现呼吸效果。基本原理,就是在一定时间内,通过控制高低电平持续时间的占比,来控制输出强度。

比如以10毫秒秒为周期,低电平点亮LED。那么低电平的时间为7毫秒,高电平的时间为3毫秒,那么在视觉上,LED灯发出的光,肯定比低电平的时间为3毫秒时更亮。

(实际上LED的发光时的亮度是一定的,只是让它总体被点亮的时间变长,LED更多的时间让自己完全亮起,因为视觉滞留效应,就会感觉更亮)

而高电平的持续时间,与一个周期的时间之比,就被称为占空比。由此也可以很轻松的想到,占空比,就是控制PWM输出强度的关键。

此时我们就可以说占空比为40%。

而由这无数个高低电平切换,所形成的波形,我们就称为PWM波形。

这就算是对PWM有了简单的理解,其本质就是通过控制高低电平的变化,来控制模拟电压的大小。

2、频率

PWM还有一个重要的属性,就是频率。

比如,1秒为一个周期,也就是PWM的频率为1HZ,此时我们高电平维持0.5秒,低电平维持0.5秒,我们就会发现,LED灯,是在闪烁的。

而当我们以10毫秒为一个周期,也就是PWM的频率为100HZ时,在这个频率下,我们的肉眼是感知不到LED的闪烁的。并且因为在10毫秒内,LED快速转换了亮灭状态,LED还未完全亮起就熄灭,所以我们会感觉LED比起上者,亮度会减小一半。

在此基础上,我们在不停改变占空比,就能实现LED呼吸灯的效果。

并且,频率越大,就会让PWM输出的越平滑,但是相对应的开销也会越大,所以选择合适的频率至关重要。

所以可以看出,频率是让所驱动对象能否正常实现我们想要的效果的关键。

3、分辨率

确定电平变化的步距,越高越好,但是与频率一样,对于硬件的要求也会越高,一般情况下,1%就足够使用。

二、PWM的代码介绍

1、定时器

首先,PWM波的输出,是靠定时器来完成的。

在手册中,定时器的功能描述,我们也能看到包含了PWM的生成。

对于生成PWM,通过手册所给的框图,我们可以看到使用的是这一部分

CNT计数器,计的数会与捕获比较寄存器进行比较,也就是会CNT与CCR进行比较。

在STM32给的库函数中,有以下几种输出比较模式

其他模式用处较少,常用的是PWM模式1。

也就是说,若是向上计数,当定时器在CNT的数小于CRR时,会输出低电平,大于时,会输出高电平。

在手册中,我们能看到,在输出比较部分,还有一个选择极性的非门

通过这个非门,我们可以改变极性,也就是可以互换高低电平的变化。

当置0的时候,则没有变化。当置1的时候,则会使输出的电平颠倒。

综上所述,我们便知道了大致如何配置定时器,以实现PWM波形了。

以下是确定PWM各项数值的计算公式

2、代码部分

前半段正常开启定时器。

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启定时器时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启IO口时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置为复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);//设置内部时钟为定时器时钟

以我们驱动电机为例,电机要求PWM的频率在1KHZ~20KHZ之间,我们设置PWM的分辨率为1%,PWM的频率为20KHZ

根据上面的公式,我们可以通过分辨率确定ARR的值。也就是 1 / (ARR+1)= 1%,所以ARR=100-1;由此也可以确定了PSC的值,也就是72MHZ / (PSC + 1)/(ARR + 1),PSC = 36 + 1;

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100-1;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 36-1;//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

接下来,便可以设置关于PWM的结构体了。

注意,我们设置的输出比较通道,示例代码用的是通道三。

	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//向上计数模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出比较
	TIM_OCInitStructure.TIM_Pulse = 50;//CRR
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);

最后使能定时器。

TIM_Cmd(TIM2,ENABLE);

在ARR确定的情况下,我们只需要改变CRR的值,便能很轻松的改变PWM的占空比,从而改变PWM的输出强度。

为了方便,我们可以单独写一个函数,再使用库函数中的一个函数,对于结构体中的CRR的值,进行单独的修改。

void PWM_SetCompare1(uint16_t dat)
{
	TIM_SetCompare3(TIM2,dat);
}

这样,对于PWM的设置全部完成。

三、结语

贴上完整的代码

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启定时器时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启IO口时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置为复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);//设置内部时钟为定时器时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100-1;//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 36-1;//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//向上计数模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出比较
	TIM_OCInitStructure.TIM_Pulse = 50;//CRR
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
}

void PWM_SetCompare1(uint16_t dat)
{
	TIM_SetCompare3(TIM2,dat);
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐