目录
一、PWM的简介
1、PWM是什么
PWM全称Pulse Width Modulation:脉冲宽度调制(简称脉宽调制,通俗的讲就是调节脉冲的宽度),是电子电力应用中非常重要的一种控制技术。
脉冲:脉冲通常是指电子技术中经常运用的一种像脉搏似的短暂起伏的电冲击 (电压或电流)。
脉冲宽度(W),简称“脉宽”,是脉冲高电平持续的时间。单位是时间,比如纳秒(ns)、微妙(μs)、毫秒(ms)等。
2、PWM的参数
1,PWM的频率:
是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位Hz。
2,PWM的周期:
T=1/f,T是周期,f是频率。如果频率为50Hz ,也就是说一个周期是20ms,那么一秒钟就有 50次PWM周期。
3,占空比:
脉宽除以脉冲周期的值,百分数表示,比如50%。也常有小数或分数表示的,比如0.5或1/2。
也就是是一个脉冲周期内,高电平的时间与整个周期时间的比例,如下图所示。
比方说,周期的时间是10ms,脉宽时间是8ms,那么占空比是8/10= 80%,这就是占空比为80%的脉冲信号。
PWM就是脉冲宽度调制,通过调节占空比就可以调节脉冲宽度。
3、PWM的原理
以STM32单片机为例,其IO口只能输出高电平和低电平。
假设高电平为3.3V、低电平则为0V,那么要输出不同的模拟电压就要用到PWM。通过改变IO口输出的方波的占空比,从而获得使用数字信号模拟成的模拟电压信号。
电压是以一种脉冲序列被加到模拟负载上去的,接通时是高电平1,断开时是低电平0。接通时直流供电输出,断开时直流供电断开。通过对接通和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值3.3V的模拟电压。
比方说,占空比为50%那就是高电平时间一半,低电平时间一半。在一定的频率下,就可以得到模拟的1.65V输出电压。那么75%的占空比,得到的电压就是2.47V。
1,高级输出比较通道
2、通用输出比较通道
3、输出比较模式
二、PWM的结构
1、PWM的基本结构
2、参数计算
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
三、PWM的应用(例程)
1、呼吸灯
一般人眼睛对于80Hz以上刷新频率则完全没有闪烁感,那么我们平时见到的LED灯,当它的频率大于50Hz的时候,人眼就会产生视觉暂留效果,基本就看不到闪烁了,而是误以为是一个常亮的LED灯。
由于频率很高时看不到闪烁,占空比越大LED越亮,占空比越小LED越暗。所以,在频率一定时,可以用不同占空比改变LED灯的亮度,使其达到一个呼吸灯的效果。
2、舵机
舵机的控制就是通过一个固定的频率,给其不同的占空比来控制舵机不同的转角。
舵机的频率一般为频率为50HZ,也就是一个20ms左右的时基脉冲,而脉冲的高电平部分一般为0.5ms-2.5ms范围,来控制舵机不同的转角。
500-2500us的PWM高电平部分对应控制180度舵机的0-180度。
以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms-------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
下图演示占空比从1ms变化到2ms时,转角的变化。
3、直流电机
调节占空比可以实现不同电压的输出,实现对电机转速的调节。
对于直流电机来讲,电机输出端引脚是高电平电机就可以转动,当输出端高电平时,电机会转动,但是是一点一点的提速,在高电平突然转向低电平时,电机由于电感有防止电流突变的作用是不会停止的,会保持这原有的转速,以此往复,电机的转速就是周期内输出的平均电压值,所以实质上我们调速是将电机处于一种,似停非停,似全速转动又非全速转动的状态,那么在一个周期的平均速度就是我们占空比调出来的速度了。
在电机控制中,电压越大,电机转速越快,而通过PWM输出不同的模拟电压,便可以使电机达到不同的输出转速。
当然,在电机控制中,不同的电机都有其适应的频率 频率太低会导致运动不稳定,如果频率刚好在人耳听觉范围(20Hz-20kHz),有时还会听到呼啸声。频率太高时,电机可能反应不过来,正常的电机频率在 6-16kHZ之间为好。
四、代码
这里来到了大家最感兴趣的部分了,在这里我就只展示PWM驱动直流电机,呼吸灯和舵机我就不写了,但是我还是会放在链接里,供大家参考。
pwm.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启TIM2的时钟
TIM_InternalClockConfig(TIM2);//开启定时器2的时钟源作为内部时钟源
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义初始化参数结构体
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim,这里是不分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上计数模式
TIM_TimeBaseInitStructure.TIM_Period=100- 1;//ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=720 - 1;//PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;;//定时器的倍率,如果定时1秒,参数是1,那就是1+1=2倍
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
// TIM_ClearFlag(TIM2,TIM_FLAG_Update);//中断清除
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启中断
TIM_OCInitTypeDef TIM_OCInitStructure;//结构体变量需要赋值
TIM_OCStructInit(&TIM_OCInitStructure);//结构体赋初始值的函数
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较的极性
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出比较的使能
TIM_OCInitStructure.TIM_Pulse =0;//设置CCR的
TIM_OC1Init(TIM2,&TIM_OCInitStructure);//初始化TIM2_CH1
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能预装载寄存器
// 用结构体初始化输出比较单元,不同函数不同的GPIO(A0)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//这里的注释部分是展示开启定时器相应通道管脚的重映射
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//部分重映射
//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭调试端口的复用
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Initstructure.GPIO_Pin= GPIO_Pin_0;
GPIO_Initstructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
// GPIO_SetBits(GPIOA,GPIO_Pin_0);
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare1(uint16_t Compare1)
{
TIM_SetCompare1(TIM2,Compare1);//TIM2通道1,改变比较值CCRx,达到不同的占空比效果
}
Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_Initstructure.GPIO_Pin= GPIO_Pin_4|GPIO_Pin_5;
GPIO_Initstructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{
if(Speed>=0)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
GPIO_SetBits(GPIOA,GPIO_Pin_5 );
PWM_SetCompare1(Speed);
}
else
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5 );
PWM_SetCompare1(-Speed);
}
}
main.c
//提高PWM的频率,让电机在堵转的时候无声,人耳听到的频率在20Hz-20kHz
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
int8_t Speed;
int main(void)
{
Key_Init();
OLED_Init();
Motor_Init();
Motor_SetSpeed(50);
OLED_ShowString(1,1,"Speed:");
while (1)
{
Motor_SetSpeed(Speed);//不断改变Speed的大小,就是在改变占空比,自然就改变了电机转速
OLED_ShowSignedNum(2,2,Speed,3);
}
}
接线图:
五、总结
PWM是我们玩小车,控制的核心东西,大家一定要好好学习,彻底掌握!希望对大家有用。
这里很抱歉,过了这么就才更新,对不起啦!下一节咱们讲循迹。
链接:https://pan.baidu.com/s/1sN5W-n_im9UtKizDyI8dHQ?pwd=yl66
提取码:yl66