STM32 PWM输出原理和直流电机PWM驱动原理详解及例程

这次讲一讲STM32输出PWM的原理以及PWM可以作为信号传输数据的原理。

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

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

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

我们就用小灯作为例子来讲解吧。

首先看看普通的发光二极管,就是一毛钱好几个的那种。
在这里插入图片描述
就这种,那种贴片的(就是你们手里开发板上发光的那个)也是同理哈。工作原理说白了就是插电就亮,断电就灭。

意思就是如果把负极接到GND,正极接到单片机的IO口上,给高电平他就亮,给低电平他就熄。(反着也一样,随便你怎么接,能亮就行)

因为人眼存在“余晖效应”嘛
在这里插入图片描述

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

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

当然你也可以理解为在相同的功率下,AB两个灯都是在做把电能转化为光能的工作,在一天里A灯断断续续地工作了12小时,B灯连续不停工作了24小时。那么谁转化的光能更多就显而易见了,谁更亮也就不言而喻了。
在这里插入图片描述
这个时候只要能在极短时间内控制灯的亮与灭就可以控制亮度了。

在上图中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。这个数字代表啥子咧,Hz你很熟悉呗,你可以超级简单地理解为它1s之内可以工作这么多次。而不同的定时器可能在不同的总线上面,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作为控制信号外接其他驱动模块使用时,比较值不可大于等于重装载值!不然万一你用的带有MOS管的模块,而且电流大时(例如电机驱动)可能会导致MOS管炸裂,它瞬间积聚大量热量(因为MOS管存在数毫欧的导通电阻,导通时产生热量)难以及时散出,而且这种用法本来就与MOS管的工作原理违背(实际上MOS管会在导通后瞬间断开,再被导通)。短暂时间(实际上就是那么tm一瞬间的事情)后将会烧毁或者直接爆炸!有时候是冒烟,伴随一阵刺鼻的味道,有时候直接是瞬间爆炸,冒烟+起火。(别问我怎么知道的,我不想听。)

下面开始设置了哈。

void TIMx_Int_Init(int arr,int psc) 
{
     GPIO_InitTypeDef GPIO_InitStructure; 
     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
     TIM_OCInitTypeDef  TIM_OCInitStructure; 

     //先定义几个初始化要用到的结构体
     
     RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE); //使能计时器的时钟
     RCC_APBxPeriphClockCmd(RCC_APBxPeriph_GPIOX);//使能GPIO的时钟
     
     //使能时钟,TIM的通道与某一个IO口对应,自己查去
     //总线是哪个也自己查去
     
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x;      //对应的那个引脚
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出 
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
     GPIO_Init(GPIOX, &GPIO_InitStructure);                //初始化 GPIO 
     
     TIM_TimeBaseStructure.TIM_Period = arr;    //设置重装载值    
     TIM_TimeBaseStructure.TIM_Prescaler =psc;  //设置预分频数  
     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割  
     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM 向上计数
     TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); //②初始化 TIMx
     
     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;    //选择 PWM 模式 2 
     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 
     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  //输出极性高 
     TIM_OC2Init(TIMx, &TIM_OCInitStructure);
     TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);  //使能预装载寄存器 
     TIM_Cmd(TIMx, ENABLE);                          //⑤使能 TIMx

 }
     

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

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

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

666666666666666666666666666666666666666666666666666666666666666666666666666

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

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

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

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

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

总之呢硬件是软件开发的基础,不要求你会设计,但是咱得懂啊。下一篇我就来讲讲 “H桥驱动原理以及有刷直流电机驱动及程序还有无刷直流电机的驱动及程序的爱恨情仇”。

更新时间不定,看心情。写的不好或者不对的地方欢迎大家指正。

发布了1 篇原创文章 · 获赞 1 · 访问量 41

猜你喜欢

转载自blog.csdn.net/qq_44776401/article/details/104342132
今日推荐