深入解析STM32 PWM输出原理与直流电机PWM驱动,附例程详解

PWM会有很多地方用到,如控制灯的亮度,控制电机,控制舵机或者其他一些外设,有时候你的单片机所输出的PWM是作为信号去传输数据,有时候是用它来提供一个可控的超小功率的电压。

首先要知道什么是PWM信号。PWM信号是“Pulse(脉冲) Width(宽度) Modulation(调制)”的缩写,意思是 可控制宽度的脉冲信号。

那么这个信号有什么用呢?它是怎么实现控制小灯或者电机呢?

我们就用小灯作为例来说。

首先看看普通的发光二极管。

就这种,那种贴片的(就是你们手里开发板上发光的那个)也是同理哈。工作原理就是通电就亮,断电就灭。

因为人眼存在“余晖效应”

当灯熄灭了的一瞬间,其实人的眼睛还感觉他是亮着的,当灯不停的发亮再熄灭,只要中间间隔的时间极其短,人眼看上去就像是它一直在亮着一样。

那么这个时候思考一下,有两个灯A和B,供电电压相同,在一段固定的时间内,A灯在不停地闪烁,频率之快以至于人眼无法分辨,其中有50%的时间亮着,50%熄灭。而B灯一直亮着。那么这样观察上去就会明显地感觉到A灯比B灯暗很多。那么这就是一种控制小灯亮度的办法了。

当然你也可以理解为在相同的功率下,AB两个灯都是在做把电能转化为光能的工作,在一天里A灯断断续续地工作了12小时,B灯连续不停工作了24小时。那么B转化的光能更多,也就更亮。

这个时候只要能在极短时间内控制灯的亮与灭就可以控制亮度了。

在上图中AB两个灯的供电端电压可以看成下图这样

现在A灯这个电压形状就是我们要控制的PWM的形状了。

也就是说小灯变暗其实并不是变暗,它的亮度随电压不变而不变,只是它的闪烁过程中暗的时间变长了,人眼看上去灯变暗了。

那么以此类推,电机转慢了其实是它一直在转动和停顿吗?????
并不是!电机的线圈,像电感类似的结构,通直流阻交流,它具有电流的不可突变性,通电时它产生的磁场不允许电流的突变,他会将电流产生的磁场用来抑制电流的变化。
所以说用PWM控制电机的话,不讲驱动电路板原理的话,可以简化理解为这样:用芯片生成的PWM去使电机两端的电源图像变得像PWM信号一样。至于他是怎么变得我们下回分解。
意思就是说如果用PWM控制电机,那么电机两端的电压是010101这么突变的,但是电机电流却不是,即使电压为0,因线圈自感电动势的存在,电机中依旧有电流流过,电机依旧继续转动,那么我们使用PWM 为什么可以控制转速呢?
你也许会想到高中物理老师说的一个词语:等效电压。
我们通过PWM去控制等效电压。
你也可以根据能量守恒来想啊,电机转起来过后,线圈电阻恒定不变,功率恒定不变,两端电压峰值也恒定不变,那么这样情况下,电源电压图形上占空比的不同将导电机在这段时间内致消耗能量的不同,以此达到转化的机械能的不同,转速是不是也不同了。

那么现在我们怎么通过STM32来输出一个如A图电源端这样形状的信号呢?

首先是频率,这个信号的周期必须极其的短,也就是频率得快,大概得多块呢?这么说吧,至少得50Hz左右才不会有明显的闪烁感。

其次是占空比,占空比也就是一个周期内高电平占了整个周期的百分之几,像A灯这个就是百分之五十,50%的占空比。

周期和频率都是可以自己设置的。

那么为了设置频率和占空比,我们就先来了解一下STM32的TIM定时器,这个定时器就是控制上图时间坐标轴的关键了。

“STM32F1 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器 (CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产 生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长 度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的, 没有互相共享的任何资源。”

简单说就是这个定时器就是定时器,你可以理解为计时用的(废话吗这不是)。

详细讲呢就是它其实是一个计数器,就是用来数数的,结合了你的芯片工作频率和你可以自己设置的预分频数,设置后就可以作为定时器使用。

举个例子哈,我之前用的STM32F103设置的的频率是72MHz,就是72 * 10 ^ 6 Hz。而不同的定时器可能在不同的总线上面,APB1总线的频率是36MHz,APB2的频率是72MHz,假设我设置一个在APB1总线上的定时器,预分频数设置成为36,那么我的这个定时器就被设置成了36 * 10 ^ 6 / 36 Hz的这么一个 计数器 ,1s之内可以数1000000个数。

然后是“重装载值”,就是说计数值达到这个重装载值后就把计数值归零。假设我设置为1000哈,那么我们一起来看,用我设好的这个定时器数到1000需要几秒钟?结果是1000/1000000=1*10 ^-3 s,也就是0.001s,1ms哈。意思就是说我的频率和周期已经设置好了哟,周期是1ms,那么频率1000Hz。

公式就是 周期 = 重装载值 / 总线频率 / 预分频数。是不是很简单了。

然后是占空比了,设置占空比需要设定一个“比较值”,当计数器计数到这个值的时侯我们就可以做一个操作,比如输出高电平,然后在计数值没达到的时候输出低电平,或者反着来也行,都是可以通过代码实现的,那么显而易见,这个比较值必须要比重装载值要小才可以。接着看一下这个图就容易明白了。

就是说信号在计数值达到比较值之后电信号发生变化。

警告:在pwm作为控制信号外接其他驱动模块使用时,比较值不可大于等于重装载值!这样会使某些廉价驱动板的H桥上下桥臂同时导通。(别问我怎么知道的,我不想听。)

下面开始设置。(参考正点原子实验)

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
 
   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
   //初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	

}

这就是初始化设置的函数了,可以在里面自己设置你想要的定时器,编辑频率,APBX,GPIOX,TIMx,Pinx都自己选自己查,对应你的硬件电路图来做出改变。

最后设置比较值就可以控制占空比,比较值设定呢用这个
TIM_SetCompare2(TIMx,你想要的比较值);

这样就可以输出一个简单的PWM波了。

相信认真看到这里的同学已经理解了这个简单的PWM,代码看不懂不重要,那是人家的库函数,你不需要知道。重要的是你要理解你想控制的东西的工作原理和控制方法。就像怎么造车怎么造发动机你不懂,没关系,你只需要知道怎么开车就可以了。

现在我再来讲一下简单的电机驱动方法。
刚才控制小灯亮度,我们是将PWM作为电源信号,而电机的控制一般都是将其作为控制信号使用,也就是说用它控制电机两端的电源,而不是直接作为电源,因为这个电压实在太低了,芯片引脚提供的电流也是太小太小了。
首先是网上到处可以找到的直流电机驱动器,就几十块一个的那种,一般都可用。

这种呢比较简单,他只是一个驱动模块,你不需要知道它的工作原理,你只用自己配置一个pwm插上去就能用,一个占空比对应一个电压,转速可以通过编码器检测自己使用PID算法来控制。

但是更多时候咱们自己或者别人设计的驱动器使用起来就没有这么简单了,尤其是无刷电机驱动。通常我们将控制芯片和驱动模块做在同一个电路板上,这样不仅可以节约成本,还可以有效减小电路板的大小,这个时候你的代码就需要结合实际的硬件来做相应的改变。

一般来讲呢直流电机的驱动大部分使用H桥驱动,什么是H桥驱动呢我会在下次闲下来的时候详细的讲。用到了H桥的话大功率一般使用MOS管来实现电压的1和0的切换,你的代码还必须根据使用的MOS驱动芯片和光耦的使用与否来做出相应的变化,还有无刷电机的三相供电也实在令人头疼。
参考链接:
STM32 PWM输出原理和直流电机PWM驱动原理详解及例程

物联沃分享整理
物联沃-IOTWORD物联网 » 深入解析STM32 PWM输出原理与直流电机PWM驱动,附例程详解

发表评论