关于PWM调速(基础篇)

       刚步入大学,第一次做小车,准备用delay延时函数来控制小车,效果不佳,熬夜看了多篇关于PWM的代码,发现并不是很详细,所以准备分享一下我的看法和,代码。

        

        PWM调速是通过调节占空比来调节速度,也就是说在高电平的时候转动,低电平时候停止转动,由于间隙很小,所以给我们的感觉就是一直在转动,只不过速度减慢。本来供给L298N的电压为12V,但是调节占空比就可以得到0~12V之间任意一个电压。

        此时就应该讲讲L298N模块了,L298N卸下输出端A旁边的跳线帽可以给单片机提供5V使能,(但是我并不建议,这样可能电机卡死烧坏板子,可以看我小车旁边是使用一个降压模块降压以后再供给了单片机),单片机的I/O口接逻辑输入和通道使能(下图图中有标识)I/O口通过给值给逻辑输入(逻辑输入左边两个接口控制左边输出A,右边两个接口控制右边输出B)来控制逻辑输出的高电平或者低电平,我来解读一下下面这个表:

 IN1,IN2表示输出端的两个口,ENA表示输出端A(如果在不适用PWM调速的时候就不用拔下使能端两侧的跳线帽,此时ENA默认为1,意思就是如果给他高电平他就以12V的电压全速跑,不拔跳线帽也不用对使能端赋值,因为你也赋不了,没有接I/O口),继续解读上表,在ENA=1的时候,如果IN1=1;IN2=0;也就是给电机两端一个高电平一个低电平,假设他正转那么IN1=0;IN2=1;就反转IN1=0;IN2=0;此时就是两端都为低电平,所以呢电机就不转,使用就有人想问,如果两端都赋值为1的话是不是也能刹车,答案是必定的,但是这容易烧坏L298N,但是都为1他的刹车效果更好(我推荐即使想要刹车效果好,但也不要使用都为1,可以采用先使电机反转再停止)在拔下跳线帽ENA=0的时候无论如何赋值电机都不会转动。B使能端同理。

我做的车为循迹小车,先贴下我的总代码,后面还有一步一步解析

#include"reg52.h"
#include"intrins.h"
sbit ZUO_LUN=P2^0;
sbit ZUO1_LUN=P2^1;//左轮
sbit YOU_LUN=P2^2;
sbit YOU1_LUN=P2^ 3;//右轮

sbit ENA=P2^4;                         
sbit ENB=P2^5;//使能端

sbit ZUO1_XJ=P1^0;
sbit ZUO_XJ=P1^1;
sbit ZHONG_XJ=P1^2;
sbit YOU_XJ=P1^3;
sbit YOU1_XJ=P1^4;//循迹定义

unsigned int PWM_ENA=0; //左侧使能时间
unsigned int PWM_ENB=0; //右侧使能时间
unsigned int PWM=0; //pwm周期为200ms
unsigned int CNT,x,y ;//跑圈计数器

 void delay(int x)  //@11.0592MHz
{
 for(y=0;y<x;y++)
 {
  unsigned char i, j;
 
  _nop_();
  _nop_();
  _nop_();
  i = 11;
  j = 190;
  do
  {
   while (--j);
  } while (--i);
 }
}


void Timer0Init(void)//定时1ms,并使用中断 
{
 TMOD= 0x01;  
 TL0 = 0xCD;  
 TH0 = 0xD4;  
 TF0 = 0; 
 TR0 = 1; 
 ET0=1;
 EA=1;
}

void QIAN_JING(void)
{       
 ZUO_LUN=1;
 ZUO1_LUN=0;
 YOU_LUN=1;
 YOU1_LUN=0;
 PWM_ENA=150;
 PWM_ENB=150;
}//前进函数

void YOU_ZHUAN(void)
{
 ZUO_LUN=0;
 ZUO1_LUN=0;
 YOU_LUN=0;
 YOU1_LUN=0;
 YOU_LUN=1;
 YOU1_LUN=0;
 PWM_ENA=0;
 PWM_ENB=100; 
}//右转函数

void ZUO_ZHUAN(void)
{
 ZUO_LUN=0;
 ZUO1_LUN=0;
 YOU_LUN=0;
 YOU1_LUN=0;
 ZUO_LUN=1;
 ZUO1_LUN=0;
 PWM_ENA=100;
 PWM_ENB=0; 
}//左转函数

void STOP(void)
{
 ZUO_LUN=0;
 ZUO1_LUN=1;
 YOU_LUN=0;
 YOU1_LUN=1;
 ZUO1_LUN=0;
 YOU1_LUN=0;
 PWM_ENA=0;
 PWM_ENB=0;
}//停止函数

void XUN_JI(void)
{
 if(ZUO1_XJ==0&&ZUO_XJ==0&&YOU_XJ==0&&YOU1_XJ==0)
 {
  QIAN_JING();
  delay(5);
  STOP();
  delay(5);
 }
 if(ZUO1_XJ==0&&ZUO_XJ==1)
 {
  ZUO_ZHUAN();
  delay(5);
  STOP();
  delay(5);
	CNT++;
 
 }
 if(YOU1_XJ==0&&YOU_XJ==1)
 {
  YOU_ZHUAN();
  delay(6);
  STOP();
  delay(5);
  CNT++;
 }
 if(ZUO1_XJ==1&&YOU1_XJ==0&&YOU_XJ==0&&ZUO_XJ==0)
 {
  ZUO_ZHUAN();
  delay(6);
  STOP();
  delay(5);
 }		 
 if(YOU1_XJ==1&&YOU_XJ==0&&ZUO_XJ==0&&ZUO1_XJ==0)
 {
     YOU_ZHUAN();
	 delay(5);
  	STOP();
  	delay(5);
 }
 if(ZUO1_XJ==1&&YOU1_XJ==1&&ZUO_XJ==1&&YOU_XJ==1)
 {
  CNT++;
  delay(10);
  if(CNT>14)																			 	
  {
   STOP();
  }
  else
  {
  QIAN_JING();
  }
 }

}

void main()
{
   Timer0Init();
   while(1)
   {
    XUN_JI();
   }
}

void timer0()interrupt 1
{
	TL0 = 0xCD;  
 	TH0 = 0xD4;  
 	TF0 = 0; 
	if(PWM==200)
	{
	PWM=0;
	}

	if(PWM<PWM_ENA)
	{
		ENA=1;
	}
	else
	{
		ENA=0;
	}

	if(PWM<PWM_ENB)
	{
		ENB=1;
	}
	else
	{
	ENB=0;							 
	}
	PWM++;
}






​
sbit ZUO_LUN=P2^0;//也就是前面说的使能端A的IN1
sbit ZUO1_LUN=P2^1;//也就是前面说的使能端A的IN2
sbit YOU_LUN=P2^2;//同理也就是使能端B的IN1
sbit YOU1_LUN=P2^ 3;//同理也就是使能端B的IN1

sbit ENA=P2^4;                         
sbit ENB=P2^5;//使能端

​

    IN1,IN2的标号为自己定义的逻辑信号的名称,自己随便定义就好

unsigned int PWM_ENA=0; //左侧使能时间
unsigned int PWM_ENB=0; //右侧使能时间
unsigned int PWM=0; //pwm初始值

这就是当时我看别人代码很懵的地方PWM_ENA表示我对使能端的时间,每次转弯的时间即占空比为自己定义我定义的PWM为200ms,也就是PWM从0加到200,到了200后又重新置0,先看我接下来的一段代码我在细细解释

void QIAN_JING(void)
{       
 ZUO_LUN=1;
 ZUO1_LUN=0;
 YOU_LUN=1;
 YOU1_LUN=0;
 PWM_ENA=150;
 PWM_ENB=150;
}//前进函数








void timer0()interrupt 1
{
	TL0 = 0xCD;  
 	TH0 = 0xD4;  
 	TF0 = 0; 
	if(PWM==200)
	{
	PWM=0;
	}

	if(PWM<PWM_ENA)
	{
		ENA=1;
	}
	else
	{
		ENA=0;
	}

	if(PWM<PWM_ENB)
	{
		ENB=1;
	}
	else
	{
	ENB=0;							 
	}
	PWM++;
}

我采用的定时器中断0,每次PWM从0每隔1ms加到200,例如前进函数我给的使能端PWM_ENA和PWM_ENB的值为150,也就是在PWM从0加到150(也就是PWM_ENA和PWM_ENB的值,当然两边值也可以不一样)的时候我的使能端给他的是高电平,也就是能转动剩下的50us给的是低电平在这50us电机就是停止的,就这样我们调节了占空比,达到降速的作用,黄皮电机不太标准跑直线容易转弯,我们也可以通过PWM来调节使左右转速相同。

最后行文仓促,知识和撰写水平均有限,难免有错,还望大佬指出。

### PWM调速的工作原理 PWM(Pulse Width Modulation,脉冲宽度调制)是一种通过调整脉冲信号的占空比来控制功率输出的技术。对于电机调速而言,PWM的核心在于改变施加于电机上的平均电压,从而达到调节电机转速的目的。 #### 占空比与电机速度的关系 当单片机或其他控制器输出一个具有固定频率但可变占空比的方波信号时,该信号被用于驱动电机。如果PWM信号处于高电平时,电流流经电机线圈并产生磁场使电机旋转;而当PWM信号为低电平时,虽然电流停止流动但由于电机内部存在电感效应,其转速不会立即下降而是逐渐减速。因此,在一定时间内,可以通过设置不同的占空比来决定电机实际运行的时间比例,进而影响最终的速度表现[^2]。 #### 具体实现机制 从硬件角度来看,生成这样的PWM波形通常依赖定时器/计数器模块配合特定配置完成。具体来说,系统会基于预设好的时钟源不断累加数值直到达到某个阈值才会触发一次中断或者状态切换操作——这便是所谓的“周期”。与此同时还有一个独立变量用来表示何时应该发生逻辑反转事件(即高低电平转换),它由另一个参数定义好之后也会随着每次循环重新加载回去形成规律性的变化模式。这两个关键要素分别对应着整个过程中的频率设定部分以及具体的占空比率调控环节[^3]。 以下是基于C语言的一个简单例子展示如何利用STM32微控制器创建基本形式下的PWM输出功能: ```c #include "stm32f1xx_hal.h" void MX_TIM2_Init(void){ TIM_HandleTypeDef htim; __HAL_RCC_TIM2_CLK_ENABLE(); htim.Instance = TIM2; htim.Init.Prescaler = 84-1;//Set prescale value to get desired frequency. htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 1000-1 ;//Set auto reload register which defines duty cycle maximum limit. HAL_TIM_PWM_Init(&htim); TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500;//Initial pulse width set at half of the period for a starting point with 50% duty cycle. sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC,TIM_CHANNEL_1); } int main(){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1); while (1){} } ``` 上述代码片段展示了初始化TIM2外设作为PWM通道的过程,并设置了初始占空比为50%的情况。通过修改`sConfigOC.Pulse`字段的不同取值,则能够轻松达成动态调整目标效果的需求。 ### 结论 综上所述,通过对PWM技术深入理解及其背后工作流程剖析可知,合理运用此方法确实可以在诸多应用场景下有效解决诸如直流无刷马达之类设备变速难题的同时还具备良好可控性和稳定性优势[^1]。
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值